mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Improved comment in commands
This commit is contained in:
@@ -3,115 +3,170 @@
|
||||
-- @module Commands
|
||||
--[[
|
||||
>>>>Example Authenticator:
|
||||
The command system is most useful when you can control who can use commands; to do this would would need to
|
||||
define an authenticator which is ran every time a command is run; in this example I will show a simple one
|
||||
that requires some commands to require the user to be a game admin:
|
||||
|
||||
-- adds an admin only authenticator where if a command has the tag admin_only: true
|
||||
-- then will only allow admins to use this command
|
||||
Commands.add_authenticator(function(player,command,tags,reject)
|
||||
if tags.admin_only then -- the command has the tag admin_only set to true
|
||||
if player.admin then -- the player is an admin
|
||||
return true -- no return is needed for success but is useful to include
|
||||
else -- the player is not admin
|
||||
-- you must return to block a command, they are a few ways to do this:
|
||||
-- return false -- most basic and has no custom error message
|
||||
-- return reject -- sill no error message and is here in case people dont know its a function
|
||||
-- reject() -- rejects the player, return not needed but please return if possible
|
||||
-- return reject() -- rejects the player and has a failsafe return to block command
|
||||
-- reject('This command is for admins only!') -- reject but with custom error message, return not needed but please return if possible
|
||||
return reject('This command is for admins only!') -- reject but with custom error message and has return failsafe
|
||||
When the authenticator is called be the command handler it will be passed 4 vales:
|
||||
1) the player who used the command
|
||||
2) the name of the command that is being used
|
||||
3) any flags which have been set for this command, this is a table of values set using :set_flag(name,value)
|
||||
4) the reject function which is the preferred method to prevent execution of the command
|
||||
|
||||
For our admin only example we will set a flag to true when we want it do be admin only so when we define the
|
||||
command will will use :set_flag('admin_only',true) and then inside the authenticator we will test if the flag
|
||||
is present using: if flags.admin_only then
|
||||
|
||||
Although no return is required to allow the command to execute it is best practice to return true; we do this in
|
||||
two cases in our authenticator:
|
||||
1) when the "admin_only" flag is not set, which we take to mean any one can use it
|
||||
2) when the "admin_only" flag is set, and the player is admin
|
||||
|
||||
Now when the user is not an admin and the command requires you to be an admin then we must reject the request:
|
||||
1) return false -- this is the most basic block and should only be used while testing
|
||||
2) return reject -- returning the reject function is only an option as a fail safe, same as returning false
|
||||
3) reject() -- this will block execution without returning to allow further code to be ran in the authenticator
|
||||
4) reject('This command is for admins only!') -- Using reject as a function allows a error message to be returned
|
||||
5) return reject() -- using return on either case above is best practice as you should execute all code before rejecting
|
||||
|
||||
Example Code:
|
||||
Commands.add_authenticator(function(player,command,flags,reject)
|
||||
if flags.admin_only then -- our test for the "admin_only" flag
|
||||
if player.admin then
|
||||
return true -- true return 2
|
||||
else
|
||||
return reject('This command is for admins only!') -- reject return 5 with a custom error message
|
||||
end
|
||||
else -- command does not require admin
|
||||
return true -- no return is needed for success but is useful to include
|
||||
else
|
||||
return true -- true return 1
|
||||
end
|
||||
end)
|
||||
|
||||
>>>>Example Parse:
|
||||
Before you go making commands it is important to understand the most powerful feature of this command handler,
|
||||
when you define a command you are able to type the params and have then be parsed by an handler so before your
|
||||
command is ever executed you can be sure that all the params are valid. This module should be paired with a general
|
||||
command parse but you may want to create your own:
|
||||
|
||||
-- adds a parse that will cover numbers within the given range
|
||||
-- input, player and reject are common to all parse functions
|
||||
-- range_min and range_max are passed to the function from add_param
|
||||
For our example we will create a parse to accept only integer numbers in a given range:
|
||||
1) we will give it the name "number-range-int" this is the "type" that the input is expected to be
|
||||
2) when we define the type we will also define the min and max of the range so we can use the function more than once
|
||||
Example parse usage:
|
||||
:add_param('repeat_count',false,'number-range-int',5,10) -- range 5 to 10 inclusive
|
||||
|
||||
The command parse will be passed 3 params and any other you define, in our case:
|
||||
1) the input that has been given by the user for this param, the role of this function is to transform this value
|
||||
nb: the input is a string but can be nil if the param is marked as optional
|
||||
2) the player who is using the command, this is always present
|
||||
3) the reject function to throw an error to the user, this is always present
|
||||
4) the range min, this is user defined and has the value given when the param is defined
|
||||
5) the range max, this is user defined and has the value given when the param is defined
|
||||
|
||||
When returning from the param parse you again have a few options with how to do this:
|
||||
1) you return the new value for the param (any non nil value) this value is then passed to the command callback
|
||||
2) not returning will cause a generic invalid error and the command callback is blocked, not recommenced
|
||||
3) return reject -- this is just a failsafe in case the function is not called, same as no return
|
||||
4) return reject() -- will give a shorter error message as you pass a nil custom error
|
||||
5) return reject('Number entered is not in range: '..range_min..', '..range_max) -- returns a custom error the the user
|
||||
nb: if you do not return reject after you call it then you are still returning nil so there will be a duplicate message
|
||||
|
||||
It should be noted that if you want to expand on an existing parse you can use Commands.parse(type,input,player,reject)
|
||||
and this value will either return a new value for the input or nil, if it is nil you should return nil to prevent dobble
|
||||
messages to the user:
|
||||
input = Commands.parse('number-int',input,player,reject)
|
||||
if not input then return end -- nil check
|
||||
|
||||
Example Code:
|
||||
Commands.add_parse('number-range-int',function(input,player,reject,range_min,range_max)
|
||||
local rtn = tonumber(input) and math.floor(tonumber(input)) or nil -- converts input to number
|
||||
if not rtn or rtn < range_min or rtn > range_max then -- check if it is nil or out of the range
|
||||
-- invalid input for we will reject the input, they are a few ways to do this:
|
||||
-- dont return anything -- will print generic input error
|
||||
-- return false -- this WILL NOT reject the input as false can be a valid output
|
||||
-- return reject -- will print generic input error
|
||||
-- return reject() -- will print generic input error with no please check type message
|
||||
-- reject() -- if you do not return the value then they will be a duplicate message
|
||||
return reject('Number entered is not in range: '..range_min..', '..range_max) -- reject with custom error
|
||||
else
|
||||
return rtn -- returns the number value this will be passed to the command callback
|
||||
end
|
||||
end)
|
||||
|
||||
>>>>Example Command:
|
||||
|
||||
-- adds a command that will print the players name a given number of times
|
||||
-- and can only be used by admin to show how auth works
|
||||
Commands.new_command('repeat-name','Will repeat you name a number of times in chat.') -- creates the new command with the name "repeat-name" and a help message
|
||||
:add_param('repeat-count',false,'number-range-int',1,5) -- adds a new param called "repeat-count" that is required and is type "number_range_int" the name can be used here as add_parse was used
|
||||
:add_param('smiley',true,function(input,player,reject) -- this param is optional and has a custom parse function where add_parse was not used before hand
|
||||
if not input then return end -- when they is an optional param input may be nil, you can return a default value here, but using nil will allow add_defaults to pick a default
|
||||
if input:lower() == 'true' or input:lower() == 'yes' then
|
||||
return true -- the value is truthy so true is returned
|
||||
else
|
||||
-- it should be noted that this function will be ran even when the param is not present
|
||||
-- in this case input is nil and so a default can be returned, see above
|
||||
return false -- false is returned other wise
|
||||
end
|
||||
end)
|
||||
:set_defaults{smiley=false} -- adds false as the default for smiley
|
||||
:set_flag('admin_only',true) -- adds the tag admin_only: true which because of the above authenticator means you must be added to use this command
|
||||
:add_alias('name','rname') -- adds two aliases "name" and "rname" for this command which will work as if the ordinal name was used
|
||||
--:enable_auto_concat() -- cant be used due to optional param here, but this will make all user input params after the last expected one be added to the last expected one
|
||||
:register(function(player,repeat_count,smiley,raw) -- this registers the command to the game, notice the params are what were defined above
|
||||
-- prints the raw input to show that it can be used
|
||||
game.print(player.name..' used a command with input: '..raw)
|
||||
-- some smiley logic
|
||||
local msg
|
||||
if smiley then
|
||||
msg = ':) '..player.name
|
||||
else
|
||||
msg = ') '..player.name
|
||||
end
|
||||
-- prints your name alot
|
||||
for i = 1,repeat_count do
|
||||
Commands.print(i..msg) -- this command is an alias for ("expcore.common").player_return it will print any value to the player/server not just strings
|
||||
end
|
||||
-- if you wanted to you can return some values here
|
||||
-- no return -- only success message is printed
|
||||
-- Commands.error('optional message here') -- prints an error message
|
||||
-- return Commands.error('optional message here') -- prints an error message, and stops success message being printed
|
||||
-- Commands.success('optional message here') -- same as below but success message is printed twice DONT DO this
|
||||
-- return Commands.success('optional message here') -- prints your message and then the success message
|
||||
end)
|
||||
|
||||
>>>>Examples With No Comments (for example formatting):
|
||||
|
||||
Commands.add_authenticator(function(player,command,tags,reject)
|
||||
if tags.admin_only then
|
||||
if player.admin then
|
||||
return true
|
||||
else
|
||||
return reject('This command is for admins only!')
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
Commands.add_parse('number_range_int',function(input,player,reject,range_min,range_max)
|
||||
local rtn = tonumber(input) and math.floor(tonumber(input)) or nil
|
||||
if not rtn or rtn < range_min or rtn > range_max then
|
||||
-- the input is either not a number or is outside the range
|
||||
return reject('Number entered is not in range: '..range_min..', '..range_max)
|
||||
else
|
||||
-- returns the input as a number value rather than a string, thus the param is now the correct type
|
||||
return rtn
|
||||
end
|
||||
end)
|
||||
|
||||
>>>>Example Command:
|
||||
How for the fun part making the commands, the commands can be set up with any number of params and flags that you want,
|
||||
you can add aliases for the commands and set default values for optional params and of course register your command callback
|
||||
in our example we will just have a command that will repeat the users name in chat X amount of times and only allow admins to use it.
|
||||
|
||||
First we create the new command, nb this will not register the command to the game this is done at the end, we will call
|
||||
the command "repeat-name" and set the help message as follows:
|
||||
Commands.new_command('repeat-name','Will repeat you name a number of times in chat.')
|
||||
:add_param('repeat-count',false,'number_range_int',1,5)
|
||||
|
||||
Now for our first param we will call "repeat-count" and it will be a required value between 1 and 5 inclusive:
|
||||
:add_param('repeat-count',false,'number-range-int',1,5)
|
||||
|
||||
Our second param we need a custom parse for but we have not defined it, this is an option for when it is unlikely for
|
||||
any other command to use the same input type; however in our case it will just be a boolean which should be noted as being
|
||||
included in the general command parse config. As for the param its self it will be called "smiley" and will be optional with
|
||||
a default value of false:
|
||||
:add_param('smiley',true,function(input,player,reject)
|
||||
-- since it is optional the input can be nil, in which case we just return
|
||||
if not input then return end
|
||||
-- if it is not nil then we check for a truthy value
|
||||
if input:lower() == 'true' or input:lower() == 'yes' then
|
||||
return true
|
||||
else
|
||||
-- note that because we did not return nil or reject then false will be passed to command callback, see example parse
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
Once all params are defined you can now define some default values if you have optional params, the default value will be used only
|
||||
when no value is given as input, if an invalid value is given then the command will still fail and this value will not be used, the
|
||||
default can also be a function which is passed the player using the command and returns a value. Here we set the default for "smiley" to false:
|
||||
:set_defaults{smiley=false}
|
||||
|
||||
Another example of defaults if we have: item, amount[opt], player[opt]
|
||||
:set_defaults{
|
||||
amount = 50, -- more than one value can be set at a time
|
||||
player = function(player)
|
||||
return player -- default is the player using the command
|
||||
end
|
||||
}
|
||||
|
||||
Now the params are set up we can alter how the command works, we can set auth flags, add aliases to this command or enable "auto concat"
|
||||
which is when you want all extra words to be concatenated onto the end of the last param, useful for reason or messages:
|
||||
:set_flag('admin_only',true) -- in our case we want "admin_only" to be set to true so only admins can use the command
|
||||
:add_alias('name','rname') -- we also add two aliases here: "name" and "rname" which point to this command
|
||||
-- :enable_auto_concat() we do not use this in our case but this can also be used to enable the "auto concat" feature
|
||||
|
||||
And finally we want to register a callback to this command, the callback is what defines what the command does, can be as complex as you
|
||||
want it to be to as simple as our example; the command receives two params plus all that you have defines:
|
||||
1) the player who used the command
|
||||
2) in our case repeat_count which will be a number
|
||||
3) in our case smiley which will be a boolean
|
||||
4) the raw input; this param is always last as is always present as a catch all
|
||||
:register(function(player,repeat_count,smiley,raw)
|
||||
-- this is to show the value for raw as this is an example command, the log file will also show this
|
||||
game.print(player.name..' used a command with input: '..raw)
|
||||
local msg = ') '..player.name
|
||||
if smiley then
|
||||
-- this is where that smiley param is used
|
||||
msg = ':'..msg
|
||||
end
|
||||
for 1 = 1,repeat_count do
|
||||
-- this print function will return ANY value to the user in a desync safe manor, this includes if the command was used through rcon
|
||||
Command.print(1..msg)
|
||||
end
|
||||
-- see below for what else can be used here
|
||||
end)
|
||||
|
||||
Some other useful functions that can be used are:
|
||||
Commands.print(any,colour[opt]) -- this will return any value value to the user including if it is ran through rcon console
|
||||
Commands.error(message[opt]) -- this returns a warning to the user, aka an error that does not prevent execution of the command
|
||||
return Commands.error(message[opt]) -- this returns an error to the user, and will halt the command execution, ie no success message is returned
|
||||
Commands.success(message[opt]) -- used to return a success message however dont use this method see below
|
||||
return Commands.success(message[opt]) -- will return the success message to the user and your given message, halts execution
|
||||
|
||||
Example Code:
|
||||
Commands.new_command('repeat-name','Will repeat you name a number of times in chat.')
|
||||
:add_param('repeat-count',false,'number-range-int',1,5) -- required int in range 1 to 5 inclusive
|
||||
:add_param('smiley',true,function(input,player,reject) -- optional boolean default false
|
||||
if not input then return end
|
||||
if input:lower() == 'true' or input:lower() == 'yes' then
|
||||
return true
|
||||
@@ -120,16 +175,16 @@
|
||||
end
|
||||
end)
|
||||
:set_defaults{smiley=false}
|
||||
:set_flag('admin_only',true)
|
||||
:add_alias('name','rname')
|
||||
:set_flag('admin_only',true) -- command is admin only
|
||||
:add_alias('name','rname') -- allow alias: name and rname
|
||||
:register(function(player,repeat_count,smiley,raw)
|
||||
game.print(player.name..' used a command with input: '..raw)
|
||||
local msg = ') '..player.name
|
||||
if smiley then
|
||||
msg = ':'..msg
|
||||
end
|
||||
for i = 1,repeat_count do
|
||||
Commands.print(i..msg)
|
||||
for 1 = 1,repeat_count do
|
||||
Command.print(1..msg)
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -148,7 +203,7 @@
|
||||
Commands.add_command(name,help) --- Creates a new command object to added details to, note this does not register the command to the game
|
||||
Commands._prototype:add_param(name,optional,parse,...) --- Adds a new param to the command this will be displayed in the help and used to parse the input
|
||||
Commands._prototype:set_defaults(defaults) --- Adds default values to params only matters if the param is optional
|
||||
Commands._prototype:set_flag(name,value) --- Adds a tag to the command which is passed via the tags param to the authenticators, can be used to assign command roles or type
|
||||
Commands._prototype:set_flag(name,value) --- Adds a tag to the command which is passed via the flags param to the authenticators, can be used to assign command roles or type
|
||||
Commands._prototype:add_alias(...) --- Adds an alias or multiple that will also be registered with the same callback, eg /teleport can be /tp with both working
|
||||
Commands._prototype:enable_auto_concat() --- Enables auto concatenation of any params on the end so quotes are not needed for last param
|
||||
Commands._prototype:register(callback) --- Adds the callback to the command and registers all aliases, params and help message with the game
|
||||
@@ -183,7 +238,7 @@ local Commands = {
|
||||
-- @tparam callback function the callback you want to register as an authenticator
|
||||
-- callback param - player: LuaPlayer - the player who is trying to use the command
|
||||
-- callback param - command: string - the name of the command which is being used
|
||||
-- callback param - tags: table - any tags which have been set for the command
|
||||
-- callback param - flags: table - any flags which have been set for the command
|
||||
-- callback param - reject: function(error_message?: string) - call to fail authorize with optional error message
|
||||
-- @treturn number the index it was inserted at use to remove the callback, if anon function used
|
||||
function Commands.add_authenticator(callback)
|
||||
@@ -241,8 +296,8 @@ function Commands.authorize(player,command_name)
|
||||
|
||||
-- loops over each authorization callback if any return false or unauthorized command will fail
|
||||
for _,callback in pairs(Commands.authorization) do
|
||||
-- callback(player: LuaPlayer, command: string, tags: table, reject: function(error_message?: string))
|
||||
local success, rtn = pcall(callback,player,command_name,command_data.tags,auth_fail)
|
||||
-- callback(player: LuaPlayer, command: string, flags: table, reject: function(error_message?: string))
|
||||
local success, rtn = pcall(callback,player,command_name,command_data.flags,auth_fail)
|
||||
-- error handler
|
||||
if not success then
|
||||
-- the callback failed to run
|
||||
@@ -360,7 +415,7 @@ function Commands.new_command(name,help)
|
||||
auto_concat=false,
|
||||
min_param_count=0,
|
||||
max_param_count=0,
|
||||
tags={}, -- stores tags that can be used by auth
|
||||
flags={}, -- stores flags that can be used by auth
|
||||
aliases={}, -- n = name: string
|
||||
params={}, -- [param_name] = {optional: boolean, default: any, parse: function, parse_args: table}
|
||||
}, {
|
||||
@@ -408,18 +463,18 @@ function Commands._prototype:set_defaults(defaults)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds a tag to the command which is passed via the tags param to the authenticators, can be used to assign command roles or type
|
||||
-- @tparam name string the name of the tag to be added; used to keep tags separate
|
||||
--- Adds a tag to the command which is passed via the flags param to the authenticators, can be used to assign command roles or type
|
||||
-- @tparam name string the name of the tag to be added; used to keep flags separate
|
||||
-- @tparam value any the tag that you want can be anything that the authenticators are expecting
|
||||
-- nb: if value is nil then name will be assumed as the value and added at a numbered index
|
||||
-- @treturn Commands._prototype pass through to allow more functions to be called
|
||||
function Commands._prototype:set_flag(name,value)
|
||||
if not value then
|
||||
-- value not given so name is the value
|
||||
table.insert(self.tags,name)
|
||||
table.insert(self.flags,name)
|
||||
else
|
||||
-- name is given so its key: value
|
||||
self.tags[name] = value
|
||||
self.flags[name] = value
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user