mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-30 20:41:41 +09:00
Improved comment in commands
This commit is contained in:
@@ -3,115 +3,170 @@
|
|||||||
-- @module Commands
|
-- @module Commands
|
||||||
--[[
|
--[[
|
||||||
>>>>Example Authenticator:
|
>>>>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
|
When the authenticator is called be the command handler it will be passed 4 vales:
|
||||||
-- then will only allow admins to use this command
|
1) the player who used the command
|
||||||
Commands.add_authenticator(function(player,command,tags,reject)
|
2) the name of the command that is being used
|
||||||
if tags.admin_only then -- the command has the tag admin_only set to true
|
3) any flags which have been set for this command, this is a table of values set using :set_flag(name,value)
|
||||||
if player.admin then -- the player is an admin
|
4) the reject function which is the preferred method to prevent execution of the command
|
||||||
return true -- no return is needed for success but is useful to include
|
|
||||||
else -- the player is not admin
|
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
|
||||||
-- you must return to block a command, they are a few ways to do this:
|
command will will use :set_flag('admin_only',true) and then inside the authenticator we will test if the flag
|
||||||
-- return false -- most basic and has no custom error message
|
is present using: if flags.admin_only then
|
||||||
-- 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
|
Although no return is required to allow the command to execute it is best practice to return true; we do this in
|
||||||
-- return reject() -- rejects the player and has a failsafe return to block command
|
two cases in our authenticator:
|
||||||
-- reject('This command is for admins only!') -- reject but with custom error message, return not needed but please return if possible
|
1) when the "admin_only" flag is not set, which we take to mean any one can use it
|
||||||
return reject('This command is for admins only!') -- reject but with custom error message and has return failsafe
|
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
|
end
|
||||||
else -- command does not require admin
|
else
|
||||||
return true -- no return is needed for success but is useful to include
|
return true -- true return 1
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
>>>>Example Parse:
|
>>>>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
|
For our example we will create a parse to accept only integer numbers in a given range:
|
||||||
-- input, player and reject are common to all parse functions
|
1) we will give it the name "number-range-int" this is the "type" that the input is expected to be
|
||||||
-- range_min and range_max are passed to the function from add_param
|
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)
|
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
|
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
|
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)
|
return reject('Number entered is not in range: '..range_min..', '..range_max)
|
||||||
else
|
else
|
||||||
|
-- returns the input as a number value rather than a string, thus the param is now the correct type
|
||||||
return rtn
|
return rtn
|
||||||
end
|
end
|
||||||
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.')
|
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)
|
: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 not input then return end
|
||||||
if input:lower() == 'true' or input:lower() == 'yes' then
|
if input:lower() == 'true' or input:lower() == 'yes' then
|
||||||
return true
|
return true
|
||||||
@@ -120,16 +175,16 @@
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
:set_defaults{smiley=false}
|
:set_defaults{smiley=false}
|
||||||
:set_flag('admin_only',true)
|
:set_flag('admin_only',true) -- command is admin only
|
||||||
:add_alias('name','rname')
|
:add_alias('name','rname') -- allow alias: name and rname
|
||||||
:register(function(player,repeat_count,smiley,raw)
|
:register(function(player,repeat_count,smiley,raw)
|
||||||
game.print(player.name..' used a command with input: '..raw)
|
game.print(player.name..' used a command with input: '..raw)
|
||||||
local msg = ') '..player.name
|
local msg = ') '..player.name
|
||||||
if smiley then
|
if smiley then
|
||||||
msg = ':'..msg
|
msg = ':'..msg
|
||||||
end
|
end
|
||||||
for i = 1,repeat_count do
|
for 1 = 1,repeat_count do
|
||||||
Commands.print(i..msg)
|
Command.print(1..msg)
|
||||||
end
|
end
|
||||||
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.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: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_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: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: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
|
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
|
-- @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 - 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 - 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
|
-- 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
|
-- @treturn number the index it was inserted at use to remove the callback, if anon function used
|
||||||
function Commands.add_authenticator(callback)
|
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
|
-- loops over each authorization callback if any return false or unauthorized command will fail
|
||||||
for _,callback in pairs(Commands.authorization) do
|
for _,callback in pairs(Commands.authorization) do
|
||||||
-- callback(player: LuaPlayer, command: string, tags: table, reject: function(error_message?: string))
|
-- callback(player: LuaPlayer, command: string, flags: table, reject: function(error_message?: string))
|
||||||
local success, rtn = pcall(callback,player,command_name,command_data.tags,auth_fail)
|
local success, rtn = pcall(callback,player,command_name,command_data.flags,auth_fail)
|
||||||
-- error handler
|
-- error handler
|
||||||
if not success then
|
if not success then
|
||||||
-- the callback failed to run
|
-- the callback failed to run
|
||||||
@@ -360,7 +415,7 @@ function Commands.new_command(name,help)
|
|||||||
auto_concat=false,
|
auto_concat=false,
|
||||||
min_param_count=0,
|
min_param_count=0,
|
||||||
max_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
|
aliases={}, -- n = name: string
|
||||||
params={}, -- [param_name] = {optional: boolean, default: any, parse: function, parse_args: table}
|
params={}, -- [param_name] = {optional: boolean, default: any, parse: function, parse_args: table}
|
||||||
}, {
|
}, {
|
||||||
@@ -408,18 +463,18 @@ function Commands._prototype:set_defaults(defaults)
|
|||||||
return self
|
return self
|
||||||
end
|
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
|
--- 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 tags separate
|
-- @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
|
-- @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
|
-- 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
|
-- @treturn Commands._prototype pass through to allow more functions to be called
|
||||||
function Commands._prototype:set_flag(name,value)
|
function Commands._prototype:set_flag(name,value)
|
||||||
if not value then
|
if not value then
|
||||||
-- value not given so name is the value
|
-- value not given so name is the value
|
||||||
table.insert(self.tags,name)
|
table.insert(self.flags,name)
|
||||||
else
|
else
|
||||||
-- name is given so its key: value
|
-- name is given so its key: value
|
||||||
self.tags[name] = value
|
self.flags[name] = value
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user