2019-11-10 20:12:29 +00:00
|
|
|
-- IcyEssentials Core Registration Framework
|
|
|
|
|
|
|
|
local storage = minetest.get_mod_storage()
|
|
|
|
|
|
|
|
ess = {
|
2019-11-11 16:52:54 +00:00
|
|
|
modules = {},
|
2019-11-10 20:12:29 +00:00
|
|
|
commands = {},
|
|
|
|
privileges = {},
|
|
|
|
world_meta = nil,
|
2019-11-11 16:52:54 +00:00
|
|
|
player_meta = {},
|
2019-11-10 20:12:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
---------------------
|
|
|
|
-- 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 --
|
|
|
|
--------------------
|
|
|
|
|
2019-11-11 16:52:54 +00:00
|
|
|
-- Load world metadata
|
2019-11-10 20:12:29 +00:00
|
|
|
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
|
|
|
|
|
2019-11-11 16:52:54 +00:00
|
|
|
-- Save world metadata
|
2019-11-10 20:12:29 +00:00
|
|
|
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
|
|
|
|
|
2019-11-11 16:52:54 +00:00
|
|
|
-- Set a world metadata value
|
2019-11-10 20:44:24 +00:00
|
|
|
function ess.set_world_meta(flag, value)
|
2019-11-10 20:12:29 +00:00
|
|
|
if not ess.world_meta then worlddata_load() end
|
|
|
|
ess.world_meta[flag] = value
|
|
|
|
worlddata_save()
|
|
|
|
end
|
|
|
|
|
2019-11-11 16:52:54 +00:00
|
|
|
-- Get a world metadata value
|
2019-11-10 20:12:29 +00:00
|
|
|
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
|
|
|
|
|
2019-11-11 16:52:54 +00:00
|
|
|
-- Match a single privilege, but also check ".all" privileges (optional)
|
|
|
|
function ess.priv_match(name, priv, skip_alls)
|
|
|
|
if not skip_alls then
|
|
|
|
local parts = string.split(priv, ".")
|
|
|
|
if #parts > 1 then
|
|
|
|
if parts[1] ~= "ess" and minetest.check_player_privs(name, {["ess.all"] = true}) then
|
2019-11-10 20:44:24 +00:00
|
|
|
return true
|
|
|
|
end
|
2019-11-11 16:52:54 +00:00
|
|
|
|
|
|
|
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
|
2019-11-10 20:44:24 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-11-10 20:12:29 +00:00
|
|
|
return minetest.check_player_privs(name, {[priv] = true})
|
|
|
|
end
|
|
|
|
|
2019-11-11 16:52:54 +00:00
|
|
|
-- Save a player's position
|
|
|
|
-- If commit is not defined or true, we save current position
|
|
|
|
-- If commit is false, just the player's position is returned
|
|
|
|
-- If commit is a position, we save that position
|
|
|
|
function ess.save_player_pos(player, commit)
|
|
|
|
local pobj
|
|
|
|
local name = player
|
|
|
|
if type(player) ~= "userdata" then
|
|
|
|
pobj = minetest.get_player_by_name(player)
|
|
|
|
if not pobj then return end
|
|
|
|
else
|
|
|
|
name = player:get_player_name()
|
|
|
|
pobj = player
|
|
|
|
end
|
2019-11-10 20:12:29 +00:00
|
|
|
|
|
|
|
local pos = pobj:get_pos()
|
2019-11-11 16:52:54 +00:00
|
|
|
if commit == nil or commit == true then
|
|
|
|
commit = pos
|
|
|
|
end
|
|
|
|
|
2019-11-10 20:12:29 +00:00
|
|
|
if commit then
|
2019-11-11 16:52:54 +00:00
|
|
|
ess.set_player_meta(name, "position", minetest.pos_to_string(commit))
|
2019-11-10 20:12:29 +00:00
|
|
|
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
|
|
|
|
|
2019-11-11 16:52:54 +00:00
|
|
|
-- Make sure .all privileges are registered
|
2019-11-10 20:12:29 +00:00
|
|
|
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
|
|
|
|
elseif i == 2 then
|
|
|
|
local a = parts[1] .. "." .. p .. ".all"
|
|
|
|
if not ess.privileges[a] then
|
|
|
|
minetest.register_privilege(a, {
|
2019-11-11 16:52:54 +00:00
|
|
|
description = "icyess all commands in module " .. parts[1] .. " category "..p,
|
2019-11-10 20:12:29 +00:00
|
|
|
give_to_singleplayer = false,
|
|
|
|
give_to_admin = false
|
|
|
|
})
|
|
|
|
ess.privileges[a] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
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
|
2019-11-11 16:52:54 +00:00
|
|
|
player_pos = ess.save_player_pos(name, false)
|
2019-11-10 20:12:29 +00:00
|
|
|
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
|
2019-11-11 16:52:54 +00:00
|
|
|
ess.save_player_pos(name, player_pos)
|
2019-11-10 20:12:29 +00:00
|
|
|
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,
|
2019-11-11 16:52:54 +00:00
|
|
|
-- save their current position before running the command.
|
|
|
|
-- Use this only when its is certain that the player will teleport.
|
2019-11-10 20:12:29 +00:00
|
|
|
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
|