Files
ox_lib/imports/addCommand/server.lua
Linden fb2225e373 chore: add copyright notices to each file
Some people accidentally, mistakenly, and without any malicious intent forget to attribute code from this resource to its source. This change will hopefully assist people, so that they do not make that mistake again.
2025-03-18 18:46:09 +11:00

165 lines
5.3 KiB
Lua

--[[
https://github.com/overextended/ox_lib
This file is licensed under LGPL-3.0 or higher <https://www.gnu.org/licenses/lgpl-3.0.en.html>
Copyright (c) 2025 Linden <https://github.com/thelindat/fivem>
]]
---@class OxCommandParams
---@field name string
---@field help? string
---@field type? 'number' | 'playerId' | 'string' | 'longString'
---@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()
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
local paramsNum = #params
for i = 1, paramsNum 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
elseif param.type == 'longString' and i == paramsNum then
if arg then
local start = raw:find(arg, 1, true)
value = start and raw:sub(start)
else
value = nil
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
---@diagnostic disable-next-line: inject-field
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