diff --git a/expcore/permission_groups.lua b/expcore/permission_groups.lua index 2d667db9..657ae2ad 100644 --- a/expcore/permission_groups.lua +++ b/expcore/permission_groups.lua @@ -51,6 +51,7 @@ local Game = require 'utils.game' local Event = require 'utils.event' +local Sudo = require 'expcore.sudo' local Permissions_Groups = { groups={}, -- store for the different groups that are created @@ -130,7 +131,7 @@ end -- @treturn boolean true if the player was added successfully, false other wise function Permissions_Groups.set_player_group(player,group) player = Game.get_player_from_any(player) - local group = Permissions_Groups.get_group_by_name(group) + group = Permissions_Groups.get_group_by_name(group) if not group or not player then return false end group:add_player(player) return true @@ -228,7 +229,7 @@ function Permissions_Groups._prototype:add_player(player) player = Game.get_player_from_any(player) local group = self:get_raw() if not group or not player then return false end - group.add_player(player) + Sudo('add-player-to-permission-group',group,player) return true end @@ -239,7 +240,7 @@ function Permissions_Groups._prototype:remove_player(player) player = Game.get_player_from_any(player) local group = self:get_raw() if not group or not player then return false end - group.remove_player(player) + Sudo('remove-player-from-permission-group',group,player) return true end @@ -279,4 +280,11 @@ Event.on_init(function() Permissions_Groups.reload_permissions() end) +Sudo.register('add-player-to-permission-group',function(permission_group,player) + permission_group.add_player(player) +end) +Sudo.register('remove-player-from-permission-group',function(permission_group,player) + permission_group.remove_player(player) +end) + return Permissions_Groups \ No newline at end of file diff --git a/expcore/roles.lua b/expcore/roles.lua index 71944007..3a5c3b7b 100644 --- a/expcore/roles.lua +++ b/expcore/roles.lua @@ -158,6 +158,7 @@ local Game = require 'utils.game' local Global = require 'utils.global' local Event = require 'utils.event' local Groups = require 'expcore.permission_groups' +local Sudo = require 'expcore.sudo' local Colours = require 'resources.color_presets' local write_json = ext_require('expcore.common','write_json') @@ -466,7 +467,9 @@ end -- 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 function Roles.define_flag_trigger(name,callback) - Roles.config.flags[name] = callback -- this can desync if there are upvalues + local sudo_name = 'role-flag-'..name + Roles.config.flags[name] = sudo_name + Sudo.register(sudo_name,callback) end --- Sets the default role which every player will have, this needs to be called at least once @@ -753,12 +756,9 @@ end local function role_update(event) local player = Game.get_player_by_index(event.player_index) -- Updates flags given to the player - for flag,callback in pairs(Roles.config.flags) do + for flag,sudo_name in pairs(Roles.config.flags) do local state = Roles.player_has_flag(player,flag) - local success,err = pcall(callback,player,state) - if not success then - log{'expcore-roles.error-log-format-flag',flag,err} - end + Sudo(sudo_name,player,state) end -- Updates the players permission group local highest = Roles.get_player_highest_role(player) @@ -766,7 +766,7 @@ local function role_update(event) if highest.permission_group[1] then local group = game.permissions.get_group(highest.permission_group[2]) if group then - group.add_player(player) + Sudo('add-player-to-permission-group',group,player) end else Groups.set_player_group(player,highest.permission_group) diff --git a/expcore/sudo.lua b/expcore/sudo.lua new file mode 100644 index 00000000..2b49f6da --- /dev/null +++ b/expcore/sudo.lua @@ -0,0 +1,78 @@ +--- An extention of task and token to allow a single require to register and run functions bypassing all permissions +--[[ +>>>> Usage + To use sudo 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 + + -- this will be blocked if the current player (from a command or gui) is not admin + local function make_admin(player) + player.admin = true + end + + -- here we give sudo access to the function under the name "make-admin" + Sudo.register('make-admin',make_admin) + + -- this will allow us to bypass this by runing one tick later outside of any player scope + Sudo.run('make-admin',game.player) + +>>>> Functions + Sudo.register(name,callback) --- Registers a new callback under the given name, used to avoid desynces + Sudo.get(name) --- Gets the function that is registered under the given name + Sudo.run(name,...) --- Runs the function that is registered under the given name, you may supply any number of params as needed +]] +local Task = require 'utils.task' +local Token = require 'utils.token' + +local Sudo = { + tokens={} +} + +local internal_run = +Token.register(function(params) + local func = Token.get(params.token) + func(unpack(params.params)) +end) + +--- Registers a new callback under the given name, used to avoid desynces +-- @tparam string name the name that will be used to call this function +-- @tparam function callback the function that will be called by this name +function Sudo.register(name,callback) + if _LIFECYCLE == 8 then + error('Calling Sudo.register after on_init() or on_load() has run is a desync risk.', 2) + end + + if Sudo.tokens[name] then + error(name..' is already registered',2) + end + + Sudo.tokens[name] = Token.register(callback) +end + +--- Gets the function that is registered under the given name +-- @tparam string name the name of the function you want to get +function Sudo.get(name) + local token = Sudo.tokens[name] + return token and Token.get(token) +end + +--- Runs the function that is registered under the given name, you may supply any number of params as needed +-- @tparam name string the name of the function you want to run +-- @tparam[opt] any ... the other params that you want to pass to your function +function Sudo.run(name,...) + local token = Sudo.tokens[name] + + if not token then + error('Sudo does not have access to run "'..tostring(name)..'" please make sure it is registered to sudo',2) + end + + Task.set_timeout_in_ticks(1, internal_run, { + token = token, + params = {...} + }) +end + +return setmetatable(Sudo,{ + __call = function(self,...) + self.run(...) + end +}) \ No newline at end of file diff --git a/modules/commands/interface.lua b/modules/commands/interface.lua index 217ff43f..1f0eae0a 100644 --- a/modules/commands/interface.lua +++ b/modules/commands/interface.lua @@ -11,7 +11,8 @@ local interface_modules = { ['Group']='expcore.permission_groups', ['Roles']='expcore.roles', ['Store']='expcore.store', - ['Gui']='expcore.gui' + ['Gui']='expcore.gui', + ['Sudo']='expcore.sudo' } -- loads all the modules given in the above table