148 lines
4.7 KiB
Lua
148 lines
4.7 KiB
Lua
|
---@class OxCommandParams
|
||
|
---@field name string
|
||
|
---@field help? string
|
||
|
---@field type? 'number' | 'playerId' | 'string'
|
||
|
---@field optional? boolean
|
||
|
|
||
|
---@class OxCommandProperties
|
||
|
---@field help string?
|
||
|
---@field params OxCommandParams[]?
|
||
|
---@field restricted boolean | string | string[]?
|
||
|
|
||
|
---@type OxCommandProperties[]
|
||
|
local registeredCommands = {}
|
||
|
local shouldSendCommands = false
|
||
|
|
||
|
SetTimeout(1000, function()
|
||
|
shouldSendCommands = true
|
||
|
TriggerClientEvent('chat:addSuggestions', -1, registeredCommands)
|
||
|
end)
|
||
|
|
||
|
AddEventHandler('playerJoining', function(source)
|
||
|
TriggerClientEvent('chat:addSuggestions', source, registeredCommands)
|
||
|
end)
|
||
|
|
||
|
---@param source number
|
||
|
---@param args table
|
||
|
---@param raw string
|
||
|
---@param params OxCommandParams[]?
|
||
|
---@return table?
|
||
|
local function parseArguments(source, args, raw, params)
|
||
|
if not params then return args end
|
||
|
|
||
|
for i = 1, #params do
|
||
|
local arg, param = args[i], params[i]
|
||
|
local value
|
||
|
|
||
|
if param.type == 'number' then
|
||
|
value = tonumber(arg)
|
||
|
elseif param.type == 'string' then
|
||
|
value = not tonumber(arg) and arg
|
||
|
elseif param.type == 'playerId' then
|
||
|
value = arg == 'me' and source or tonumber(arg)
|
||
|
|
||
|
if not value or not DoesPlayerExist(value--[[@as string]]) then
|
||
|
value = false
|
||
|
end
|
||
|
else
|
||
|
value = arg
|
||
|
end
|
||
|
|
||
|
if not value and (not param.optional or param.optional and arg) then
|
||
|
return Citizen.Trace(("^1command '%s' received an invalid %s for argument %s (%s), received '%s'^0\n"):format(string.strsplit(' ', raw) or raw, param.type, i, param.name, arg))
|
||
|
end
|
||
|
|
||
|
arg = value
|
||
|
|
||
|
args[param.name] = arg
|
||
|
args[i] = nil
|
||
|
end
|
||
|
|
||
|
return args
|
||
|
end
|
||
|
|
||
|
---@param commandName string | string[]
|
||
|
---@param properties OxCommandProperties | false
|
||
|
---@param cb fun(source: number, args: table, raw: string)
|
||
|
---@param ... any
|
||
|
function lib.addCommand(commandName, properties, cb, ...)
|
||
|
-- Try to handle backwards-compatibility with the old addCommand syntax (prior to v3.0)
|
||
|
local restricted, params
|
||
|
|
||
|
if properties then
|
||
|
if ... or table.type(properties) ~= 'hash' then
|
||
|
local _commandName = type(properties) == 'table' and properties[1] or properties
|
||
|
local info = debug.getinfo(2, 'Sl')
|
||
|
|
||
|
warn(("command '%s' is using deprecated syntax for lib.addCommand\nupdate the command or use lib.__addCommand to ignore this warning\n> source ^0(^5%s^0:%d)"):format(_commandName, info.short_src, info.currentline))
|
||
|
---@diagnostic disable-next-line: deprecated
|
||
|
return lib.__addCommand(commandName, properties, cb, ...)
|
||
|
end
|
||
|
|
||
|
restricted = properties.restricted
|
||
|
params = properties.params
|
||
|
end
|
||
|
|
||
|
if params then
|
||
|
for i = 1, #params do
|
||
|
local param = params[i]
|
||
|
|
||
|
if param.type then
|
||
|
param.help = param.help and ('%s (type: %s)'):format(param.help, param.type) or ('(type: %s)'):format(param.type)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local commands = type(commandName) ~= 'table' and { commandName } or commandName
|
||
|
local numCommands = #commands
|
||
|
local totalCommands = #registeredCommands
|
||
|
|
||
|
local function commandHandler(source, args, raw)
|
||
|
args = parseArguments(source, args, raw, params)
|
||
|
|
||
|
if not args then return end
|
||
|
|
||
|
local success, resp = pcall(cb, source, args, raw)
|
||
|
|
||
|
if not success then
|
||
|
Citizen.Trace(("^1command '%s' failed to execute!\n%s"):format(string.strsplit(' ', raw) or raw, resp))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
for i = 1, numCommands do
|
||
|
totalCommands += 1
|
||
|
commandName = commands[i]
|
||
|
|
||
|
RegisterCommand(commandName, commandHandler, restricted and true)
|
||
|
|
||
|
if restricted then
|
||
|
local ace = ('command.%s'):format(commandName)
|
||
|
local restrictedType = type(restricted)
|
||
|
|
||
|
if restrictedType == 'string' and not IsPrincipalAceAllowed(restricted, ace) then
|
||
|
lib.addAce(restricted, ace)
|
||
|
elseif restrictedType == 'table' then
|
||
|
for j = 1, #restricted do
|
||
|
if not IsPrincipalAceAllowed(restricted[j], ace) then
|
||
|
lib.addAce(restricted[j], ace)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if properties then
|
||
|
properties.name = ('/%s'):format(commandName)
|
||
|
properties.restricted = nil
|
||
|
registeredCommands[totalCommands] = properties
|
||
|
|
||
|
if i ~= numCommands and numCommands ~= 1 then
|
||
|
properties = table.clone(properties)
|
||
|
end
|
||
|
|
||
|
if shouldSendCommands then TriggerClientEvent('chat:addSuggestions', -1, properties) end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return lib.addCommand
|