2023-02-22 01:24:23 +11:00
---@class OxCommandParams
---@field name string
---@field help? string
2024-07-01 03:42:21 +02:00
---@field type? 'number' | 'playerId' | 'string' | 'longString'
2023-02-22 01:24:23 +11:00
---@field optional? boolean
2023-02-21 19:52:12 +11:00
---@class OxCommandProperties
---@field help string?
2023-07-25 01:59:39 +10:00
---@field params OxCommandParams[]?
2023-02-21 19:52:12 +11:00
---@field restricted boolean | string | string[]?
---@type OxCommandProperties[]
local registeredCommands = { }
2023-02-22 01:30:52 +11:00
local shouldSendCommands = false
2022-02-28 08:09:03 +11:00
SetTimeout ( 1000 , function ( )
2023-02-22 01:30:52 +11:00
shouldSendCommands = true
2023-02-21 19:52:12 +11:00
TriggerClientEvent ( ' chat:addSuggestions ' , - 1 , registeredCommands )
2022-02-28 08:09:03 +11:00
end )
AddEventHandler ( ' playerJoining ' , function ( source )
2023-02-21 19:52:12 +11:00
TriggerClientEvent ( ' chat:addSuggestions ' , source , registeredCommands )
2022-02-28 08:09:03 +11:00
end )
2023-02-21 19:52:12 +11:00
---@param source number
---@param args table
2023-02-22 01:24:23 +11:00
---@param raw string
2023-07-25 01:59:39 +10:00
---@param params OxCommandParams[]?
2023-02-21 19:52:12 +11:00
---@return table?
2023-02-22 01:24:23 +11:00
local function parseArguments ( source , args , raw , params )
2023-02-21 19:52:12 +11:00
if not params then return args end
2024-07-01 03:42:21 +02:00
local paramsNum = # params
for i = 1 , paramsNum do
2023-02-21 19:52:12 +11:00
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 )
2024-01-17 16:42:26 +11:00
if not value or not DoesPlayerExist ( value --[[@as string]] ) then
2023-02-21 19:52:12 +11:00
value = false
end
2024-07-01 03:42:21 +02:00
elseif param.type == ' longString ' and i == paramsNum then
local start = raw : find ( arg , 1 , true )
value = start and raw : sub ( start )
2023-02-21 19:52:12 +11:00
else
value = arg
end
if not value and ( not param.optional or param.optional and arg ) then
2023-04-01 11:25:57 +11:00
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 ) )
2023-02-21 19:52:12 +11:00
end
arg = value
args [ param.name ] = arg
args [ i ] = nil
end
return args
2022-02-28 08:09:03 +11:00
end
2023-02-21 19:52:12 +11:00
---@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 \n update 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
2023-02-22 01:24:23 +11:00
local function commandHandler ( source , args , raw )
args = parseArguments ( source , args , raw , params )
if not args then return end
2024-01-17 16:42:26 +11:00
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
2023-02-22 01:24:23 +11:00
end
2023-02-21 19:52:12 +11:00
for i = 1 , numCommands do
totalCommands += 1
commandName = commands [ i ]
2023-02-22 01:24:23 +11:00
RegisterCommand ( commandName , commandHandler , restricted and true )
2023-02-21 19:52:12 +11:00
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
2024-07-01 03:42:21 +02:00
---@diagnostic disable-next-line: inject-field
2023-02-21 19:52:12 +11:00
properties.name = ( ' /%s ' ) : format ( commandName )
properties.restricted = nil
registeredCommands [ totalCommands ] = properties
if i ~= numCommands and numCommands ~= 1 then
properties = table.clone ( properties )
end
2023-02-22 01:30:52 +11:00
if shouldSendCommands then TriggerClientEvent ( ' chat:addSuggestions ' , - 1 , properties ) end
2023-02-21 19:52:12 +11:00
end
end
2021-12-30 02:25:00 +11:00
end
2022-09-14 01:20:50 +10:00
return lib.addCommand