Updated Docs

This commit is contained in:
Cooldude2606
2020-04-01 00:01:40 +01:00
parent 95af6cfc34
commit c9534de868
115 changed files with 23355 additions and 6604 deletions

View File

@@ -1,31 +1,31 @@
--[[-- Core Module - Async
- An extention of task and token to allow a single require to register and run async functions.
@core Async
@alias Async
- An extention of task and token to allow a single require to register and run async functions.
@core Async
@alias Async
@usage
-- To use Async you must register the allowed functions when the files are loaded, often this will just be giving access to
-- some functions within a module if you expect that some parts may be blocked by in game permissions or a custom system you have made
-- you may also want to register functions that you want to have a delayed call, such as waiting 2 seconds before printing a message
@usage
-- To use Async you must register the allowed functions when the file is loaded, often this will just be giving access to
-- some functions within a module if you expect that at part may be blocked by in game permissions or a custom system you have made
-- you may also want to register functions that you want to have a time delay, such as waiting 2 seconds before printing a message
-- This player.admin is called (command or gui element event) by a player who isnt admin then it will error
-- here we register the function to promote the player so that it will run async
local promote_player =
Async.register(function(player)
player.admin = true
end)
-- When player.admin is called (either command or gui element event) by a player who isnt admin then it will error
-- here we register the function to promote the player so that it will run async and outside the player scope
local promote_player =
Async.register(function(player)
player.admin = true
end)
-- This will allow us to bypass this by running one tick later outside of any player scope
Async(promote_player,game.player)
-- This will allow us to bypass the error by running one tick later outside of any player scope
Async(promote_player,game.player)
-- Here we make an sync function that we want to have a delay, note the delay is not defined here
local print_message =
Async.register(function(player,message)
player.print(message)
end)
-- Here we make an sync function that we want to have a delay, note the delay is not defined here
local print_message =
Async.register(function(player,message)
player.print(message)
end)
-- We can then call the async function with a delay using the wait function
Async.wait(60,print_message,game.player,'One second has passed!')
-- We can then call the async function with a delay using the wait function
Async.wait(60, print_message, game.player, 'One second has passed!')
]]
local Task = require 'utils.task' --- @dep utils.task
@@ -39,13 +39,38 @@ Token.register(function(params)
return func(unpack(params.params))
end)
--- Register a new async function, must called when the file is loaded
-- @tparam function callback the function that will become an async function
--[[-- Register a new async function, must called when the file is loaded
@function register
@tparam function callback the function that can be called as an async function
@treturn string the uid of the async function which can be passed to Async.run and Async.wait
@usage-- Registering a function to set the admin state of a player
local set_admin =
Async.register(function(player, state)
if player.valid then
player.admin = state
end
end)
@usage-- Registering a function to print to a player
local print_to_player =
Async.register(function(player, message)
if player.valid then
player.print(message)
end
end)
]]
Async.register = Token.register
--- Runs the async function linked to this token, you may supply any number of params as needed
-- @tparam string token the token of the async function you want to run
-- @tparam[opt] any ... the other params that you want to pass to your function
--[[-- Runs an async function, you may supply any number of arguments as required by that function
@tparam string token the token of the async function you want to run
@tparam[opt] any ... the other params that you want to pass to your function
@usage-- Make a player admin regardless of if you are admin
Async.run(set_admin, player, true)
]]
function Async.run(token,...)
Task.queue_task(internal_run, {
token = token,
@@ -53,10 +78,15 @@ function Async.run(token,...)
})
end
--- Runs the async function linked to this token after the given number of ticks, you may supply any number of params as needed
-- @tparam number ticks the number of ticks that you want the function to run after
-- @tparam string token the token of the async function you want to run
-- @tparam[opt] any ... the other params that you want to pass to your function
--[[-- Runs an async function after the given number of ticks, you may supply any number of arguments as required by that function
@tparam number ticks the number of ticks that you want the function to run after
@tparam string token the token of the async function you want to run
@tparam[opt] any ... the other params that you want to pass to your function
@usage-- Print a message to a player after 5 seconds
Async.wait(300, print_to_player, 'Hello, World!')
]]
function Async.wait(ticks,token,...)
Task.set_timeout_in_ticks(ticks, internal_run, {
token = token,

View File

@@ -1,197 +1,193 @@
--[[-- Core Module - Commands
- Factorio command making module that makes commands with better parse and more modularity
@core Commands
@alias Commands
- Factorio command making module that makes commands with better parse and more modularity
@core Commands
@alias Commands
@usage
---- 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:
@usage--- Full code example, see below for explaination
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
else
return false
end
end)
:set_defaults{ smiley=false }
: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)
-- 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
local msg = ') '..player.name
if smiley then
msg = ':'..msg
end
-- 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
for 1 = 1,repeat_count do
Command.print(1..msg)
end
end)
-- 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
@usage--- 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.
-- 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
-- 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.')
-- 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
return true -- true return 1
end
end)
-- 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)
@usage
---- 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:
-- 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)
-- 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
-- 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}
-- 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
-- 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
}
-- 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
-- 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
-- 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 double
-- messages to the user:
input = Commands.parse('number-int',input,player,reject)
if not input then return end -- nil check
-- 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)
-- 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
-- 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)
-- Other values that can be returned from register
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 don't use this method see below
return Commands.success(message[opt]) -- will return the success message to the user and your given message, halts execution
return <any> -- if any value is returned then it will be returned to the player via a Commands.success call
@usage
---- 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.
@usage--- Example Authenticator:
-- The command system is best used when you can control who uses 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 certain commands to require the user to be a game admin.
-- 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.')
-- For our admin only example we will set a flag to true when we want it to be admin only;
-- when we define the command will will use :set_flag('admin_only', true);
-- then inside the authenticator we will test if the flag is present using: if flags.admin_only then
-- 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)
-- When the authenticator is called by the command handler it will be passed 4 arguments:
-- 1) player - the player who used the command
-- 2) command - the name of the command that is being used
-- 3) flags - the flags which have been set for this command, flags are set with :set_flag(name, value)
-- 4) reject - the reject function which is the preferred method to prevent execution of the command
-- 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)
-- No return is required to allow the command to execute but 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 assume that any one can use it
-- 2) when the "admin_only" flag is set, and the player is admin
-- 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}
-- When want to prevent exicution of the command we must reject it, listed is how that can be done:
-- 1) return false -- this is the most basic rejection and should only be used while testing
-- 2) return reject -- returning the reject function is as a fail safe in case you forget to call it, same as returning false
-- 3) reject() -- this will block execution without to allowing further code to be ran in your 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 your code before rejecting
-- 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
}
-- Example Code:
Commands.add_authenticator(function(player, command, flags, reject)
-- Check if the command is admin only
if flags.admin_only then
-- Return true if player is admin, or reject and return error message
return player.admin or reject('This command is for admins only!')
else
-- Return true if command was not admin only
return true
end
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
@usage--- Example Parse:
-- Before you make a command 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 and validated before your command is executed;
-- This module should is paired with a general command parse but you may want to create your own.
-- 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)
-- 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
:add_param('repeat_count', false, 'number-range-int', 5, 10) -- "repeat_count" is required "number-range-int" in a range 5 to 10 inclusive
-- 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 don't use this method see below
return Commands.success(message[opt]) -- will return the success message to the user and your given message, halts execution
return <any> if any value is returned then it will be returned to the player via a Commands.success call
-- The command parse will be passed 3 arguments plus any other which you define, in our case:
-- 1) input - 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) player - the player who is using the command, this is always present
-- 3) reject - the reject function to throw an error to the user, this is always present
-- 4) range_min - the range min, this is user defined and has the value given when the param is defined
-- 5) range_max - the range max, this is user defined and has the value given when the param is defined
-- 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
else
return false
end
end)
:set_defaults{smiley=false}
: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 1 = 1,repeat_count do
Command.print(1..msg)
end
end)
-- When returning from the param parse you 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 is rejected, 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 to the user
-- nb: if you do not return reject after you call it then you will still be returning nil so there will be a duplicate error message
-- It should be noted that if you want to expand on an existing parse you can use Commands.parse(type, input, player, reject)
-- this function will either return a new value for the input or nil, if it is nil you should return nil to prevent duplicate
-- error 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
-- 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)
]]
@@ -199,38 +195,58 @@ local Game = require 'utils.game' --- @dep utils.game
local player_return,write_json = _C.player_return, _C.write_json --- @dep expcore.common
local Commands = {
defines={ -- common values are stored error like signals
--- Values returned by the signal functions to cause the command system to react
defines = {
error='CommandError',
unauthorized='CommandErrorUnauthorized',
success='CommandSuccess'
},
commands={}, -- custom command data will be stored here
authorization_fail_on_error=false, -- set true to have authorize fail if a callback fails to run, more secure
authorization={}, -- custom function are stored here which control who can use what commands
parse_functions={}, -- used to store default functions which are common parse function such as player or number in range
print=player_return, -- short cut so player_return does not need to be required in every module
_prototype={}, -- used to store functions which gets added to new custom commands
--- Custom command data will be stored here
commands={},
--- Set true to have authorize fail if a callback fails to run, more secure
authorization_fail_on_error=false,
--- Custom function are stored here which control who can use what commands
authorization={},
--- Used to store default functions which are common parse function such as player or number in range
parse_functions={},
-- Sends a value to the player, different to success as this does not signal the end of your command
print=player_return,
--- Used to store functions which gets added to new custom commands
_prototype={},
}
--- Authenication.
-- Functions that control who can use commands
-- @section auth
--- Adds an authorization callback, function used to check if a player if allowed to use a command
-- @tparam function callback 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 - 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
--[[-- Adds an authorization callback, function used to check if a player if allowed to use a command
@tparam function callback the callback you want to register as an authenticator
@treturn number the index it was inserted at use to remove the callback, if anon function used
@usage-- Test if a command is admin only and if the player is admin
local admin_authenticator =
Commands.add_authenticator(function(player, command, flags, reject)
if flags.admin_only then
return player.admin or reject('This command is for admins only!')
else
return true
end
end)
]]
function Commands.add_authenticator(callback)
table.insert(Commands.authorization,callback)
return #Commands.authorization
end
--- Removes an authorization callback
-- @tparam function|number callback the callback to remove, an index returned by add_authenticator can be passed
-- @treturn boolean was the callback found and removed
--[[-- Removes an authorization callback
@tparam function|number callback the callback to remove, an index returned by add_authenticator can be passed
@treturn boolean if the callback found and removed successfuly
@usage-- Removing the admin authenticator, can not be done dueing runtime
Commands.remove_authenticator(admin_authenticator)
]]
function Commands.remove_authenticator(callback)
if type(callback) == 'number' then
-- if a number is passed then it is assumed to be the index
@@ -256,13 +272,18 @@ function Commands.remove_authenticator(callback)
return false
end
--- Mostly used internally, calls all authorization callbacks, returns if the player is authorized
-- @tparam LuaPlayer player the player that is using the command, passed to callbacks
-- @tparam string command_name the command that is being used, passed to callbacks
-- @treturn[1] boolean true player is authorized
-- @treturn[1] string commands const for success
-- @treturn[2] boolean false player is unauthorized
-- @treturn[2] string|locale_string the reason given by the authenticator
--[[-- Mostly used internally, calls all authorization callbacks, returns if the player is authorized
@tparam LuaPlayer player the player that is using the command, passed to callbacks
@tparam string command_name the command that is being used, passed to callbacks
@treturn[1] boolean true player is authorized
@treturn[1] string commands const for success
@treturn[2] boolean false player is unauthorized
@treturn[2] string|locale_string the reason given by the authenticator
@usage-- Test if a player can use "repeat-name"
local authorized, status = Commands.authorize(game.player, 'repeat-name')
]]
function Commands.authorize(player,command_name)
local failed
if not player then return true end
@@ -300,13 +321,22 @@ function Commands.authorize(player,command_name)
return true, Commands.defines.success
end
end
--- Getters.
-- Functions that get commands
-- @section getters
--- Gets all commands that a player is allowed to use, game commands not included
-- @tparam[opt] LuaPlayer player the player that you want to get commands of, nil will return all commands
-- @treturn table all commands that that player is allowed to use, or all commands
--[[-- Gets all commands that a player is allowed to use, game commands are not included
@tparam[opt] LuaPlayer player the player that you want to get commands of, nil will return all commands
@treturn table all commands that that player is allowed to use, or all commands
@usage-- Get the command you are allowed to use
local commands = Commands.get(game.player)
@usage-- Get all commands that are registered
local commands = Commands.get()
]]
function Commands.get(player)
player = Game.get_player_from_any(player)
if not player then return Commands.commands end
@@ -319,12 +349,20 @@ function Commands.get(player)
return allowed
end
--- Searches command names and help messages to find possible commands, game commands included
-- @tparam string keyword the word which you are trying to find
-- @tparam[opt] LuaPlayer allowed_player the player to get allowed commands of, if nil all commands are searched
-- @treturn table all commands that contain the key word, and allowed by player if player given
function Commands.search(keyword,allowed_player)
local custom_commands = Commands.get(allowed_player)
--[[-- Searches command names and help messages to find possible commands, game commands are included
@tparam string keyword the word which you are trying to find in your search
@tparam[opt] LuaPlayer player the player to get allowed commands of, if nil all commands are searched
@treturn table all commands that contain the key word, and allowed by player if player given
@usage-- Get all commands which "repeat"
local commands = Commands.search('repeat')
@usage-- Get all commands which "repeat" and you are allowed to use
local commands = Commands.search('repeat', game.player)
]]
function Commands.search(keyword,player)
local custom_commands = Commands.get(player)
local matches = {}
keyword = keyword:lower()
-- loops over custom commands
@@ -354,15 +392,25 @@ end
-- Functions that help with parsing
-- @section parse
--- Adds a parse function which can be called by name rather than callback (used in add_param)
-- nb: this is not needed as you can use the callback directly this just allows it to be called by name
-- @tparam string name the name of the parse, should be the type like player or player_alive, must be unique
-- @tparam function callback the callback that is ran to parse the input
-- parse param - input: string - the input given by the user for this param
-- parse param - player: LuaPlayer - the player who is using the command
-- parse param - reject: function(error_message) - use this function to send a error to the user and fail running
-- parse return - the value that will be passed to the command callback, must not be nil and if reject then command is not run
-- @treturn boolean was the parse added will be false if the name is already used
--[[-- Adds a parse function which can be called by name (used in add_param)
nb: this is not required as you can use the callback directly this just allows it to be called by name
@tparam string name the name of the parse, should be the type like player or player_alive, must be unique
@tparam function callback the callback that is ran to parse the input
@treturn boolean was the parse added will be false if the name is already used
@usage-- Adding a parse to validate ints in a given range
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
-- 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 rather than a string, thus the param is now the correct type
return rtn
end
end)
]]
function Commands.add_parse(name,callback)
if Commands.parse_functions[name] then
return false
@@ -372,18 +420,28 @@ function Commands.add_parse(name,callback)
end
end
--- Removes a parse function, see add_parse for adding them
-- @tparam string name the name of the parse to remove
--[[-- Removes a parse function, see add_parse for adding them
@tparam string name the name of the parse to remove
@usage-- Removing a parse
Commands.remove_parse('number-range-int')
]]
function Commands.remove_parse(name)
Commands.parse_functions[name] = nil
end
--- Intended to be used within other parse functions, runs a parse and returns success and new value
-- @tparam string name the name of the parse to call, must be registered and cant be a function
-- @tparam string input string the input to pass to the parse, will always be a but might not be the original input
-- @tparam LuaPlayer player the player that is calling using the command
-- @tparam function reject the reject function that was passed by the command hander
-- @treturn any the new value for the input, may be nil, if nil then either there was an error or input was nil
--[[-- Intended to be used within other parse functions, runs a parse and returns success and new value
@tparam string name the name of the parse to call, must be registered parse
@tparam string input string the input to pass to the parse, must be a string but not necessarily the original input
@tparam LuaPlayer player the player that is using the command
@tparam function reject the reject function that was passed by the command hander
@treturn any the new value for the input, may be nil, if nil then either there was an error or input was nil
@usage-- Parsing a int in a given range
local parsed_input = Commands.parse('number-range-int', '7', player, reject, 1, 10) -- valid range 1 to 10
]]
function Commands.parse(name,input,player,reject,...)
if not Commands.parse_functions[name] then return end
local success,rtn = pcall(Commands.parse_functions[name],input,player,reject,...)
@@ -397,10 +455,16 @@ end
-- Functions that create a new command
-- @section creation
--- Creates a new command object to added details to, note this does not register the command to the game
-- @tparam string name the name of the command to be created
-- @tparam string help the help message for the command
-- @treturn Commands._prototype this will be used with other functions to generate the command functions
--[[-- Creates a new command object to added details to, note this does not register the command to the game api
@tparam string name the name of the command to be created
@tparam string help the help message for the command
@treturn Commands._prototype this will be used with other functions to generate the command functions
@usage-- Define a new command
local command =
Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.')
]]
function Commands.new_command(name,help)
local command = setmetatable({
name=name,
@@ -419,16 +483,23 @@ function Commands.new_command(name,help)
return command
end
--- Adds a new param to the command this will be displayed in the help and used to parse the input
-- @tparam string name the name of the new param that is being added to the command
-- @tparam[opt=false] boolean optional is this param required for this command, these must be after all required params
-- @tparam[opt=pass function through] ?string|function parse this function will take the input and return a new (or same) value
-- @param[opt] ... extra args you want to pass to the parse function; for example if the parse is general use
-- parse param - input: string - the input given by the user for this param
-- parse param - player: LuaPlayer - the player who is using the command
-- parse param - reject: function(error_message) - use this function to send a error to the user and fail running
-- parse return - the value that will be passed to the command callback, must not be nil and if reject then command is not run
-- @treturn Commands._prototype pass through to allow more functions to be called
--[[-- Adds a new param to the command this will be displayed in the help and used to parse the input
@tparam string name the name of the new param that is being added to the command
@tparam[opt=false] boolean optional is this param required for this command, these must be after all required params
@tparam[opt=pass function through] ?string|function parse this function will take the input and return a new (or same) value
@param[opt] ... extra args you want to pass to the parse function; for example if the parse is general use
@treturn Commands._prototype pass through to allow more functions to be called
@usage-- Adding a param which has an parse defined
command:add_param('repeat-count', false, 'number-range-int', 1, 5)
@usage-- Adding a param which has a custom parse, see Commands.add_parse for details
command:add_param('smiley', true, function(input, player, reject)
if not input then return end
return input:lower() == 'true' or input:lower() == 'yes' or false
end)
]]
function Commands._prototype:add_param(name,optional,parse,...)
local parse_args = {...}
if type(optional) ~= 'boolean' then
@@ -449,10 +520,20 @@ function Commands._prototype:add_param(name,optional,parse,...)
return self
end
--- Adds default values to params only matters if the param is optional, if default value is a function it is called with param player
-- @tparam table defaults table a keyed by the name of the param with the value as the default value {paramName=defaultValue}
-- callback param - player: LuaPlayer - the player using the command, default value does not need to be a function callback
-- @treturn Commands._prototype pass through to allow more functions to be called
--[[-- Add default values to params, only as an effect if the param is optional, if default value is a function it is called with acting player
@tparam table defaults table which is keyed by the name of the param and the value is the default value
@treturn Commands._prototype pass through to allow more functions to be called
@usage-- Adding default values
command:set_defaults{
smiley = false,
-- not in example just used to show arguments given
player_name = function(player)
return player.name
end
}
]]
function Commands._prototype:set_defaults(defaults)
for name,value in pairs(defaults) do
if self.params[name] then
@@ -462,26 +543,32 @@ function Commands._prototype:set_defaults(defaults)
return self
end
--- 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 string name the name of the tag to be added; used to keep flags separate
-- @tparam any value 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
--[[-- 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 string name the name of the tag to be added, set to true if no value is given
@tparam[opt=true] any value the tag that you want can be anything that the authenticators are expecting
@treturn Commands._prototype pass through to allow more functions to be called
@usage-- Setting a custom flag
command:set_flag('admin_only', true)
@usage-- When value is true it does not need to be given
command:set_flag('admin_only')
]]
function Commands._prototype:set_flag(name,value)
if not value then
-- value not given so name is the value
table.insert(self.flags,name)
else
-- name is given so its key: value
self.flags[name] = value
end
value = value or true
self.flags[name] = value
return self
end
--- Adds an alias or multiple that will also be registered with the same callback, eg /teleport can be /tp with both working
-- @usage command:add_alias('aliasOne','aliasTwo','etc')
-- @tparam string any ... amount of aliases that you want this command to be callable with
-- @treturn Commands._prototype pass through to allow more functions to be called
--[[-- Adds an alias, or multiple, that will also be registered with the same callback, eg /teleport can be used as /tp
@tparam string any ... amount of aliases that you want this command to be callable with
@treturn Commands._prototype pass through to allow more functions to be called
@usage-- Added multiple aliases to a command
command:add_alias('name', 'rname')
]]
function Commands._prototype:add_alias(...)
for _,alias in pairs({...}) do
table.insert(self.aliases,alias)
@@ -490,21 +577,35 @@ function Commands._prototype:add_alias(...)
return self
end
--- Enables auto concatenation of any params on the end so quotes are not needed for last param
-- nb: this will disable max param checking as they will be concatenated onto the end of that last param
-- this can be useful for reasons or longs text, can only have one per command
-- @treturn Commands._prototype pass through to allow more functions to be called
--[[-- Enables auto concatenation of any params on the end so quotes are not needed for last param
nb: this will disable max param checking as they will be concatenated onto the end of that last param
this can be useful for reasons or longs text, can only have one per command
@treturn Commands._prototype pass through to allow more functions to be called
@usage-- Enable auto concat for a command
command:enable_auto_concat()
]]
function Commands._prototype:enable_auto_concat()
self.auto_concat = true
return self
end
--- Adds the callback to the command and registers all aliases, params and help message with the game
-- nb: this must be the last function ran on the command and must be done for the command to work
-- @tparam function callback the callback for the command, will receive the player running command, and params added with add_param
-- callback param - player: LuaPlayer - the player who used the command
-- callback param - ... - any params which were registered with add_param in the order they where registered
-- callback param - raw: string - the raw input from the user, comes after every param added with add_param
--[[-- Adds the callback to the command and registers all aliases, params and help message with the game api
nb: this must be the last function ran on the command and must be done for the command to work
@tparam function callback the callback for the command, will receive the player running command, and params added with add_param
@usage-- Registering your command to the game api
command:register(function(player, repeat_count, smiley, _)
local msg = ') '..player.name
if smiley then msg = ':'..msg end
for 1 = 1,repeat_count do
Command.print(1..msg)
end
end)
]]
function Commands._prototype:register(callback)
-- generates a description to be used
self.callback = callback
@@ -538,13 +639,16 @@ end
-- Functions that indicate status
-- @section status
--- Sends an error message to the player and returns a constant to return to command handler to exit execution
-- nb: this is for non fatal errors meaning there is no log of this event
-- nb: if reject is giving as a param to the callback use that instead
-- @usage return Commands.error()
-- @tparam[opt] string error_message an optional error message that can be sent to the user
-- @tparam[opt] string play_sound the sound to play for the error
-- @treturn Commands.defines.error return this to command handler to exit execution
--[[-- Sends an error message to the player and when returned will stop exicution of the command
nb: this is for non fatal errors meaning there is no log of this event, use during register callback
@tparam[opt=''] string error_message an optional error message that can be sent to the user
@tparam[opt=utility/wire_pickup] string play_sound the sound to play for the error
@treturn Commands.defines.error return this to command handler to exit execution
@usage-- Send an error message to the player, and stops further code running
return Commands.error('The player you selected is offline')
]]
function Commands.error(error_message,play_sound)
error_message = error_message or ''
player_return({'expcore-commands.command-fail',error_message},'orange_red')
@@ -555,12 +659,20 @@ function Commands.error(error_message,play_sound)
return Commands.defines.error
end
--- Sends an error to the player and logs the error, used with pcall within command handler please avoid direct use
-- nb: use error(error_message) within your callback to trigger do not trigger directly as the handler may still continue
-- @tparam boolean success the success value returned from pcall, or just false to trigger error
-- @tparam string command_name the name of the command this is used within the log
-- @tparam string error_message the error returned by pcall or some other error, this is logged and not returned to player
-- @treturn boolean the opposite of success so true means to cancel execution, used internally
--[[-- Sends an error to the player and logs the error, used with pcall within command handler please avoid direct use
nb: use error(error_message) within your callback to trigger do not trigger directly as code exictuion may still continue
@tparam boolean success the success value returned from pcall, or just false to trigger error
@tparam string command_name the name of the command this is used within the log
@tparam string error_message the error returned by pcall or some other error, this is logged and not returned to player
@treturn boolean the opposite of success so true means to cancel execution, used internally
@usage-- Used in the command system to log handler errors
local success, err = pcall(command_data.callback, player, unpack(params))
if Commands.internal_error(success, command_data.name, err) then
return command_log(player, command_data, 'Internal Error: Command Callback Fail', raw_params, command_event.parameter, err)
end
]]
function Commands.internal_error(success,command_name,error_message)
if not success then
Commands.error('Internal Error, Please contact an admin','utility/cannot_build')
@@ -569,16 +681,34 @@ function Commands.internal_error(success,command_name,error_message)
return not success
end
--- Sends a value to the player, followed by a command complete message
-- nb: either return a value from your callback to trigger or return the return of this to prevent two messages
-- @tparam[opt] any value the value to return to the player, if nil then only success message returned
-- @treturn Commands.defines.success return this to the command handler to prevent two success messages
--[[-- Sends a value to the player, followed by a command complete message
nb: returning any value from your callback will trigger this function, return this function to prevent duplicate messages
@tparam[opt] any value the value to return to the player, if nil then only success message returned
@treturn Commands.defines.success return this to the command handler to prevent two success messages
@usage-- Print a custom success message
return Commands.success('Your message has been printed')
@usage-- Returning the value has the same result
return 'Your message has been printed'
]]
function Commands.success(value)
if value ~= nil then player_return(value) end
player_return({'expcore-commands.command-ran'},'cyan')
return Commands.defines.success
end
--[[-- Sends a value to the player, different to success as this does not signal the end of your command
@function print
@tparam any value the value that you want to return to the player
@tparam table colour the colour of the message that the player sees
@usage-- Output a message to the player
Commands.print('Your command is in progress')
]]
-- logs command usage to file
local function command_log(player,command,comment,params,raw,details)
local player_name = player and player.name or '<Server>'
@@ -594,6 +724,7 @@ end
--- Main event function that is ran for all commands, used internally please avoid direct use
-- @tparam table command_event passed directly from command event from the add_command function
-- @usage Commands.run_command(event)
function Commands.run_command(command_event)
local command_data = Commands.commands[command_event.name]
-- player can be nil when it is the server

View File

@@ -1,46 +1,59 @@
--[[-- Core Module - Common Library
- Adds some commonly used functions used in many modules
@core Common-Library
@alias Common
--[[-- Core Module - Common
- Adds some commonly used functions used in many modules
@core Common
@alias Common
]]
local Colours = require 'utils.color_presets' --- @dep utils.color_presets
local Game = require 'utils.game' --- @dep utils.game
local Util = require 'util' --- @dep util
require 'overrides.table'
require 'overrides.math'
local Common = {}
--- Type Checking.
-- @section typeCheck
--- Asserts the argument is of type test_type
-- @usage type_check('foo','string') -- return true
-- @usage type_check('foo') -- return false
-- @tparam any value the value to be tested
-- @tparam[opt=nil] string test_type the type to test for if not given then it tests for nil
-- @treturn boolean is v of type test_type
--[[-- Asserts the argument is of type test_type
@tparam any value the value to be tested
@tparam[opt=nil] string test_type the type to test for if not given then it tests for nil
@treturn boolean is v of type test_type
@usage-- Check for a string value
local is_string = type_check(value, 'string')
@usage-- Check for a nil value
local is_nil = type_check(value)
]]
function Common.type_check(value, test_type)
return test_type and value and type(value) == test_type or not test_type and not value or false
end
--- Raises an error if the value is of the wrong type
-- @usage type_error('foo','number','Value must be a number') -- will raise error "Value must be a number"
-- @tparam any value the value that you want to test the type of
-- @tparam string test_type the type that the value should be
-- @tparam string error_message the error message that is returned
-- @tparam number level the level to call the error on (level = 1 means the caller)
-- @treturn boolean true if no error was called
--[[-- Raises an error if the value is of the wrong type
@tparam any value the value that you want to test the type of
@tparam string test_type the type that the value should be
@tparam string error_message the error message that is returned
@tparam number level the level to call the error on (level = 1 is the caller)
@treturn boolean true if no error was called
@usage-- Raise error if value is not a number
type_error(value, 'number', 'Value must be a number')
]]
function Common.type_error(value, test_type, error_message, level)
level = level and level+1 or 2
return Common.type_check(value,test_type) or error(error_message,level)
end
--- Asserts the argument is one of type test_types
-- @param value the variable to check
-- @param test_types the type as a table of strings
-- @treturn boolean true if value is one of test_types
--[[-- Asserts the argument is one of type test_types
@param value the variable to check
@param test_types the type as a table of strings
@treturn boolean true if value is one of test_types
@usage-- Check for a string or table
local is_string_or_table = multi_type_check(value, {'string','table'})
]]
function Common.multi_type_check(value, test_types)
local vtype = type(value)
for _, arg_type in ipairs(test_types) do
@@ -51,45 +64,73 @@ function Common.multi_type_check(value, test_types)
return false
end
--- Raises an error if the value is of the wrong type
-- @usage multi_type_error('foo',{'string','table'},'Value must be a string or table') -- will raise error "Value must be a string or table"
-- @tparam any value the value that you want to test the type of
-- @tparam table test_types the type as a table of strings
-- @tparam string error_message the error message that is returned
-- @tparam number level the level to call the error on (level = 1 means the caller)
-- @treturn boolean true if no error was called
--[[-- Raises an error if the value is of the wrong type
@tparam any value the value that you want to test the type of
@tparam table test_types the type as a table of strings
@tparam string error_message the error message that is returned
@tparam number level the level to call the error on (level = 1 is the caller)
@treturn boolean true if no error was called
@usage-- Raise error if value is not a string or table
multi_type_error('foo', {'string','table'}, 'Value must be a string or table')
]]
function Common.multi_type_error(value, test_types, error_message, level)
level = level and level+1 or 2
return Common.mult_type_check(value, test_types) or error(error_message,level)
end
--- Raises an error when the value is the incorrect type, uses a consistent error message format
-- @usage validate_argument_type('foo','number','repeat_count',2) -- will raise error "Bad argument #02 to "<anon>"; "repeat_count" is of type string expected number"
-- @tparam any value the value that you want to test the type of
-- @tparam string test_type the type that the value should be
-- @tparam string param_name the name of the param
-- @tparam number param_number the number param it is
-- @treturn boolean true if no error was raised
function Common.validate_argument_type(value, test_type, param_name, param_number)
--[[-- Raises an error when the value is the incorrect type, uses a consistent error message format
@tparam any value the value that you want to test the type of
@tparam string test_type the type that the value should be
@tparam number param_number the number param it is
@tparam[opt] string param_name the name of the param
@treturn boolean true if no error was raised
@usage-- Output: "Bad argument #2 to "<anon>"; argument is of type string expected number"
validate_argument_type(value, 'number', 2)
@usage-- Output: "Bad argument #2 to "<anon>"; "repeat_count" is of type string expected number"
validate_argument_type(value, 'number', 2, 'repeat_count')
]]
function Common.validate_argument_type(value, test_type, param_number, param_name)
if not Common.test_type(value,test_type) then
local function_name = debug.getinfo(2,'n').name or '<anon>'
local error_message = string.format('Bad argument #%2d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), test_type)
local error_message
if param_name then
error_message = string.format('Bad argument #%d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), test_type)
else
error_message = string.format('Bad argument #%d to %q; argument is of type %s expected %s', param_number, function_name, type(value), test_type)
end
return error(error_message,3)
end
return true
end
--- Raises an error when the value is the incorrect type, uses a consistent error message format
-- @usage validate_argument_type('foo',{'string','table'},'repeat_count',2) -- will raise error "Bad argument #02 to "<anon>"; "repeat_count" is of type string expected string or table"
-- @tparam any value the value that you want to test the type of
-- @tparam string test_types the types that the value should be
-- @tparam string param_name the name of the param
-- @tparam number param_number the number param it is
-- @treturn boolean true if no error was raised
function Common.validate_argument_multi_type(value, test_types, param_name, param_number)
--[[-- Raises an error when the value is the incorrect type, uses a consistent error message format
@tparam any value the value that you want to test the type of
@tparam string test_types the types that the value should be
@tparam number param_number the number param it is
@tparam[opt] string param_name the name of the param
@treturn boolean true if no error was raised
@usage-- Output: "Bad argument #2 to "<anon>"; argument is of type number expected string or table"
validate_argument_type(value, {'string','table'}, 2)
@usage-- Output: "Bad argument #2 to "<anon>"; "player" is of type number expected string or table"
validate_argument_type(value, {'string','table'}, 2, 'player')
]]
function Common.validate_argument_multi_type(value, test_types, param_number, param_name)
if not Common.multi_type_check(value,test_types) then
local function_name = debug.getinfo(2,'n').name or '<anon>'
local error_message = string.format('Bad argument #%2d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), table.concat(test_types,' or '))
local error_message
if param_name then
error_message = string.format('Bad argument #%2d to %q; %q is of type %s expected %s', param_number, function_name, param_name, type(value), table.concat(test_types,' or '))
else
error_message = string.format('Bad argument #%2d to %q; argument is of type %s expected %s', param_number, function_name, type(value), table.concat(test_types,' or '))
end
return error(error_message,3)
end
return true
@@ -116,10 +157,15 @@ end
--- Value Returns.
-- @section valueReturns
--- Tests if a string contains a given substring.
-- @tparam string s the string to check for the substring
-- @tparam string contains the substring to test for
-- @treturn boolean true if the substring was found in the string
--[[-- Tests if a string contains a given substring.
@tparam string s the string to check for the substring
@tparam string contains the substring to test for
@treturn boolean true if the substring was found in the string
@usage-- Test if a string contains a sub string
local found = string_contains(str, 'foo')
]]
function Common.string_contains(s, contains)
return s and string.find(s, contains) ~= nil
end
@@ -127,82 +173,104 @@ end
--[[-- Used to resolve a value that could also be a function returning that value
@tparam any value the value which you want to test is not nil and if it is a function then call the function
@treturn any the value given or returned by value if it is a function
@usage-- Default value handling
-- if default value is not a function then it is returned
-- if it is a function then it is called with the first argument being self
local value = Common.resolve_value(self.defaut_value,self)
-- if default value is a function then it is called with the first argument being self
local value = Common.resolve_value(self.defaut_value, self)
]]
function Common.resolve_value(value,...)
if value then
if type(value) == 'function' then
return value(...)
else
return value
end
end
end
--- Returns a valid string with the name of the actor of a command.
-- @treturns string the name of the current actor
function Common.get_actor()
return game.player and game.player.name or '<server>'
return value and type(value) == 'function' and value(...) or value
end
--- Converts a varible into its boolean value, nil and false return false
-- @treturn boolean the boolean form of the varible
-- @usage local bool = cast_bool(var)
function Common.cast_bool(var)
return var and true or false
end
--- Returns either the second or third argument based on the first argument
-- @usage ternary(input_string == 'test', 'Input is test', 'Input is not test')
function Common.ternary(c, t, f)
return c and t or f
end
--- Returns a string for a number with comma seperators
-- @usage comma_value(input_number)
function Common.comma_value(n) -- credit http://richard.warburton.it
local left, num, right = string.match(n, '^([^%d]*%d)(%d*)(.-)$')
return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right
end
--- Sets a table element to value while also returning value.
-- @param tbl table to change the element of
-- @param key string
-- @param value nil|boolean|number|string|table to set the element to
-- @return value
--[[-- Sets a table element to value while also returning value.
@tparam table tbl to change the element of
@tparam string key the key to set the value of
@tparam any value the value to set the key as
@treturn any the value that was set
@usage-- Set and return value
local value = set_and_return(players, player.name, player.online_time)
]]
function Common.set_and_return(tbl, key, value)
tbl[key] = value
return value
end
--- Writes a table object to a file in json format
-- @tparam string path the path of the file to write include / to use dir
-- @tparam table tbl the table that will be converted to a json string and wrote to file
--[[-- Writes a table object to a file in json format
@tparam string path the path of the file to write include / to use dir
@tparam table tbl the table that will be converted to a json string and wrote to file
@usage-- Write a lua table as a json to script-outpt/dump
write_json('dump', tbl)
]]
function Common.write_json(path,tbl)
game.write_file(path,game.table_to_json(tbl)..'\n',true,0)
end
--- Calls a require that will not error if the file is not found
-- @usage local file = opt_require('file.not.present') -- will not cause any error
-- @tparam string path the path that you want to require
-- @return the returns from that file or nil, error if not loaded
--[[-- Calls a require that will not error if the file is not found
@usage local file = opt_require('file.not.present') -- will not cause any error
@tparam string path the path that you want to require
@return the returns from that file or nil, error if not loaded
@usage-- Require a file without causing errors, for when a file might not exist
local Module = opt_require 'expcore.common'
]]
function Common.opt_require(path)
local success, rtn = pcall(require,path)
if success then return rtn
else return nil,rtn end
end
--- Returns a desync safe file path for the current file
-- @tparam[opt=0] number offset the offset in the stack to get, 0 is current file
-- @treturn string the file path
--[[-- Returns a desync safe file path for the current file
@tparam[opt=0] number offset the offset in the stack to get, 0 is current file
@treturn string the file path
@usage-- Get the current file path
local file_path = get_file_path()
]]
function Common.get_file_path(offset)
offset = offset or 0
return debug.getinfo(offset+2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
end
--- Converts a table to an enum
-- @tparam table tbl table the that will be converted
-- @treturn table the new table that acts like an enum
--[[-- Converts a table to an enum
@tparam table tbl table the that will be converted
@treturn table the new table that acts like an enum
@usage-- Make an enum
local colors = enum{
'red',
'green',
'blue'
}
]]
function Common.enum(tbl)
local rtn = {}
for k,v in pairs(tbl) do
@@ -221,12 +289,23 @@ function Common.enum(tbl)
return rtn
end
--- Returns the closest match to the input
-- @tparam table options table a of options for the auto complete
-- @tparam string input string the input that will be completed
-- @tparam[opt=false] boolean use_key when true the keys of options will be used as the options
-- @tparam[opt=false] boolean rtn_key when true the the key will be returned rather than the value
-- @return the list item found that matches the input
--[[-- Returns the closest match to the input
@tparam table options table a of options for the auto complete
@tparam string input string the input that will be completed
@tparam[opt=false] boolean use_key when true the keys of options will be used as the options
@tparam[opt=false] boolean rtn_key when true the the key will be returned rather than the value
@return the list item found that matches the input
@usage-- Get the element that includes "foo"
local value = auto_complete(tbl, "foo")
@usage-- Get the element with a key that includes "foo"
local value = auto_complete(tbl, "foo", true)
@usage-- Get the key with that includes "foo"
local key = auto_complete(tbl, "foo", true, true)
]]
function Common.auto_complete(options,input,use_key,rtn_key)
local rtn = {}
if type(input) ~= 'string' then return end
@@ -234,40 +313,65 @@ function Common.auto_complete(options,input,use_key,rtn_key)
for key,value in pairs(options) do
local check = use_key and key or value
if Common.string_contains(string.lower(check),input) then
local result = rtn_key and key or value
table.insert(rtn,result)
return rtn_key and key or value
end
end
return rtn[1]
end
--- Formating.
-- @section formating
--- Returns a message with valid chat tags to change its colour
-- @tparam string message the message that will be in the output
-- @tparam table color a color which contains r,g,b as its keys
-- @treturn string the message with the color tags included
--[[-- Returns a valid string with the name of the actor of a command.
@tparam string player_name the name of the player to use rather than server, used only if game.player is nil
@treturn string the name of the current actor
@usage-- Get the current actor
local player_name = get_actor()
]]
function Common.get_actor(player_name)
return game.player and game.player.name or player_name or '<server>'
end
--[[-- Returns a message with valid chat tags to change its colour
@tparam string message the message that will be in the output
@tparam table color a color which contains r,g,b as its keys
@treturn string the message with the color tags included
@usage-- Use factorio tags to color a chat message
local message = format_chat_colour('Hello, World!', { r=355, g=100, b=100 })
]]
function Common.format_chat_colour(message,color)
color = color or Colours.white
local color_tag = '[color='..math.round(color.r,3)..','..math.round(color.g,3)..','..math.round(color.b,3)..']'
return string.format('%s%s[/color]',color_tag,message)
end
--- Returns a message with valid chat tags to change its colour, using localization
-- @tparam ?string|table message the message that will be in the output
-- @tparam table color a color which contains r,g,b as its keys
-- @treturn table the message with the color tags included
--[[-- Returns a message with valid chat tags to change its colour, using localization
@tparam ?string|table message the message that will be in the output
@tparam table color a color which contains r,g,b as its keys
@treturn table the message with the color tags included
@usage-- Use factorio tags and locale strings to color a chat message
local message = format_chat_colour_localized('Hello, World!', { r=355, g=100, b=100 })
]]
function Common.format_chat_colour_localized(message,color)
color = color or Colours.white
color = math.round(color.r,3)..','..math.round(color.g,3)..','..math.round(color.b,3)
return {'color-tag',color,message}
end
--- Returns the players name in the players color
-- @tparam LuaPlayer player the player to use the name and color of
-- @tparam[opt=false] boolean raw_string when true a is returned rather than a localized string
-- @treturn table the players name with tags for the players color
--[[-- Returns the players name in the players color
@tparam LuaPlayer player the player to use the name and color of
@tparam[opt=false] boolean raw_string when true a string is returned rather than a localized string
@treturn table the players name with tags for the players color
@usage-- Format a players name using the players color as a string
local message = format_chat_player_name(game.player, true)
]]
function Common.format_chat_player_name(player,raw_string)
player = Game.get_player_from_any(player)
local player_name = player and player.name or '<Server>'
@@ -279,13 +383,21 @@ function Common.format_chat_player_name(player,raw_string)
end
end
--- Will return a value of any type to the player/server console, allows colour for in-game players
-- @usage player_return('Hello, World!') -- returns 'Hello, World!' to game.player or server console
-- @usage player_return('Hello, World!','green') -- returns 'Hello, World!' to game.player with colour green or server console
-- @usage player_return('Hello, World!',nil,player) -- returns 'Hello, World!' to the given player
-- @param value any value of any type that will be returned to the player or console
-- @tparam[opt=defines.colour.white] ?defines.color|string colour the colour of the text for the player, ignored when printing to console
-- @tparam[opt=game.player] LuaPlayer player the player that return will go to, if no game.player then returns to server
--[[-- Will return a value of any type to the player/server console, allows colour for in-game players
@tparam any value a value of any type that will be returned to the player or console
@tparam[opt=defines.colour.white] ?defines.color|string colour the colour of the text for the player, ignored when printing to console
@tparam[opt=game.player] LuaPlayer player the player that return will go to, if no game.player then returns to server
@usage-- Return a value to the current actor, rcon included
player_return('Hello, World!')
@usage-- Return a value to the current actor, with color
player_return('Hello, World!', 'green')
@usage-- Return to a player other than the current
player_return('Hello, World!', nil, player)
]]
function Common.player_return(value,colour,player)
colour = Common.type_check(colour,'table') and colour or Colours[colour] ~= Colours.white and Colours[colour] or Colours.white
player = player or game.player
@@ -320,14 +432,26 @@ function Common.player_return(value,colour,player)
else rcon.print(returnAsString) end
end
--- Formats tick into a clean format, denominations from highest to lowest
-- long will use words rather than letters
--[[-- Formats tick into a clean format, denominations from highest to lowest
-- time will use : separates
-- string will return a string not a locale string
-- when a denomination is false it will overflow into the next one
-- @tparam number ticks the number of ticks that represents a time
-- @tparam table options table a of options to use for the format
-- @treturn string a locale string that can be used
@tparam number ticks the number of ticks that represents a time
@tparam table options table a of options to use for the format
@treturn string a locale string that can be used
@usage-- Output: "0h 5m"
local time = format_time(18000, { hours=true, minutes=true, string=true })
@usage-- Output: "0 hours and 5 minutes"
local time = format_time(18000, { hours=true, minutes=true, string=true, long=true })
@usage-- Output: "00:05:00"
local time = format_time(18000, { hours=true, minutes=true, seconds=true, string=true })
@usage-- Output: "--:--:--"
local time = format_time(18000, { hours=true, minutes=true, seconds=true, string=true, null=true })
]]
function Common.format_time(ticks,options)
-- Sets up the options
options = options or {
@@ -415,12 +539,18 @@ end
--- Factorio.
-- @section factorio
--- Moves items to the position and stores them in the closest entity of the type given
-- @tparam table items items which are to be added to the chests, ['name']=count
-- @tparam[opt=navies] LuaSurface surface the surface that the items will be moved to
-- @tparam[opt={0,0}] table position the position that the items will be moved to {x=100,y=100}
-- @tparam[opt=32] number radius the radius in which the items are allowed to be placed
-- @tparam[opt=iron-chest] string chest_type the chest type that the items should be moved into
--[[-- Moves items to the position and stores them in the closest entity of the type given
@tparam table items items which are to be added to the chests, ['name']=count
@tparam[opt=navies] LuaSurface surface the surface that the items will be moved to
@tparam[opt={0,0}] table position the position that the items will be moved to {x=100,y=100}
@tparam[opt=32] number radius the radius in which the items are allowed to be placed
@tparam[opt=iron-chest] string chest_type the chest type that the items should be moved into
@treturn LuaEntity the last chest that had items inserted into it
@usage-- Copy all the items in a players inventory and place them in chests at {0,0}
move_items(game.player.get_main_inventory().get_contents())
]]
function Common.move_items(items,surface,position,radius,chest_type)
chest_type = chest_type or 'iron-chest'
surface = surface or game.surfaces[1]
@@ -466,14 +596,19 @@ function Common.move_items(items,surface,position,radius,chest_type)
return last_chest
end
--[[-- https://github.com/Refactorio/RedMew/blob/9184b2940f311d8c9c891e83429fc57ec7e0c4a2/map_gen/maps/diggy/debug.lua#L31
Prints a colored value on a location.
@param value between -1 and 1
@param surface LuaSurface
@param position Position {x, y}
@param scale float
@param offset float
@param immutable bool if immutable, only set, never do a surface lookup, values never change
--[[-- Prints a colored value on a location, color is based on the value.
nb: src is below but the gradent has been edited
https://github.com/Refactorio/RedMew/blob/9184b2940f311d8c9c891e83429fc57ec7e0c4a2/map_gen/maps/diggy/debug.lua#L31
@tparam number value the value to show must be between -1 and 1, scale can be used to achive this
@tparam LuaSurface surface the surface to palce the value on
@tparam table position {x, y} the possition to palce the value at
@tparam[opt=1] number scale how much to scale the colours by
@tparam[opt=0] number offset the offset in the +x +y direction
@tparam[opt=false] boolean immutable if immutable, only set, never do a surface lookup, values never change
@usage-- Place a 0 at {0,0}
print_grid_value(0, game.player.surface, { x=0, y=0 })
]]
function Common.print_grid_value(value, surface, position, scale, offset, immutable)
local is_string = type(value) == 'string'
@@ -488,23 +623,9 @@ function Common.print_grid_value(value, surface, position, scale, offset, immuta
scale = scale or 1
offset = offset or 0
position = {x = position.x + offset, y = position.y + offset}
local r = math.max(1, value) / scale
local g = 1 - math.abs(value) / scale
local b = math.min(1, value) / scale
if (r > 0) then
r = 0
end
if (b < 0) then
b = 0
end
if (g < 0) then
g = 0
end
r = math.abs(r)
local r = math.clamp(-value/scale, 0, 1)
local g = math.clamp(1-math.abs(value)/scale, 0, 1)
local b = math.clamp(value/scale, 0, 1)
color = { r = r, g = g, b = b}
@@ -534,81 +655,13 @@ function Common.print_grid_value(value, surface, position, scale, offset, immuta
}.active = false
end
--[[--
Prints a colored value on a location. When given a color_value and a delta_color,
will change the color of the text from the base to base + value * delta. This will
make the color of the text range from 'base_color' to 'base_color + delta_color'
as the color_value ranges from 0 to 1
@param value of number to be displayed
@param surface LuaSurface
@param position Position {x, y}
@param offset float position offset
@param immutable bool if immutable, only set, never do a surface lookup, values never change
@param color_value float How far along the range of values of colors the value is to be displayed
@param base_color {r,g,b} The color for the text to be if color_value is 0
@param delta_color {r,g,b} The amount to correct the base_color if color_value is 1
@param under_bound {r,g,b} The color to be used if color_value < 0
@param over_bound {r,g,b} The color to be used if color_value > 1
--[[-- Clears all flying text entities on a surface
@tparam LuaSurface surface the surface to clear
@usage-- Remove all flying text on the surface
clear_flying_text(game.player.surface)
]]
function Common.print_colored_grid_value(value, surface, position, offset, immutable,
color_value, base_color, delta_color, under_bound, over_bound)
local is_string = type(value) == 'string'
-- default values:
local color = base_color or Colours.white
local d_color = delta_color or Colours.black
local u_color = under_bound or color
local o_color = over_bound or color
if (color_value < 0) then
color = u_color
elseif (color_value > 1) then
color = o_color
else
color = {
r = color.r + color_value * d_color.r,
g = color.g + color_value * d_color.g,
b = color.b + color_value * d_color.b
}
end
local text = value
if type(immutable) ~= 'boolean' then
immutable = false
end
if not is_string then
offset = offset or 0
position = {x = position.x + offset, y = position.y + offset}
-- round at precision of 2
text = math.floor(100 * value) * 0.01
if (0 == text) then
text = '0.00'
end
end
if not immutable then
local text_entity = surface.find_entity('flying-text', position)
if text_entity then
text_entity.text = text
text_entity.color = color
return
end
end
surface.create_entity{
name = 'flying-text',
color = color,
text = text,
position = position
}.active = false
end
--- Clears all flying text entities on a surface
-- @tparam LuaSurface surface the surface to clear
function Common.clear_flying_text(surface)
local entities = surface.find_entities_filtered{name ='flying-text'}
for _,entity in pairs(entities) do

View File

@@ -1 +1 @@
return require 'expcore.gui.require'
return require 'expcore.gui._require'

131
expcore/gui/_require.lua Normal file
View File

@@ -0,0 +1,131 @@
--[[-- Core Module - Gui
- Used to simplify gui creation using factory functions called element defines
@core Gui
@alias Gui
@usage-- To draw your element you only need to call the factory function
-- You are able to pass any other arguments that are used in your custom functions but the first is always the parent element
local example_button_element = example_button(parent_element)
@usage-- Making a factory function for a button with the caption "Example Button"
-- This method has all the same features as LuaGuiElement.add
local example_button =
Gui.element{
type = 'button',
caption = 'Example Button'
}
@usage-- Making a factory function for a button which is contained within a flow
-- This method is for when you still want to register event handlers but cant use the table method
local example_flow_with_button =
Gui.element(function(event_trigger,parent,...)
-- ... shows that all other arguments from the factory call are passed to this function
-- Here we are adding a flow which we will then later add a button to
local flow =
parent.add{ -- paraent is the element which is passed to the factory function
name = 'example_flow',
type = 'flow'
}
-- Now we add the button to the flow that we created earlier
local element =
flow.add{
name = event_trigger, -- event_trigger should be the name of any elements you want to trigger your event handlers
type = 'button',
caption = 'Example Button'
}
-- You must return a new element, this is so styles can be applied and returned to the caller
-- You may return any of your elements that you added, consider the context in which it will be used for which should be returned
return element
end)
@usage-- Styles can be added to any element define, simplest way mimics LuaGuiElement.style[key] = value
local example_button =
Gui.element{
type = 'button',
caption = 'Example Button',
style = 'forward_button' -- factorio styles can be applied here
}
:style{
height = 25, -- same as element.style.height = 25
width = 100 -- same as element.style.width = 25
}
@usage-- Styles can also have a custom function when the style is dynamic and depends on other factors
-- Use this method if your style is dynamic and depends on other factors
local example_button =
Gui.element{
type = 'button',
caption = 'Example Button',
style = 'forward_button' -- factorio styles can be applied here
}
:style(function(style,element,...)
-- style is the current style object for the elemenent
-- element is the element that is being changed
-- ... shows that all other arguments from the factory call are passed to this function
local player = game.players[element.player_index]
style.height = 25
style.width = 100
style.font_color = player.color
end)
@usage-- You are able to register event handlers to your elements, these can be factorio events or custom ones
-- All events are checked to be valid before raising any handlers, this means element.valid = true and player.valid = true
Gui.element{
type = 'button',
caption = 'Example Button'
}
:on_click(function(player,element,event)
-- player is the player who interacted with the element to cause the event
-- element is a refrence to the element which caused the event
-- event is a raw refrence to the event data if player and element are not enough
player.print('Clicked: '..element.name)
end)
@usage-- Example from core_defines, Gui.core_defines.hide_left_flow, called like: hide_left_flow(parent_element)
--- Button which hides the elements in the left flow, shows inside the left flow when frames are visible
-- @element hide_left_flow
local hide_left_flow =
Gui.element{
type = 'sprite-button',
sprite = 'utility/close_black',
style = 'tool_button',
tooltip = {'expcore-gui.left-button-tooltip'}
}
:style{
padding = -3,
width = 18,
height = 20
}
:on_click(function(player,_,_)
Gui.hide_left_flow(player)
end)
@usage-- Eample from defines, Gui.alignment, called like: Gui.alignment(parent, name, horizontal_align, vertical_align)
-- Notice how _ are used to blank arguments that are not needed in that context and how they line up with above
Gui.alignment =
Gui.element(function(_,parent,name,_,_)
return parent.add{
name = name or 'alignment',
type = 'flow',
}
end)
:style(function(style,_,_,horizontal_align,vertical_align)
style.padding = {1,2}
style.vertical_align = vertical_align or 'center'
style.horizontal_align = horizontal_align or 'right'
style.vertically_stretchable = style.vertical_align ~= 'center'
style.horizontally_stretchable = style.horizontal_align ~= 'center'
end)
]]
local Gui = require 'expcore.gui.prototype'
require 'expcore.gui.core_defines'
require 'expcore.gui.top_flow'
require 'expcore.gui.left_flow'
require 'expcore.gui.helper_functions'
require 'expcore.gui.defines'
return Gui

View File

@@ -4,7 +4,7 @@
]]
local Gui = require 'expcore.gui.prototype'
local Event = require 'utils.event' --- @dep utils.event
local Event = require 'utils.event'
--- Core Defines.
-- @section coreDefines

View File

@@ -4,7 +4,7 @@
]]
local Gui = require 'expcore.gui.prototype'
local mod_gui = require 'mod-gui' --- @dep mod-gui
local mod_gui = require 'mod-gui'
local hide_left_flow = Gui.core_defines.hide_left_flow.name
@@ -82,7 +82,7 @@ end
--[[-- Draw all the left elements onto the left flow, internal use only with on join
@tparam LuaPlayer player the player that you want to draw the elements for
@usage Draw all the left elements
@usage-- Draw all the left elements
Gui.draw_left_flow(player)
]]

View File

@@ -1,152 +1,26 @@
--[[-- Core Module - Gui
- Used to simplify gui creation using factory functions called element defines
@core Gui
@alias Gui
@usage-- To draw your element you only need to call the factory function
-- You are able to pass any other arguments that are used in your custom functions but the first is always the parent element
local example_button_element = example_button(parent_element)
@usage-- Making a factory function for a button with the caption "Example Button"
-- This method has all the same features as LuaGuiElement.add
local example_button =
Gui.element{
type = 'button',
caption = 'Example Button'
}
@usage-- Making a factory function for a button which is contained within a flow
-- This method is for when you still want to register event handlers but cant use the table method
local example_flow_with_button =
Gui.element(function(event_trigger,parent,...)
-- ... shows that all other arguments from the factory call are passed to this function
-- Here we are adding a flow which we will then later add a button to
local flow =
parent.add{ -- paraent is the element which is passed to the factory function
name = 'example_flow',
type = 'flow'
}
-- Now we add the button to the flow that we created earlier
local element =
flow.add{
name = event_trigger, -- event_trigger should be the name of any elements you want to trigger your event handlers
type = 'button',
caption = 'Example Button'
}
-- You must return a new element, this is so styles can be applied and returned to the caller
-- You may return any of your elements that you added, consider the context in which it will be used for which should be returned
return element
end)
@usage-- Styles can be added to any element define, simplest way mimics LuaGuiElement.style[key] = value
local example_button =
Gui.element{
type = 'button',
caption = 'Example Button',
style = 'forward_button' -- factorio styles can be applied here
}
:style{
height = 25, -- same as element.style.height = 25
width = 100 -- same as element.style.width = 25
}
@usage-- Styles can also have a custom function when the style is dynamic and depends on other factors
-- Use this method if your style is dynamic and depends on other factors
local example_button =
Gui.element{
type = 'button',
caption = 'Example Button',
style = 'forward_button' -- factorio styles can be applied here
}
:style(function(style,element,...)
-- style is the current style object for the elemenent
-- element is the element that is being changed
-- ... shows that all other arguments from the factory call are passed to this function
local player = game.players[element.player_index]
style.height = 25
style.width = 100
style.font_color = player.color
end)
@usage-- You are able to register event handlers to your elements, these can be factorio events or custom ones
-- All events are checked to be valid before raising any handlers, this means element.valid = true and player.valid = true
Gui.element{
type = 'button',
caption = 'Example Button'
}
:on_click(function(player,element,event)
-- player is the player who interacted with the element to cause the event
-- element is a refrence to the element which caused the event
-- event is a raw refrence to the event data if player and element are not enough
player.print('Clicked: '..element.name)
end)
@usage-- Example from core_defines, Gui.core_defines.hide_left_flow, called like: hide_left_flow(parent_element)
--- Button which hides the elements in the left flow, shows inside the left flow when frames are visible
-- @element hide_left_flow
local hide_left_flow =
Gui.element{
type = 'sprite-button',
sprite = 'utility/close_black',
style = 'tool_button',
tooltip = {'expcore-gui.left-button-tooltip'}
}
:style{
padding = -3,
width = 18,
height = 20
}
:on_click(function(player,_,_)
Gui.hide_left_flow(player)
end)
@usage-- Eample from defines, Gui.alignment, called like: Gui.alignment(parent, name, horizontal_align, vertical_align)
-- Notice how _ are used to blank arguments that are not needed in that context and how they line up with above
Gui.alignment =
Gui.element(function(_,parent,name,_,_)
return parent.add{
name = name or 'alignment',
type = 'flow',
}
end)
:style(function(style,_,_,horizontal_align,vertical_align)
style.padding = {1,2}
style.vertical_align = vertical_align or 'center'
style.horizontal_align = horizontal_align or 'right'
style.vertically_stretchable = style.vertical_align ~= 'center'
style.horizontally_stretchable = style.horizontal_align ~= 'center'
end)
@module Gui
]]
local Event = require 'utils.event' --- @dep utils.event
local Gui = {
--- The current highest uid that is being used by a define, will not increase during runtime
-- @field uid
uid = 0,
--- String indexed table used to avoid conflict with custom event names, similar to how defines.events works
-- @table events
events = {},
--- Uid indexed array that stores all the factory functions that were defined, no new values will be added during runtime
-- @table defines
defines = {},
--- An string indexed table of all the defines which are used by the core of the gui system, used for internal refrence
-- @table core_defines
core_defines = {},
--- Used to store the file names where elements were defined, this can be useful to find the uid of an element, mostly for debuging
-- @table file_paths
file_paths = {},
--- Used to store extra infomation about elements as they get defined such as the params used and event handlers registered to them
-- @table debug_info
debug_info = {},
--- The prototype used to store the functions of an element define
-- @table _prototype_element
_prototype_element = {},
--- The prototype metatable applied to new element defines
-- @table _mt_element
_mt_element = {
__call = function(self,parent,...)
local element = self._draw(self.name,parent,...)
@@ -365,50 +239,86 @@ end
--- Called when the player opens a GUI.
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_open(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_open = event_handler_factory(defines.events.on_gui_opened)
--- Called when the player closes the GUI they have open.
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_close(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_close = event_handler_factory(defines.events.on_gui_closed)
--- Called when LuaGuiElement is clicked.
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_click(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_click = event_handler_factory(defines.events.on_gui_click)
--- Called when a LuaGuiElement is confirmed, for example by pressing Enter in a textfield.
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_confirmed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_confirmed = event_handler_factory(defines.events.on_gui_confirmed)
--- Called when LuaGuiElement checked state is changed (related to checkboxes and radio buttons).
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_checked_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_checked_changed = event_handler_factory(defines.events.on_gui_checked_state_changed)
--- Called when LuaGuiElement element value is changed (related to choose element buttons).
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_elem_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_elem_changed = event_handler_factory(defines.events.on_gui_elem_changed)
--- Called when LuaGuiElement element location is changed (related to frames in player.gui.screen).
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_location_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_location_changed = event_handler_factory(defines.events.on_gui_location_changed)
--- Called when LuaGuiElement selected tab is changed (related to tabbed-panes).
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_tab_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_tab_changed = event_handler_factory(defines.events.on_gui_selected_tab_changed)
--- Called when LuaGuiElement selection state is changed (related to drop-downs and listboxes).
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_selection_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_selection_changed = event_handler_factory(defines.events.on_gui_selection_state_changed)
--- Called when LuaGuiElement switch state is changed (related to switches).
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_switch_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_switch_changed = event_handler_factory(defines.events.on_gui_switch_state_changed)
--- Called when LuaGuiElement text is changed by the player.
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_text_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_text_changed = event_handler_factory(defines.events.on_gui_text_changed)
--- Called when LuaGuiElement slider value is changed (related to the slider element).
-- @tparam function handler the event handler which will be called
-- @usage element_define:on_value_changed(function(event)
-- event.player.print(table.inspect(event))
--end)
Gui._prototype_element.on_value_changed = event_handler_factory(defines.events.on_gui_value_changed)
-- Module return

View File

@@ -1,8 +0,0 @@
local Gui = require 'expcore.gui.prototype'
require 'expcore.gui.core_defines'
require 'expcore.gui.top_flow'
require 'expcore.gui.left_flow'
require 'expcore.gui.helper_functions'
require 'expcore.gui.defines'
return Gui

View File

@@ -145,7 +145,7 @@ function Gui.toolbar_button(sprite,tooltip,authenticator)
end
--[[-- Styles a top flow button depending on the state given
@tparam LuaGuiElement the button element to style
@tparam LuaGuiElement button the button element to style
@tparam boolean state The state the button is in
@usage-- Sets the button to the visible style

View File

@@ -1,29 +1,25 @@
--[[-- Core Module - Permission Groups
- Permission group making for factorio so you never have to make one by hand again
@core Permissions-Groups
@alias Permissions_Groups
- Permission group making for factorio so you never have to make one by hand again
@core Groups
@alias Permissions_Groups
@usage
---- Example Group (Allow All)
@usage--- Example Group (Allow All)
-- here we will create an admin group however we do not want them to use the map editor or mess with the permission groups
Permission_Groups.new_group('Admin') -- this defines a new group called "Admin"
:allow_all() -- this makes the default to allow any input action unless set other wise
:disallow{ -- here we disallow the input action we don't want them to use
'add_permission_group',
'delete_permission_group',
'import_permissions_string',
'map_editor_action',
'toggle_map_editor'
}
-- here we will create an admin group however we do not want them to use the map editor or mess with the permission groups
Permission_Groups.new_group('Admin') -- this defines a new group called "Admin"
:allow_all() -- this makes the default to allow any input action unless set other wise
:disallow{ -- here we disallow the input action we don't want them to use
'add_permission_group',
'delete_permission_group',
'import_permissions_string',
'map_editor_action',
'toggle_map_editor'
}
@usage
---- Example Group (Disallow All)
-- here we will create a group that cant do anything but talk in chat
Permission_Groups.new_group('Restricted') -- this defines a new group called "Restricted"
:disallow_all() -- this makes the default to disallow any input action unless set other wise
:allow('write_to_console') -- here we allow them to chat, {} can be used here if we had more than one action
@usage--- Example Group (Disallow All)
-- here we will create a group that cant do anything but talk in chat
Permission_Groups.new_group('Restricted') -- this defines a new group called "Restricted"
:disallow_all() -- this makes the default to disallow any input action unless set other wise
:allow('write_to_console') -- here we allow them to chat, {} can be used here if we had more than one action
]]
@@ -55,9 +51,14 @@ Permissions_Groups.async_token_remove_from_permission_group = remove_from_permis
-- Functions that get permission groups
-- @section getters
--- Defines a new permission group that can have it actions set in the config
-- @tparam string name the name of the new group
-- @treturn Permissions_Groups._prototype the new group made with function to allow and disallow actions
--[[-- Defines a new permission group that can have it actions set in the config
@tparam string name the name of the new group
@treturn Permissions_Groups._prototype the new group made with function to allow and disallow actions
@usage-- Defining a new permission group
Groups.new_group('Admin')
]]
function Permissions_Groups.new_group(name)
local group = setmetatable({
name=name,
@@ -70,16 +71,26 @@ function Permissions_Groups.new_group(name)
return group
end
--- Returns the group with the given name, case sensitive
-- @tparam string name the name of the group to get
-- @treturn ?Permissions_Groups._prototype|nil the group with that name or nil if non found
--[[-- Returns the group with the given name, case sensitive
@tparam string name the name of the group to get
@treturn ?Permissions_Groups._prototype|nil the group with that name or nil if non found
@usage-- Getting a permision group
local admin_group = Groups.get_group_by_name('Admin')
]]
function Permissions_Groups.get_group_by_name(name)
return Permissions_Groups.groups[name]
end
--- Returns the group that a player is in
-- @tparam LuaPlayer player the player to get the group of can be name index etc
-- @treturn ?Permissions_Groups._prototype|nil the group with that player or nil if non found
--[[-- Returns the group that a player is in
@tparam LuaPlayer player the player to get the group of can be name index etc
@treturn ?Permissions_Groups._prototype|nil the group with that player or nil if non found
@usage-- Get your permission group
local group = Groups.get_group_from_player(game.player)
]]
function Permissions_Groups.get_group_from_player(player)
player = Game.get_player_from_any(player)
if not player then return end
@@ -93,43 +104,27 @@ end
-- Functions that control all groups
-- @section players
--- Reloads/creates all permission groups and sets them to they configured state
--[[-- Reloads/creates all permission groups and sets them to they configured state
@usage-- Reload the permission groups, used internally
Groups.reload_permissions()
]]
function Permissions_Groups.reload_permissions()
for _,group in pairs(Permissions_Groups.groups) do
group:create()
end
end
--- Removes all permissions from every permission group except for "Default" and any passed as exempt
-- @tparam ?string|Array<string> exempt groups that you want to be except, "Default" is always exempt
-- @treturn number the number of groups that had they permissions removed
function Permissions_Groups.lockdown_permissions(exempt)
local count = 0
if type(exempt) ~= 'table' then
exempt = {exempt}
end
for _,group in pairs(exempt) do
if type(group) == 'string' then
exempt[group:lower()] = true
elseif type(group) == 'table' then
exempt[group.name:lower()] = true
end
end
for _,group in pairs(game.permissions.groups) do
if not exempt[group.name:lower()] and not group.name == 'Default' then
count = count +1
for _,action in pairs(defines.input_action) do
group.set_allows_action(action,false)
end
end
end
return count
end
--[[-- Sets a player's group to the one given, a player can only have one group at a time
@tparam LuaPlayer player the player to effect can be name index etc
@tparam string group the name of the group to give to the player
@treturn boolean true if the player was added successfully, false other wise
--- Sets a player's group to the one given, a player can only have one group at a time
-- @tparam LuaPlayer player the player to effect can be name index etc
-- @tparam string group the name of the group to give to the player
-- @treturn boolean true if the player was added successfully, false other wise
@usage-- Set your permission group
Groups.set_player_group(game.player, 'Admin')
]]
function Permissions_Groups.set_player_group(player,group)
player = Game.get_player_from_any(player)
group = Permissions_Groups.get_group_by_name(group)
@@ -142,10 +137,15 @@ end
-- Functions that control group actions
-- @section actions
--- Sets the allow state of an action for this group, used internally but is safe to use else where
-- @tparam ?string|defines.input_action action the action that you want to set the state of
-- @tparam boolean state the state that you want to set it to, true = allow, false = disallow
-- @treturn Permissions_Groups._prototype returns self so function can be chained
--[[-- Sets the allow state of an action for this group, used internally but is safe to use else where
@tparam ?string|defines.input_action action the action that you want to set the state of
@tparam boolean state the state that you want to set it to, true = allow, false = disallow
@treturn Permissions_Groups._prototype returns self so function can be chained
@usage-- Set an action to be disalowed
group:set_action('toggle_map_editor', false)
]]
function Permissions_Groups._prototype:set_action(action,state)
if type(action) == 'string' then
action = defines.input_action[action]
@@ -154,9 +154,16 @@ function Permissions_Groups._prototype:set_action(action,state)
return self
end
--- Sets an action or actions to be allowed for this group even with disallow_all triggered, Do not use in runtime
-- @tparam string|Array<string> actions the action or actions that you want to allow for this group
-- @treturn Permissions_Groups._prototype returns self so function can be chained
--[[-- Sets an action or actions to be allowed for this group even with disallow_all triggered, Do not use in runtime
@tparam string|Array<string> actions the action or actions that you want to allow for this group
@treturn Permissions_Groups._prototype returns self so function can be chained
@usage-- Allow some actions
group:allow{
'write_to_console'
}
]]
function Permissions_Groups._prototype:allow(actions)
if type(actions) ~= 'table' then
actions = {actions}
@@ -167,9 +174,20 @@ function Permissions_Groups._prototype:allow(actions)
return self
end
--- Sets an action or actions to be disallowed for this group even with allow_all triggered, Do not use in runtime
-- @tparam string|Array<string> actions the action or actions that you want to disallow for this group
-- @treturn Permissions_Groups._prototype returns self so function can be chained
--[[-- Sets an action or actions to be disallowed for this group even with allow_all triggered, Do not use in runtime
@tparam string|Array<string> actions the action or actions that you want to disallow for this group
@treturn Permissions_Groups._prototype returns self so function can be chained
@usage-- Disalow some actions
group:disallow{
'add_permission_group',
'delete_permission_group',
'import_permissions_string',
'map_editor_action',
'toggle_map_editor'
}
]]
function Permissions_Groups._prototype:disallow(actions)
if type(actions) ~= 'table' then
actions = {actions}
@@ -180,23 +198,38 @@ function Permissions_Groups._prototype:disallow(actions)
return self
end
--- Sets the default state for any actions not given to be allowed, useful with :disallow
-- @treturn Permissions_Groups._prototype returns self so function can be chained
--[[-- Sets the default state for any actions not given to be allowed, useful with :disallow
@treturn Permissions_Groups._prototype returns self so function can be chained
@usage-- Allow all actions unless given by disallow
group:allow_all()
]]
function Permissions_Groups._prototype:allow_all()
self.allow_all_actions = true
return self
end
--- Sets the default state for any action not given to be disallowed, useful with :allow
-- @treturn Permissions_Groups._prototype returns self so function can be chained
--[[-- Sets the default state for any action not given to be disallowed, useful with :allow
@treturn Permissions_Groups._prototype returns self so function can be chained
@usage-- Disallow all actions unless given by allow
group:disallow_all()
]]
function Permissions_Groups._prototype:disallow_all()
self.allow_all_actions = false
return self
end
--- Returns if an input action is allowed for this group
-- @tparam ?string|defines.input_action action the action that you want to test for
-- @treturn boolean true if the group is allowed the action, false other wise
--[[-- Returns if an input action is allowed for this group
@tparam ?string|defines.input_action action the action that you want to test for
@treturn boolean true if the group is allowed the action, false other wise
@usage-- Test if a group is allowed an action
local allowed = group:is_allowed('write_to_console')
]]
function Permissions_Groups._prototype:is_allowed(action)
if type(action) == 'string' then
action = defines.input_action[action]
@@ -212,14 +245,13 @@ end
-- Functions that control group players
-- @section players
--- Returns the LuaPermissionGroup that was created with this group object, used internally
-- @treturn LuaPermissionGroup the raw lua permission group
function Permissions_Groups._prototype:get_raw()
return game.permissions.get_group(self.name)
end
--[[-- Creates or updates the permission group with the configured actions, used internally
@treturn LuaPermissionGroup the permission group that was created
--- Creates or updates the permission group with the configured actions, used internally
-- @treturn LuaPermissionGroup the permission group that was created
@usage-- Create the permission group so players can be added, used internally
group:create()
]]
function Permissions_Groups._prototype:create()
local group = self:get_raw()
if not group then
@@ -231,9 +263,25 @@ function Permissions_Groups._prototype:create()
return group
end
--- Adds a player to this group
-- @tparam LuaPlayer player LuaPlayer the player you want to add to this group can be name or index etc
-- @treturn boolean true if the player was added successfully, false other wise
--[[-- Returns the LuaPermissionGroup that was created with this group object, used internally
@treturn LuaPermissionGroup the raw lua permission group
@usage-- Get the factorio api permision group, used internally
local permission_group = group:get_raw()
]]
function Permissions_Groups._prototype:get_raw()
return game.permissions.get_group(self.name)
end
--[[-- Adds a player to this group
@tparam LuaPlayer player LuaPlayer the player you want to add to this group can be name or index etc
@treturn boolean true if the player was added successfully, false other wise
@usage-- Add a player to this permission group
group:add_player(game.player)
]]
function Permissions_Groups._prototype:add_player(player)
player = Game.get_player_from_any(player)
local group = self:get_raw()
@@ -242,9 +290,14 @@ function Permissions_Groups._prototype:add_player(player)
return true
end
--- Removes a player from this group
-- @tparam LuaPlayer player LuaPlayer the player you want to remove from this group can be name or index etc
-- @treturn boolean true if the player was removed successfully, false other wise
--[[-- Removes a player from this group
@tparam LuaPlayer player LuaPlayer the player you want to remove from this group can be name or index etc
@treturn boolean true if the player was removed successfully, false other wise
@usage-- Remove a player from this permission group
group:remove_player(game.player)
]]
function Permissions_Groups._prototype:remove_player(player)
player = Game.get_player_from_any(player)
local group = self:get_raw()
@@ -253,9 +306,17 @@ function Permissions_Groups._prototype:remove_player(player)
return true
end
--- Returns all player that are in this group with the option to filter to online/offline only
-- @tparam[opt] boolean online if nil returns all players, if true online players only, if false returns online players only
-- @treturn table a table of players that are in this group; filtered if online param is given
--[[-- Returns all player that are in this group with the option to filter to online/offline only
@tparam[opt] boolean online if nil returns all players, if true online players only, if false returns online players only
@treturn table a table of players that are in this group; filtered if online param is given
@usage-- Get all players in this group
local online_players = group:get_players()
@usage-- Get all online players in this group
local online_players = group:get_players(true)
]]
function Permissions_Groups._prototype:get_players(online)
local players = {}
local group = self:get_raw()
@@ -273,9 +334,14 @@ function Permissions_Groups._prototype:get_players(online)
return players
end
--- Prints a message to every player in this group
-- @tparam string message the message that you want to send to the players
-- @treturn number the number of players that received the message
--[[-- Prints a message to every player in this group
@tparam string message the message that you want to send to the players
@treturn number the number of players that received the message
@usage-- Print a message to all players in thie group
group:print('Hello, World!')
]]
function Permissions_Groups._prototype:print(message)
local players = self:get_players(true)
for _,player in pairs(players) do

View File

@@ -1,115 +1,111 @@
--[[-- Core Module - Roles
- Factorio role system to manage custom permissions.
@core Roles
@alias Roles
- Factorio role system to manage custom permissions.
@core Roles
@alias Roles
@usage
---- Using Role System (Frontend):
When a map first starts you will want to define on mass all the players you expect to join and the roles to give them:
Roles.override_player_roles{
Cooldude2606 = {'Owner','Admin','Member'},
NotCooldude2606 = {'Member'}
}
@usage--- Using Role System (assignment):
--When a map first starts you will want to define on mass all the players you expect to join and the roles to give them:
Roles.override_player_roles{
Cooldude2606 = {'Owner','Admin','Member'},
NotCooldude2606 = {'Member'}
}
Once the game is running you still want to be able to give role and remove them which is when you would use:
Roles.assign_player(player,'Admin',by_player_name) -- this will give the "Admin" role to the player
Roles.unassign_player(player,{'Admin','Moderator'},by_player_name) -- this will remove "Admin" and "Moderator" role in one go
--Once the game is running you still want to be able to give role and remove them which is when you would use:
Roles.assign_player(player,'Admin',by_player_name) -- this will give the "Admin" role to the player
Roles.unassign_player(player,{'Admin','Moderator'},by_player_name) -- this will remove "Admin" and "Moderator" role in one go
@usage
---- Using Role System (Backend):
To comparer two players you can comparer the index of they highest roles, can be used when you want to allow a "write" down type system:
Roles.get_player_highest_role(playerOne).index < Roles.get_player_highest_role(playerTwo).index -- remember that less means a higher role
@usage--- Using Role System (role testing):
--To comparer two players you can comparer the index of they highest roles, can be used when you want to allow a "write" down type system:
Roles.get_player_highest_role(playerOne).index < Roles.get_player_highest_role(playerTwo).index -- remember that less means a higher role
Listing all of a players roles can also be useful which is when you would want to use:
Roles.get_player_roles(player) -- the return is an array that can be looped over however this is not in particular order
--Listing all of a players roles can also be useful which is when you would want to use:
Roles.get_player_roles(player) -- the return is an array that can be looped over however this is not in particular order
Finally you may want to test if a player has a certain role, flag or action allowed which is when you would use:
Roles.player_has_role(player,'Admin') -- you can provide a role name if you only want a name based system
Roles.player_has_flag(player,'is_donator') -- your roles can be grouped together with flags such as is_donator
Roles.player_allowed(player,'game modifiers') -- or you can have an action based system where each action is something the player can do
--Finally you may want to test if a player has a certain role, flag or action allowed which is when you would use:
Roles.player_has_role(player,'Admin') -- you can provide a role name if you only want a name based system
Roles.player_has_flag(player,'is_donator') -- your roles can be grouped together with flags such as is_donator
Roles.player_allowed(player,'game modifiers') -- or you can have an action based system where each action is something the player can do
@usage
---- Example Flag Define:
Flags can be used to group multiple roles and actions under one catch all, for example if you want a piece of code to only
be active for your donators then you would add a "is_donator" flag to all your donator roles and then in the code test if
a player has that tag present:
@usage--- Example Flag Define:
--Flags can be used to group multiple roles and actions under one catch all, for example if you want a piece of code to only
--be active for your donators then you would add a "is_donator" flag to all your donator roles and then in the code test if
--a player has that tag present:
-- give you donators a speed boost when they join; these functions aren't required but can be useful
Roles.define_flag_trigger('is_donator',function(player,state)
if state then
player.character_running_speed_modifier = 1.5
else
player.character_running_speed_modifier = 1
end
end)
-- then on all your donator roles you would add
Roles.new_role('Donator')
:set_flag('is_donator')
-- and in your code you would test for
if Roles.player_has_flag(player,'is_donator') then
-- some donator only code
-- give you donators a speed boost when they join; these functions aren't required but can be useful
Roles.define_flag_trigger('is_donator',function(player,state)
if state then
player.character_running_speed_modifier = 1.5
else
player.character_running_speed_modifier = 1
end
end)
@usage
---- Example Role Define:
You can't use a role system without any roles so first you must define your roles; each role has a minimum of a name with
the option for a shorthand:
Roles.new_role('Administrator','Admin')
-- then on all your donator roles you would add
Roles.new_role('Donator')
:set_flag('is_donator')
Next you will want to add any extras you want to have, such as a tag, colour, permission group or any custom flags:
Roles.new_role('Administrator','Admin')
:set_custom_tag('[Admin]')
:set_custom_color('red') -- this can be {r=0,g=0,b=0} or a predefined value
:set_permission_group('Staff') -- a second argument can be added if you have not used the custom permission group config
:set_flag('is_admin')
-- and in your code you would test for
if Roles.player_has_flag(player,'is_donator') then
-- some donator only code
end
You will then want to decide if you want to allow all actions, this should of course be used sparely:
Roles.new_role('Administrator','Admin')
...extras...
:set_allow_all()
@usage--- Example Role Define:
--You can't use a role system without any roles so first you must define your roles; each role has a minimum of a name with
--the option for a shorthand:
Roles.new_role('Administrator','Admin')
If you don't do this want this as i would advise you do then you will want to define what the role can do; this comes with
an optional inheritance system if you like those sort of things in which case disallow may also be of some use to you:
Roles.new_role('Administrator','Admin')
...extras...
:set_parent('Moderator') -- the admin can do anything that a moderator can do
:allow{ -- these actions can be anything just try to keep them without conflicts
'command/kill',
'gui/game settings'
}
--Next you will want to add any extras you want to have, such as a tag, colour, permission group or any custom flags:
Roles.new_role('Administrator','Admin')
:set_custom_tag('[Admin]')
:set_custom_color('red') -- this can be {r=0,g=0,b=0} or a predefined value
:set_permission_group('Staff') -- a second argument can be added if you have not used the custom permission group config
:set_flag('is_admin')
Here is what the finished admin role would look like:
Roles.new_role('Administrator','Admin')
:set_custom_tag('[Admin]')
:set_custom_color('red')
:set_permission_group('Staff')
:set_flag('is_admin')
:set_parent('Moderator')
:allow{
'command/kill',
'gui/game settings'
}
--You will then want to decide if you want to allow all actions, this should of course be used sparely:
Roles.new_role('Administrator','Admin')
...extras...
:set_allow_all()
@usage
---- Example System Define:
Once all roles are defined these steps must be done to ensure the system is ready to use, this includes setting a default
role, assigning a root (all permission) role that the server/system will use and the linear order that the roles fall into:
--If you don't do this want this as i would advise you do then you will want to define what the role can do; this comes with
--an optional inheritance system if you like those sort of things in which case disallow may also be of some use to you:
Roles.new_role('Administrator','Admin')
...extras...
:set_parent('Moderator') -- the admin can do anything that a moderator can do
:allow{ -- these actions can be anything just try to keep them without conflicts
'command/kill',
'gui/game settings'
}
Roles.set_default('Guest')
Roles.set_root('System')
--Here is what the finished admin role would look like:
Roles.new_role('Administrator','Admin')
:set_custom_tag('[Admin]')
:set_custom_color('red')
:set_permission_group('Staff')
:set_flag('is_admin')
:set_parent('Moderator')
:allow{
'command/kill',
'gui/game settings'
}
Roles.define_role_order{
'System',
'Administrator',
'Moderator',
'Donator',
'Guest'
}
@usage--- Example System Define:
--Once all roles are defined these steps must be done to ensure the system is ready to use, this includes setting a default
--role, assigning a root (all permission) role that the server/system will use and the linear order that the roles fall into:
Roles.set_default('Guest')
Roles.set_root('System')
Roles.define_role_order{
'System',
'Administrator',
'Moderator',
'Donator',
'Guest'
}
--Just remember that in this example all these roles have not been defined; so make sure all your roles that are used are defined
--before hand; a config file on load is useful for this to ensure that its loaded before the first player even joins.
Just remember that in this example all these roles have not been defined; so make sure all your roles that are used are defined
before hand; a config file on load is useful for this to ensure that its loaded before the first player even joins.
]]
local Game = require 'utils.game' --- @dep utils.game
@@ -196,8 +192,13 @@ local function emit_player_roles_updated(player,type,roles,by_player_name,skip_g
})
end
--- Returns a string which contains all roles in index order displaying all data for them
-- @treturn string the debug output string
--[[-- Returns a string which contains all roles in index order displaying all data for them
@treturn string the debug output string
@usage-- Print the debug string
game.player.print(Roles.debug())
]]
function Roles.debug()
local output = ''
for index,role_name in pairs(Roles.config.order) do
@@ -209,9 +210,14 @@ function Roles.debug()
return output
end
--- Prints a message to all players in the given roles, may send duplicate message however factorio blocks spam
-- @tparam table roles table a of roles which to send the message to
-- @tparam string message the message to send to the players
--[[-- Prints a message to all players in the given roles, may send duplicate message however factorio blocks spam
@tparam table roles table a of roles which to send the message to
@tparam string message the message to send to the players
@usage-- Print a message to the given roles
Roles.print_to_roles({'Administrator','Moderator'}, 'Hello, World!')
]]
function Roles.print_to_roles(roles,message)
for _,role in pairs(roles) do
role = Roles.get_role_from_any(role)
@@ -219,9 +225,14 @@ function Roles.print_to_roles(roles,message)
end
end
--- Prints a message to all players who have the given role or one which is higher (excluding default)
-- @tparam string role the name of the role to send the message to
-- @tparam string message the message to send to the players
--[[-- Prints a message to all players who have the given role or one which is higher (excluding default)
@tparam string role the name of the role to send the message to
@tparam string message the message to send to the players
@usage-- Print a message to the roles above this role, includes the given role
Roles.print_to_roles_higher('Moderator', 'Hello, World!')
]]
function Roles.print_to_roles_higher(role,message)
role = Roles.get_role_from_any(role)
if not role then return end
@@ -234,9 +245,14 @@ function Roles.print_to_roles_higher(role,message)
Roles.print_to_roles(roles,message)
end
--- Prints a message to all players who have the given role or one which is lower (excluding default)
-- @tparam string role the name of the role to send the message to
-- @tparam string message the message to send to the players
--[[-- Prints a message to all players who have the given role or one which is lower (excluding default)
@tparam string role the name of the role to send the message to
@tparam string message the message to send to the players
@usage-- Print a message to the roles below this role, includes the given role
Roles.print_to_roles_higher('Moderator', 'Hello, World!')
]]
function Roles.print_to_roles_lower(role,message)
role = Roles.get_role_from_any(role)
if not role then return end
@@ -249,25 +265,40 @@ function Roles.print_to_roles_lower(role,message)
Roles.print_to_roles(roles,message)
end
--- Get a role for the given name
-- @tparam string name the name of the role to get
-- @treturn Roles._prototype the role with that name or nil
--[[-- Get a role for the given name
@tparam string name the name of the role to get
@treturn Roles._prototype the role with that name or nil
@usage-- Get a role by its name
local role = Roles.get_role_by_name('Moderator')
]]
function Roles.get_role_by_name(name)
return Roles.config.roles[name]
end
--- Get a role with the given order index
-- @tparam number index the place in the order list of the role to get
-- @treturn Roles._prototype the role with that index in the order list or nil
--[[-- Get a role with the given order index
@tparam number index the place in the order list of the role to get
@treturn Roles._prototype the role with that index in the order list or nil
@usage-- Get a role by its index in the order list
local role = Roles.get_role_by_name(2)
]]
function Roles.get_role_by_order(index)
local name = Roles.config.order[index]
return Roles.config.roles[name]
end
--- Gets a role from a name,index or role object (where it is just returned)
-- nb: this function is used for the input for most outward facing functions
-- @tparam ?number|string|table any the value used to find the role
-- @treturn Roles._prototype the role that was found or nil see above
--[[-- Gets a role from a name,index or role object (where it is just returned)
nb: this function is used for the input for most outward facing functions
@tparam ?number|string|table any the value used to find the role
@treturn Roles._prototype the role that was found or nil see above
@usage-- Get a role by its name or order
local role = Roles.get_role_from_any('Moderator')
]]
function Roles.get_role_from_any(any)
local t_any = type(any)
if t_any == 'number' or tonumber(any) then
@@ -280,9 +311,14 @@ function Roles.get_role_from_any(any)
end
end
--- Gets all the roles of the given player, this will always contain the default role
-- @tparam LuaPlayer player the player to get the roles of
-- @treturn table a table where the values are the roles which the player has
--[[-- Gets all the roles of the given player, this will always contain the default role
@tparam LuaPlayer player the player to get the roles of
@treturn table a table where the values are the roles which the player has
@usage-- Get the roles that a player has
local roles = Roles.get_player_roles(game.player)
]]
function Roles.get_player_roles(player)
player = Game.get_player_from_any(player)
if not player then return {Roles.config.roles[Roles.config.internal.root]} end
@@ -295,9 +331,14 @@ function Roles.get_player_roles(player)
return rtn
end
--- Gets the highest role which the player has, can be used to compeer one player to another
-- @tparam LuaPlayer player the player to get the highest role of
-- @treturn the role with the highest order index which this player has
--[[-- Gets the highest role which the player has, can be used to compeer one player to another
@tparam LuaPlayer player the player to get the highest role of
@treturn the role with the highest order index which this player has
@usage-- Get the highest role that a player has
local role = Roles.get_player_highest_role(game.player)
]]
function Roles.get_player_highest_role(player)
local roles = Roles.get_player_roles(player)
if not roles then return end
@@ -314,12 +355,20 @@ end
-- Functions for changing player's roles
-- @section assinment
--- Gives a player the given role(s) with an option to pass a by player name used in the log
-- @tparam LuaPlayer player the player that will be assigned the roles
-- @tparam table roles table a of roles that the player will be given, can be one role and can be role names
-- @tparam[opt=<server>] string by_player_name the name of the player that will be shown in the log
-- @tparam[opt=false] boolean skip_checks when true there will be no checks are done for if the player is valid
-- @tparam[opt=false] boolean silent when true there will be no game message printed
--[[-- Gives a player the given role(s) with an option to pass a by player name used in the log
@tparam LuaPlayer player the player that will be assigned the roles
@tparam table roles table a of roles that the player will be given, can be one role and can be role names
@tparam[opt=<server>] string by_player_name the name of the player that will be shown in the log
@tparam[opt=false] boolean skip_checks when true there will be no checks are done for if the player is valid
@tparam[opt=false] boolean silent when true there will be no game message printed
@usage-- Assign a player to the Moderator role
Roles.assign_player(game.player, 'Moderator')
@usage-- Assign a player to the Moderator role, even if the player has never been on the map
Roles.assign_player('Cooldude2606', 'Moderator', nil, true)
]]
function Roles.assign_player(player,roles,by_player_name,skip_checks,silent)
local valid_player = Game.get_player_from_any(player)
if not skip_checks and not valid_player then return end
@@ -337,12 +386,20 @@ function Roles.assign_player(player,roles,by_player_name,skip_checks,silent)
end
end
--- Removes a player from the given role(s) with an option to pass a by player name used in the log
-- @tparam LuaPlayer player the player that will have the roles removed
-- @tparam table roles table a of roles to be removed from the player, can be one role and can be role names
-- @tparam[opt=<server>] string by_player_name the name of the player that will be shown in the logs
-- @tparam[opt=false] boolean skip_checks when true there will be no checks are done for if the player is valid
-- @tparam[opt=false] boolean silent when true there will be no game message printed
--[[-- Removes a player from the given role(s) with an option to pass a by player name used in the log
@tparam LuaPlayer player the player that will have the roles removed
@tparam table roles table a of roles to be removed from the player, can be one role and can be role names
@tparam[opt=<server>] string by_player_name the name of the player that will be shown in the logs
@tparam[opt=false] boolean skip_checks when true there will be no checks are done for if the player is valid
@tparam[opt=false] boolean silent when true there will be no game message printed
@usage-- Unassign a player from the Moderator role
Roles.unassign_player(game.player, 'Moderator')
@usage-- Unassign a player from the Moderator role, even if the player has never been on the map
Roles.unassign_player('Cooldude2606', 'Moderator', nil, true)
]]
function Roles.unassign_player(player,roles,by_player_name,skip_checks,silent)
local valid_player = Game.get_player_from_any(player)
if not skip_checks and not valid_player then return end
@@ -361,20 +418,41 @@ function Roles.unassign_player(player,roles,by_player_name,skip_checks,silent)
end
end
--- Overrides all player roles with the given table of roles, useful to mass set roles on game start
-- @tparam table roles table a which is indexed by case sensitive player names and has the value of a table of role names
function Roles.override_player_roles(roles)
Roles.config.players = roles
--[[-- Overrides all player roles with the given table of roles, useful to mass set roles on game start
@tparam[opt] string player_name the player to set the roles for, if not given all roles are overriden
@tparam table roles table a which is indexed by case sensitive player names and has the value of a table of role names
@usage-- Override the roles of a single player, other users are not effected
Roles.override_player_roles('Cooldude2606', {'Moderator'})
@usage-- Override all existing roles, effects all users not just ones listed
Roles.override_player_roles{
['Cooldude2606'] = {'Administrator','Moderator'},
['arty714'] = {'Administrator','Moderator'},
}
]]
function Roles.override_player_roles(player_name,roles)
if not roles then
Roles.config.players = player_name
else
Roles.config.players[player_name] = roles
end
end
--- Checks.
-- Functions for checking player's roles
-- @section checks
--- A test for weather a player has the given role
-- @tparam LuaPlayer player the player to test the roles of
-- @tparam ?string|number|table search_role a pointer to the role that is being searched for
-- @treturn boolean true if the player has the role, false otherwise, nil for errors
--[[-- A test for weather a player has the given role
@tparam LuaPlayer player the player to test the roles of
@tparam ?string|number|table search_role a pointer to the role that is being searched for
@treturn boolean true if the player has the role, false otherwise, nil for errors
@usage-- Test if a player has a role
local has_role = Roles.player_has_role(game.player, 'Moderator')
]]
function Roles.player_has_role(player,search_role)
local roles = Roles.get_player_roles(player)
if not roles then return end
@@ -386,10 +464,15 @@ function Roles.player_has_role(player,search_role)
return false
end
--- A test for weather a player has the given flag true for at least one of they roles
-- @tparam LuaPlayer player the player to test the roles of
-- @tparam string flag_name the name of the flag that is being looked for
-- @treturn boolean true if the player has at least one role which has the flag set to true, false otherwise, nil for errors
--[[-- A test for weather a player has the given flag true for at least one of they roles
@tparam LuaPlayer player the player to test the roles of
@tparam string flag_name the name of the flag that is being looked for
@treturn boolean true if the player has at least one role which has the flag set to true, false otherwise, nil for errors
@usage-- Test if a player has a role
local has_flag = Roles.player_has_flag(game.player, 'is_donator')
]]
function Roles.player_has_flag(player,flag_name)
local roles = Roles.get_player_roles(player)
if not roles then return end
@@ -401,10 +484,15 @@ function Roles.player_has_flag(player,flag_name)
return false
end
--- A test for weather a player has at least one role which is allowed the given action
-- @tparam LuaPlayer player the player to test the roles of
-- @tparam string action the name of the action that is being tested for
-- @treturn boolean true if the player has at least one role which is allowed this action, false otherwise, nil for errors
--[[-- A test for weather a player has at least one role which is allowed the given action
@tparam LuaPlayer player the player to test the roles of
@tparam string action the name of the action that is being tested for
@treturn boolean true if the player has at least one role which is allowed this action, false otherwise, nil for errors
@usage-- Test if a player has a role
local has_flag = Roles.player_has_flag(game.player, 'is_donator')
]]
function Roles.player_allowed(player,action)
local roles = Roles.get_player_roles(player)
if not roles then return end
@@ -420,9 +508,20 @@ end
-- Functions which are used to define roles
-- @section checks
--- Used to set the role order, higher in the list is better, must be called at least once in config
--[[-- Used to set the role order, higher in the list is better, must be called at least once in config
-- nb: function also re links parents due to expected position in the config file
-- @tparam table order table a which is keyed only by numbers (start 1) and values are roles in order with highest first
@tparam table order table a which is keyed only by numbers (start 1) and values are roles in order with highest first
@usage-- Define which roles are higher than others
Roles.define_role_order{
'System',
'Administrator',
'Moderator',
'Donator',
'Guest'
}
]]
function Roles.define_role_order(order)
-- Clears and then rebuilds the order table
_C.error_if_runtime()
@@ -457,26 +556,41 @@ function Roles.define_role_order(order)
end
end
--- Defines a new trigger for when a tag is added or removed from a player
-- @tparam string name the name of the flag which the roles will have
-- @tparam function callback the function that is called when roles are assigned
-- flag param - player - the player that has had they roles changed
-- flag param - state - the state of the flag, aka if the flag is present
--[[-- Defines a new trigger for when a tag is added or removed from a player
@tparam string name the name of the flag which the roles will have
@tparam function callback the function that is called when roles are assigned
@usage-- Defineing a flag trigger
Roles.define_flag_trigger('is_donator', function(player, state)
player.character_running_speed_modifier = state and 1.5 or 1
end)
]]
function Roles.define_flag_trigger(name,callback)
_C.error_if_runtime()
Roles.config.flags[name] = Async.register(callback)
end
--- Sets the default role which every player will have, this needs to be called at least once
-- @tparam string name the name of the default role
--[[-- Sets the default role which every player will have, this needs to be called at least once
@tparam string name the name of the default role
@usage-- Setting the default role
Roles.set_default('Guest')
]]
function Roles.set_default(name)
local role = Roles.config.roles[name]
if not role then return end
Roles.config.internal.default = name
end
--- Sets the root role which will always have all permissions, any server actions act from this role
-- @tparam string name the name of the root role
--[[-- Sets the root role which will always have all permissions, any server actions act from this role
@tparam string name the name of the root role
@usage-- Setting the root role
Roles.set_root('System')
]]
function Roles.set_root(name)
local role = Roles.config.roles[name]
if not role then return end
@@ -484,10 +598,15 @@ function Roles.set_root(name)
Roles.config.internal.root = name
end
--- Defines a new role and returns the prototype to allow configuration
-- @tparam string name the name of the new role, must be unique
-- @tparam[opt=name] string short_hand the shortened version of the name
-- @treturn Roles._prototype the start of the config chain for this role
--[[-- Defines a new role and returns the prototype to allow configuration
@tparam string name the name of the new role, must be unique
@tparam[opt=name] string short_hand the shortened version of the name
@treturn Roles._prototype the start of the config chain for this role
@usage-- Defineing a new role
local role = Roles.new_role('Moderator', 'Mod')
]]
function Roles.new_role(name,short_hand)
_C.error_if_runtime()
if Roles.config.roles[name] then return error('Role name is non unique') end
@@ -506,18 +625,31 @@ end
-- Functions for using the role action system
-- @section actions
--- Sets the default allow state of the role, true will allow all actions
-- @tparam[opt=true] boolean state true will allow all actions
-- @treturn Roles._prototype allows chaining
--[[-- Sets the default allow state of the role, true will allow all actions
@tparam[opt=true] boolean state true will allow all actions
@treturn Roles._prototype allows chaining
@usage-- Allow all actions for this role, useful for root like roles
role:set_allow_all()
]]
function Roles._prototype:set_allow_all(state)
if state == nil then state = true end
self.allow_all_actions = not not state -- not not forces a boolean value
return self
end
--- Sets the allow actions for this role, actions in this list will be allowed for this role
-- @tparam table actions indexed with numbers and is an array of action names, order has no effect
-- @treturn Roles._prototype allows chaining
--[[-- Sets the allow actions for this role, actions in this list will be allowed for this role
@tparam table actions indexed with numbers and is an array of action names, order has no effect
@treturn Roles._prototype allows chaining
@usage-- Allow some actions for a role
role:allow{
'command/kill',
'gui/game settings'
}
]]
function Roles._prototype:allow(actions)
if type(actions) ~= 'table' then
actions = {actions}
@@ -528,9 +660,17 @@ function Roles._prototype:allow(actions)
return self
end
--- Sets the disallow actions for this role, will prevent actions from being allowed regardless of inheritance
-- @tparam table actions indexed with numbers and is an array of action names, order has no effect
-- @treturn Roles._prototype allows chaining
--[[-- Sets the disallow actions for this role, will prevent actions from being allowed regardless of inheritance
@tparam table actions indexed with numbers and is an array of action names, order has no effect
@treturn Roles._prototype allows chaining
@usage-- Disalow an action for a role, useful if inherit an action from a parent
role:disallow{
'command/kill',
'gui/game settings'
}
]]
function Roles._prototype:disallow(actions)
if type(actions) ~= 'table' then
actions = {actions}
@@ -541,9 +681,14 @@ function Roles._prototype:disallow(actions)
return self
end
--- Test for if a role is allowed the given action, mostly internal see Roles.player_allowed
-- @tparam string action the name of the action to test if it is allowed
-- @treturn boolean true if action is allowed, false otherwise
--[[-- Test for if a role is allowed the given action, mostly internal see Roles.player_allowed
@tparam string action the name of the action to test if it is allowed
@treturn boolean true if action is allowed, false otherwise
@usage-- Test if a role is allowed an action
local allowed = role:is_allowed('command/kill')
]]
function Roles._prototype:is_allowed(action)
local is_root = Roles.config.internal.root.name == self.name
return self.allowed_actions[action] or self.allow_all_actions or is_root
@@ -553,26 +698,41 @@ end
-- Functions for using the role flag system
-- @section flags
--- Sets the state of a flag for a role, flags can be used to apply effects to players
-- @tparam string name the name of the flag to set the value of
-- @tparam[opt=true] boolean value the state to set the flag to
-- @treturn Roles._prototype allows chaining
--[[-- Sets the state of a flag for a role, flags can be used to apply effects to players
@tparam string name the name of the flag to set the value of
@tparam[opt=true] boolean value the state to set the flag to
@treturn Roles._prototype allows chaining
@usage-- Set a flag for a role
role:set_flag('is_admin')
]]
function Roles._prototype:set_flag(name,value)
if value == nil then value = true end
self.flags[name] = not not value -- not not forces a boolean value
return self
end
--- Clears all flags from this role, individual flags can be removed with set_flag(name,false)
-- @treturn Roles._prototype allows chaining
--[[-- Clears all flags from this role, individual flags can be removed with set_flag(name,false)
@treturn Roles._prototype allows chaining
@usage-- Remove all flags from a role
role:clear_flags()
]]
function Roles._prototype:clear_flags()
self.flags = {}
return self
end
--- A test for if the role has a flag set
-- @tparam string name the name of the flag to test for
-- @treturn boolean true if the flag is set, false otherwise
--[[-- A test for if the role has a flag set
@tparam string name the name of the flag to test for
@treturn boolean true if the flag is set, false otherwise
@usage-- Test if a role has a flag
local has_flag = role:has_flag('is_admin')
]]
function Roles._prototype:has_flag(name)
return self.flags[name] or false
end
@@ -581,17 +741,27 @@ end
-- Functions for chaning other proerties
-- @section properties
--- Sets a custom player tag for the role, can be accessed by other code
-- @tparam string tag the value that the tag will be
-- @treturn Roles._prototype allows chaining
--[[-- Sets a custom player tag for the role, can be accessed by other code
@tparam string tag the value that the tag will be
@treturn Roles._prototype allows chaining
@usage-- Set a custom tag for this role, other code is required to set the tag
role:set_custom_tag('Mod')
]]
function Roles._prototype:set_custom_tag(tag)
self.custom_tag = tag
return self
end
--- Sets a custom colour for the role, can be accessed by other code
-- @tparam table color ?string|table can either be and rgb colour or the name of a colour defined in the presets
-- @treturn Roles._prototype allows chaining
--[[-- Sets a custom colour for the role, can be accessed by other code
@tparam table color ?string|table can either be and rgb colour or the name of a colour defined in the presets
@treturn Roles._prototype allows chaining
@usage-- Set a custom colour for this role, other code is required to use this value
role:set_custom_color{ r=255, g=100, b=100}
]]
function Roles._prototype:set_custom_color(color)
if type(color) ~= 'table' then
color = Colours[color]
@@ -600,10 +770,15 @@ function Roles._prototype:set_custom_color(color)
return self
end
--- Sets the permission group for this role, players will be moved to the group of they highest role
-- @tparam string name the name of the permission group to have players moved to
-- @tparam[opt=false] boolean use_factorio_api when true the custom permission group module is ignored
-- @treturn Roles._prototype allows chaining
--[[-- Sets the permission group for this role, players will be moved to the group of they highest role
@tparam string name the name of the permission group to have players moved to
@tparam[opt=false] boolean use_factorio_api when true the custom permission group module is ignored
@treturn Roles._prototype allows chaining
@usage-- Set the permission group for this role, see permission_groups.lua
role:set_permission_group('Admin')
]]
function Roles._prototype:set_permission_group(name,use_factorio_api)
_C.error_if_runtime()
if use_factorio_api then
@@ -616,10 +791,15 @@ function Roles._prototype:set_permission_group(name,use_factorio_api)
return self
end
--- Sets the parent for a role, any action not in allow or disallow will be looked for in its parents
-- nb: this is a recursive action, and changing the allows and disallows will effect all children roles
-- @tparam string role the name of the role that will be the parent; has imminent effect if role is already defined
-- @treturn Roles._prototype allows chaining
--[[-- Sets the parent for a role, any action not in allow or disallow will be looked for in its parents
nb: this is a recursive action, and changing the allows and disallows will effect all children roles
@tparam string role the name of the role that will be the parent; has imminent effect if role is already defined
@treturn Roles._prototype allows chaining
@usage-- Set the parent for this role to inherit all actions allowed
role:set_parent('Guest')
]]
function Roles._prototype:set_parent(role)
_C.error_if_runtime()
self.parent = role
@@ -629,19 +809,31 @@ function Roles._prototype:set_parent(role)
return self
end
--- Sets an auto promote condition that is checked every 5 seconds, if true is returned then the player will receive the role
-- nb: this is one way, failing false after already gaining the role will not revoke the role
-- @tparam function callback receives only one param which is player to promote, return true to promote the player
-- @treturn Roles._prototype allows chaining
function Roles._prototype:set_auto_promote_condition(callback)
--[[-- Sets an auto assign condition that is checked every 60 seconds, if true is returned then the player will receive the role
nb: this is one way, failing false after already gaining the role will not revoke the role
@tparam function callback receives only one param which is player to promote, return true to promote the player
@treturn Roles._prototype allows chaining
@usage-- Give this role to a user if there are admin, ran every 60 seconds
role:set_auto_assign_condition(function(player)
return player.admin
end)
]]
function Roles._prototype:set_auto_assign_condition(callback)
_C.error_if_runetime_closure(callback)
self.auto_promote_condition = callback
return self
end
--- Sets the role to not allow players to have auto promote effect them, useful to keep people locked to a punishment
-- @tparam[opt=true] boolean state when true the players with this role will not be auto promoted
-- @treturn Roles._prototype allows chaining
--[[-- Sets the role to not allow players to have auto assign effect them, useful to keep people locked to a role
@tparam[opt=true] boolean state when true the players with this role will not be auto assigned to other roles
@treturn Roles._prototype allows chaining
@usage-- Make a role stop players from being auto assigned to other roles
role:set_block_auto_promote()
]]
function Roles._prototype:set_block_auto_promote(state)
if state == nil then state = true end
self.block_auto_promote = not not state -- forces a boolean value
@@ -652,11 +844,16 @@ end
-- Functions that control players in a role
-- @section players
--- Adds a player to this role, players can have more than one role at a time, used internally see Roles.assign
-- @tparam LuaPlayer player the player that will be given this role
-- @tparam boolean skip_check when true player will be taken as the player name (use when player has not yet joined)
-- @tparam boolean skip_event when true the event emit will be skipped, this is used internally with Roles.assign
-- @treturn boolean true if the player was added successfully
--[[-- Adds a player to this role, players can have more than one role at a time, used internally see Roles.assign
@tparam LuaPlayer player the player that will be given this role
@tparam boolean skip_check when true player will be taken as the player name (use when player has not yet joined)
@tparam boolean skip_event when true the event emit will be skipped, this is used internally with Roles.assign
@treturn boolean true if the player was added successfully
@usage-- Assign a player to this role
role:add_player(game.player)
]]
function Roles._prototype:add_player(player,skip_check,skip_event)
player = Game.get_player_from_any(player)
-- Default role cant have players added or removed
@@ -686,11 +883,16 @@ function Roles._prototype:add_player(player,skip_check,skip_event)
return true
end
--- Removes a player from this role, players can have more than one role at a time, used internally see Roles.unassign
-- @tparam LuaPlayer player the player that will lose this role
-- @tparam boolean skip_check when true player will be taken as the player name (use when player has not yet joined)
-- @tparam boolean skip_event when true the event emit will be skipped, this is used internally with Roles.unassign
-- @treturn boolean true if the player was removed successfully
--[[-- Removes a player from this role, players can have more than one role at a time, used internally see Roles.unassign
@tparam LuaPlayer player the player that will lose this role
@tparam boolean skip_check when true player will be taken as the player name (use when player has not yet joined)
@tparam boolean skip_event when true the event emit will be skipped, this is used internally with Roles.unassign
@treturn boolean true if the player was removed successfully
@usage-- Unassign a player from this role
role:remove_player(game.player)
]]
function Roles._prototype:remove_player(player,skip_check,skip_event)
player = Game.get_player_from_any(player)
-- Default role cant have players added or removed
@@ -725,9 +927,17 @@ function Roles._prototype:remove_player(player,skip_check,skip_event)
return rtn
end
--- Returns an array of all the players who have this role, can be filtered by online status
-- @tparam[opt=nil] boolean online when given will filter by this online state, nil will return all players
-- @treturn table all the players who have this role, indexed order is meaningless
--[[-- Returns an array of all the players who have this role, can be filtered by online status
@tparam[opt=nil] boolean online when given will filter by this online state, nil will return all players
@treturn table all the players who have this role, indexed order is meaningless
@usage-- Get all the players with this role
local players = role:get_players()
@usage-- Get all online players with this role
local players = role:get_players(true)
]]
function Roles._prototype:get_players(online)
local players = {}
-- Gets all players that have this role
@@ -756,9 +966,14 @@ function Roles._prototype:get_players(online)
end
end
--- Will print a message to all players with this role
-- @tparam string message the message that will be printed to the players
-- @treturn number the number of players who received the message
--[[-- Will print a message to all players with this role
@tparam string message the message that will be printed to the players
@treturn number the number of players who received the message
@usage-- Print a message to all players with this role
role:print('Hello, World!')
]]
function Roles._prototype:print(message)
local players = self:get_players(true)
for _,player in pairs(players) do