commit 170b90372238d83699c213cec60f6333691225a5 Author: Billy S Date: Fri Nov 2 17:07:51 2018 -0400 First commit diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..657e844 --- /dev/null +++ b/depends.txt @@ -0,0 +1 @@ +lib_chatcmdbuilder diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..55400e1 --- /dev/null +++ b/init.lua @@ -0,0 +1,283 @@ +local function load_data() + ms = priv_roles.storage + local data = {} + data.players = minetest.deserialize(ms:get_string("players")) or {} -- Table of what players have what roles + data.roles = minetest.deserialize(ms:get_string("roles")) or {} -- Table of roles and associated privs + return data +end + +local function save_data() + local p = minetest.serialize(priv_roles.data.players) + priv_roles.storage:set_string("players", p) +end + +local function save_roles() + local r = minetest.serialize(priv_roles.data.roles) + priv_roles.storage:set_string("roles", r) +end + +-- This really ought to be standard +function table.shallow_copy(t) + local t2 = {} + for k,v in pairs(t) do + t2[k] = v + end + return t2 +end + +-- Global mod list +priv_roles = {} +local p = minetest.get_modpath(minetest.get_current_modname()) + +-- Get old set_privs function +priv_roles.set_player_privs = minetest.set_player_privs + +-- Call this to make sure that a player's role will exist +priv_roles.check_for_player = function(name) + if priv_roles.data.players[name] == nil then + priv_roles.data.players[name] = table.shallow_copy(priv_roles.default_roles) + priv_roles.data.players[name]["_extra"] = {} + end + -- Make sure _extra is defined + if priv_roles.data.players[name]["_extra"] == nil then + priv_roles.data.players[name]["_extra"] = {} + end +end + +priv_roles.calc_privs = function(player, only_role_based) + priv_roles.check_for_player(player) + local roles = priv_roles.data.players[player] + if roles then + local privs = {} + for r, _ in pairs(roles) do + -- It could be the _extra role; if so ignore it + if r == "_extra" then + -- It could be a role that was removed; if so remove it + elseif priv_roles.data.roles[r] == nil then + priv_roles.data.players[player][r] = nil + else + local r_privs = table.shallow_copy(priv_roles.data.roles[r]) + -- If "_all" is in r_privs, expand it to be all privs excepts ones mentioned in the role + if r_privs["_all"] then + for p, _ in pairs(minetest.registered_privileges) do + if r_privs[p] == nil then + r_privs[p] = true + end + end + r_privs["_all"] = nil + end + -- If "_nothing" is in r_privs, give no privs + if r_privs["_nothing"] then return {} end + -- Calculate the privs table + for p, v in pairs(r_privs) do + if privs[v] ~= false then -- If the priv is removed by a role, other roles can't re-add it + privs[p] = v + end + end + end + end + if only_role_based ~= true then + -- Apply all the privs in the _extra role + for priv, value in pairs(roles["_extra"]) do + privs[priv] = value + end + end + -- Get rid of all the privs with a value of false + local privs_table = {} + for p, v in pairs(privs) do + if v then + privs_table[p] = v + end + end + return privs_table + else + return {} + end +end + +-- Redefine minetest.set_player_privs + +function minetest.set_player_privs(player, full_privs) + -- Make sure player is valid + if (player == nil) or (not minetest.player_exists(player)) then + return false + end + -- Make sure privs table is valid + if full_privs == nil or type(full_privs) ~= "table" then + return false + end + -- Make sure the player has a roles table + priv_roles.check_for_player(player) + -- Get all the role-based privs + local privs = priv_roles.calc_privs(player, true) + local extra_privs = {} + -- Figure out what extra priv need to be granted + for p, _ in pairs(full_privs) do + if privs[p] == nil then + extra_privs[p] = true + end + end + -- Figure out what extra privs need to be removed + for p, _ in pairs(privs) do + if full_privs[p] == nil then + extra_privs[p] = false + end + end + -- Update _extra + priv_roles.data.players[player]["_extra"] = extra_privs + -- Calculate + local privs_final = priv_roles.calc_privs(player) + -- Set privs + priv_roles.set_player_privs(player, privs_final) + -- Save data + save_data() +end + +-- Set up roles on joinplayer +minetest.register_on_joinplayer(function(player) + local pName = player:get_player_name() + priv_roles.check_for_player(pName) + -- Update privs (necessary for new players or if privs of a role were changed) + priv_roles.set_player_privs(pName, priv_roles.calc_privs(pName)) +end) + +-- Define mod functions +priv_roles.grant = function(player, role) + -- Get the role + local r = priv_roles.data.roles[role] + if r then -- Does the role exist + if minetest.player_exists(player) then -- Does the player exist? + priv_roles.check_for_player(player) + -- Add role to player + local p_roles = priv_roles.data.players[player] + p_roles[role] = true + priv_roles.data.players[player] = p_roles + -- Override anything in _extra that conflicts with that role + for p, _ in pairs(r) do + if priv_roles.data.players[player]["_extra"][p] == false then + priv_roles.data.players[player]["_extra"][p] = nil + end + end + -- Cacluate privs + local p_privs = priv_roles.calc_privs(player) + -- Assign privs + priv_roles.set_player_privs(player, p_privs) + -- Save data + save_data() + return true, "Done!" + else + return false, "Player " .. player .. "does not exist." + end + else + return false, "Role " .. role .. " does not exist." + end +end + +priv_roles.revoke = function(player, role) + -- Get the role + local r = priv_roles.data.roles[role] + if r then -- Does the role exist + if minetest.player_exists(player) then -- Does the player exist? + priv_roles.check_for_player(player) + if priv_roles.data.players[player][role] then -- Does the player have that role? + -- Remove role from player + priv_roles.data.players[player][role] = nil + -- Override anything in _extra that has a priv in this role + for p, _ in pairs(r) do + if priv_roles.data.players[player]["_extra"][p] == true then + priv_roles.data.players[player]["_extra"][p] = nil + end + end + -- Calc privs + p_privs = priv_roles.calc_privs(player) + priv_roles.set_player_privs(player, p_privs) + -- Save data + save_data() + return true, "Done!" + else + return false, "Player " .. player .. " does not have role " .. role + end + else + return false, "Player " .. player .. " does not exist." + end + else + return false, "Role " .. role .. " does not exist." + end +end + +priv_roles.list = function(player) + if minetest.player_exists(player) then + priv_roles.check_for_player(player) + local roles = priv_roles.data.players[player] + local r_str = "Roles of " .. player .. ":" + for r, _ in pairs(roles) do + if r ~= "_extra" then + r_str = r_str .. " " .. r + end + end + return true, r_str + else + return false, "Player " .. player .. " does not exist." + end +end + +-- Load mod data +priv_roles.storage = minetest.get_mod_storage() +priv_roles.data = load_data() + +-- Add in roles +dofile(p .. "/settings.lua") + +-- Roles chat command +ChatCmdBuilder.new("roles", function(cmd) + -- grant player a role + cmd:sub("grant :name :role", function(name, t, r) + if minetest.check_player_privs(name, {privs = true}) then + local worked, msg = priv_roles.grant(t, r) + if worked then + minetest.chat_send_player(t, name .. " granted you the " .. r .. " role!") + end + return worked, msg + else + return false, "You don't have permission to run this command" + end + end) + -- revoke player a role + cmd:sub("revoke :name :role", function(name, t, r) + if minetest.check_player_privs(name, {privs = true}) then + local worked, msg = priv_roles.revoke(t, r) + if worked then + minetest.chat_send_player(t, name .. " revoked from you the " .. r .. " role!") + end + return worked, msg + else + return false, "You don't have permission to run this command" + end + end) + -- List player roles + cmd:sub("of :name", function(name, t) + local worked, msg = priv_roles.list(t) + return worked, msg + end) + -- List all roles + cmd:sub("list", function(name) + local l_str = "Available roles:" + for r, _ in pairs(priv_roles.data.roles) do + l_str = l_str .. " " .. r + end + return true, l_str + end) + -- Help + cmd:sub("help", function(name) + return true, "/roles grant : Grants player named the role \n" .. + "/roles revoke : Revokes role from player named \n" .. + "/roles of : Lists the roles of player named \n" .. + "/roles list: Lists all roles\n" .. + "/roles help: Shows this help" + end) +end, { + description = "Manage/view player roles", + privs = { + interact = true + } +}) diff --git a/settings.lua b/settings.lua new file mode 100644 index 0000000..1480b60 --- /dev/null +++ b/settings.lua @@ -0,0 +1,48 @@ +-- Default roles; these are the roles given to a player when they join +priv_roles.default_roles = {player = true} + +-- +-- Player "ranks" +-- + +priv_roles.data.roles["player"] = { interact = true, + shout = true, + home = true} + +priv_roles.data.roles["trusted"] = { lava = true, + areas_high_limit = true} + +priv_roles.data.roles["moderator"] = { kick = true, + ban = true, + basic_privs = true, + fly = true, + jail = true, + bring = true, + teleport = true, + fast = true, + lava = true} + +priv_roles.data.roles["admin"] = { _all = true, + server = false, + privs = false} + +priv_roles.data.roles["owner"] = { _all = true} + +-- +-- Server builders +-- + +priv_roles.data.roles["builder"] = { fast = true, + fly = true, + creative = true, + noclip = true, + teleport = true, + areas = true} + +priv_roles.data.roles["expert_builder"] = { worldedit = true} + +-- +-- Punishments +-- + +priv_roles.data.roles["noprivs"] = { _nothing = true}