-- IcyEssentials Core Registration Framework local storage = minetest.get_mod_storage() ess = { commands = {}, privileges = {}, modules = {}, player_meta = {}, world_meta = nil, } --------------------- -- PLAYER METADATA -- --------------------- -- Load player metadata local function playerdata_load(name) local decoded = minetest.deserialize(storage:get_string(name)) if not decoded then ess.player_meta[name] = {} return {} end ess.player_meta[name] = decoded return decoded end -- Save player metadata local function playerdata_save(name) if not ess.player_meta[name] then return end local encoded = minetest.serialize(ess.player_meta[name]) storage:set_string(name, encoded) end -- Set a player metadata value function ess.set_player_meta(player, flag, value) if not ess.player_meta[player] then playerdata_load(player) end ess.player_meta[player][flag] = value playerdata_save(player) end -- Get a player's metadata value function ess.get_player_meta(player, flag) if not ess.player_meta[player] then playerdata_load(player) end return ess.player_meta[player][flag] end -------------------- -- WORLD METADATA -- -------------------- -- Load player metadata local function worlddata_load() local decoded = minetest.deserialize(storage:get_string("_data")) if not decoded then ess.world_meta = {} return {} end ess.world_meta = decoded return decoded end -- Save player metadata local function worlddata_save() if not ess.world_meta then return end local encoded = minetest.serialize(ess.world_meta) storage:set_string("_data", encoded) end -- Set a player metadata value function ess.set_world_meta(flag, value) if not ess.world_meta then worlddata_load() end ess.world_meta[flag] = value worlddata_save() end -- Get a player's metadata value function ess.get_world_meta(flag) if not ess.world_meta then worlddata_load() end return ess.world_meta[flag] end ------------- -- UTILITY -- ------------- -- Just return a (TODO: translated) string that rejects permission function ess.reject_permission() return false, "You don't have permission to run this command." end -- Match a single privilege, but also check ".all" privileges function ess.priv_match(name, priv) local parts = string.split(priv, ".") if #parts > 1 then if minetest.check_player_privs(name, {[parts[1] .. ".all"] = true}) then return true end if #parts > 2 then if minetest.check_player_privs(name, {[parts[1] .. "." .. parts[2] .. ".all"] = true}) then return true end end end return minetest.check_player_privs(name, {[priv] = true}) end -- Save a player's position for use with /back local function save_player_pos(player, commit) local pobj = minetest.get_player_by_name(player) if not pobj then return end local pos = pobj:get_pos() if commit then ess.set_player_meta(player, "position", minetest.pos_to_string(commit)) end return pos end ---------------- -- PRIVILEGES -- ---------------- local function handle_command_privileges(privileges, description, default) local perms = {} for perm in pairs(privileges) do local parts = string.split(perm, ".") if ess.modules[parts[1]] and not ess.privileges[perm] then minetest.register_privilege(perm, { description = description, give_to_singleplayer = default, }) ess.privileges[perm] = true end perms[perm] = true if #parts > 1 then for i,p in ipairs(parts) do if i == 1 then local a = p .. ".all" if not ess.privileges[a] then minetest.register_privilege(a, { description = "icyess all commands in module " .. p, give_to_singleplayer = false, give_to_admin = false }) ess.privileges[a] = true end perms[a] = true elseif i == 2 then local a = parts[1] .. "." .. p .. ".all" if not ess.privileges[a] then minetest.register_privilege(a, { description = "icyess all commands in module " .. p .. " category "..p, give_to_singleplayer = false, give_to_admin = false }) ess.privileges[a] = true end perms[a] = true end end end end perms["ess.all"] = true return perms end ------------------ -- CHATCOMMANDS -- ------------------ local function register_chatcommand(command, def) if def.privs then def.privs = handle_command_privileges(def.privs, def.description, def.default == true) end local function fn (name, params) local privileges_met = false -- Check for any of the privileges if def.privs then for priv in pairs(def.privs) do if ess.priv_match(name, priv) then privileges_met = true break end end else privileges_met = true end if not privileges_met then return ess.reject_permission() end -- If this command is a teleport, save the player position local player_pos if def.save_player_pos then player_pos = save_player_pos(name) end local splitparams = string.split(params, " ") -- Run the chat command function local ret,mesg = def.func(name, params, splitparams) -- If we saved player position and the command succeeded, commit the last position save if ret and player_pos then save_player_pos(name, player_pos) end return ret,mesg end -- Clean-up the command definition local pd = table.copy(def) pd.privs = {} pd.module = nil pd.category = nil pd.default = nil pd.override = nil pd.override_aliases = nil pd.save_player_pos = nil pd.func = fn -- If this command is overriding, check if a command like this already exists and override it if def.override and minetest.registered_chatcommands[command] then minetest.override_chatcommand(command, pd) else minetest.register_chatcommand(command, pd) end end --[[ IcyEss Module registration Registers a module. ]] function ess.register_module(modname, description) ess.modules[modname] = { mod = minetest.get_current_modname(), description = description } return { register_chatcommand = function (root, cmddef) cmddef.module = modname return ess.register_chatcommand(root, cmddef) end } end --[[ IcyEss Command registration { -- Command aliases (optional) -- All of these will be registered as separate commands with the same -- privileges and execute function aliases = {}, -- Optional module name, such as "ess-chat" or "protect". -- This will be used in privilege generation and grouping. module = "ess", -- Optional command category, such as "time" or "item". -- This will be used in privilege generation and grouping. category = "item", -- Command privileges (optional) -- Set to true to generate privilege based on the command name privs = true, -- Set privileges a table in order to optionally require one of these privileges -- If the privilege starts with the module name, they will automatically be -- registered, if they don't already exist. privs = { "ess.item.repair" = true, "ess.item.repair.other" = true, }, -- Command execution (required) func = function (name, params), -- If command like this exists, do we override it? override = false, -- If aliases exist, do we override them? override_aliases = false, -- If this command is given to singleplayer default = false, -- If this command modifies player's position in some way, -- save their current position before running the command save_player_pos = false } ]] function ess.register_chatcommand(root, cmddef) assert(type(cmddef) == "table", "command definition is not a table") assert(cmddef.description ~= nil, "command is missing a description") assert(cmddef.func ~= nil, "command definition is missing a function") assert(type(cmddef.func) == "function", "command definition is missing a function") if ess.commands[root] and not cmddef.override then return end if not cmddef.privs and cmddef.privileges then cmddef.privs = table.copy(cmddef.privileges) cmddef.privileges = nil end local privs = cmddef.privs if not privs then privs = {} end -- Set default module if not cmddef.module then cmddef.module = "ess" end -- Generate privilege if privs == true then local a = "" if cmddef.module then a = a .. cmddef.module .. "." end if cmddef.category then a = a .. cmddef.category .. "." end privs = {[a .. root] = true} end -- No privileges required local plen = 0 for _ in pairs(privs) do plen = plen + 1 end if plen == 0 then privs = nil end cmddef.privs = privs ess.commands[root] = cmddef register_chatcommand(root, cmddef) if not cmddef.aliases or #cmddef.aliases == 0 then return end local aliasdef = table.copy(cmddef) aliasdef.func = cmddef.func aliasdef.override = cmddef.override_aliases == true aliasdef.override_aliases = nil aliasdef.description = cmddef.description .. " (alias to "..root..")" for _,a in pairs(cmddef.aliases) do register_chatcommand(a,aliasdef) end end function ess.autoregister(list, category) for cmd,def in pairs(list) do def.category = category ess.register_chatcommand(cmd, def) end end