icyessentials/ess_core/init.lua

367 lines
8.8 KiB
Lua

-- 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