Minetest mod: Toggle privs in areas
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
7.6 KiB

-- toggle_areas mod by h3ndrik
toggle_areas = {}
local mod_storage = minetest.get_mod_storage()
toggle_areas.astore = AreaStore()
toggle_areas.area_privs = {}
toggle_areas.registered_on_enter = {}
toggle_areas.registered_on_leave = {}
areas_owner_privs = minetest.settings:get("toggle_areas.owner_privs") or "+creative, +fast, +fly"
areas_guest_privs = minetest.settings:get("toggle_areas.guest_privs") or "-fly, -fast"
default_privs = minetest.settings:get("toggle_areas.default_privs") or "-creative, +fast, -fly"
function toggle_areas:load_areas()
local test = minetest.deserialize(mod_storage:get_string("astore"))
local edge1 = { x=-10, y=-10, z=-10 }
local edge2 = { x=10, y=10, z=10 }
local data = "Testarea"
local astore_id = self.astore:insert_area(edge1, edge2, tostring(data))
toggle_areas:set_area_privs(astore_id, "+creative, +fast, +fly")
self.register_on_enter(astore_id, function(player)
local name = player:get_player_name()
local privs = minetest.get_player_privs(name)
minetest.log("warning", "[toggle_areas] callback worked")
privs.fly = true
privs.fast = false
minetest.set_player_privs(name, privs)
end)
end
function toggle_areas:save_areas()
local datastr = minetest.serialize(self.astore)
if not datastr then
minetest.log("error", "[toggle_areas] Failed to serialize area data!")
return
end
mod_storage:set_string("astore", datastr)
end
function toggle_areas:register_on_enter(id, func)
toggle_areas.registered_on_enter[id] = func
end
function toggle_areas:set_area_privs(id, privs_string)
toggle_areas.area_privs[id] = privs_string
end
function toggle_areas:decode_privs_string(str)
-- minetest/builtin/common/misc_helpers.lua:core.string_to_privs()
assert(type(str) == "string")
local delim = ','
local privs_grant = {}
local privs_revoke = {}
for _, priv in pairs(string.split(str, delim)) do
priv = priv:trim()
local toggle = string.sub(priv, 1, 1)
priv = string.sub(priv, 2)
if toggle == '+' then
privs_grant[priv] = true
privs_revoke[priv] = nil
elseif toggle == '-' then
privs_revoke[priv] = true
privs_grant[priv] = nil
end
end
return privs_grant, privs_revoke
end
function toggle_areas:is_areas_mod(area_id)
local is_areas_id = string.sub(id, 1, 2) == "a_"
local a_id = tonumber( string.sub(id, 3) )
return is_areas_id, a_id
end
function toggle_areas:get_area_size(astore_area)
local pos1 = astore_area.min
local pos2 = astore_area.max
local x = math.abs( pos2.x - pos1.x )
local z = math.abs( pos2.z - pos1.x )
return x*z
end
function toggle_areas:save_player_privs(player)
local name = player:get_player_name()
local pmeta = player:get_meta()
local privs = minetest.get_player_privs(name)
pmeta:set_string("toggle_areas_privs", minetest.serialize(privs))
end
function toggle_areas:restore_player_privs(player)
local name = player:get_player_name()
local pmeta = player:get_meta()
local privs = minetest.deserialize(pmeta:get_string("toggle_areas_privs"))
if privs then
minetest.set_player_privs(name, privs)
pmeta:set_string("toggle_areas_privs", nil)
end
end
function toggle_areas:save_player_inventory(player, listname)
local name = player:get_player_name()
local pmeta = player:get_meta()
local inv = player:get_inventory()
local player_items = inv:get_list("main")
inv:set_list(listname, player_items)
end
function toggle_areas:restore_player_inventory(player, listname)
local name = player:get_player_name()
local pmeta = player:get_meta()
local inv = player:get_inventory()
local player_items = inv:get_list(listname) or {}
inv:set_list("main", player_items)
end
function toggle_areas:player_enter_area(player, privstring)
local name = player:get_player_name()
local has_creative = minetest.check_player_privs(name, {creative=true})
local privs_grant, privs_revoke = toggle_areas:decode_privs_string(privstring)
if not has_creative and privs_grant.creative and not privs_revoke.creative then
minetest.chat_send_player(name, "You entered creative mode")
toggle_areas:save_player_inventory(player, "saved_survival")
toggle_areas:restore_player_inventory(player, "saved_creative")
elseif has_creative and privs_revoke.creative then
minetest.chat_send_player(name, "You entered survival mode")
toggle_areas:save_player_inventory(player, "saved_creative")
toggle_areas:restore_player_inventory(player, "saved_survival")
end
local has_privs = minetest.get_player_privs(name)
local privs = has_privs
for newpriv, _ in pairs(privs_grant) do
privs[newpriv] = true
end
for newpriv, _ in pairs(privs_revoke) do
privs[newpriv] = nil
end
minetest.set_player_privs(name, privs)
end
function toggle_areas:update_player(player)
local name = player:get_player_name()
local pos = vector.round(player:get_pos())
local pmeta = player:get_meta()
-- pmeta:mark_as_private("toggle_areas")
local player_last_active_areas = pmeta:get_string("toggle_areas.active_areas") or "-1"
local player_active_areas = "-1"
local areas_owner = false
local areas_guest = false
local areas_open = false
local new_area = nil
local smallest_area = {}
if minetest.check_player_privs(name, { protection_bypass=true }) then
minetest.log("warning", "[toggle_areas] Player has protection_bypass priv")
return
end
-- enter area
local current_areas = self.astore:get_areas_for_pos(pos, true, true)
for astore_id, astore_area in pairs( current_areas ) do
local areasize = toggle_areas:get_area_size(astore_area)
if not smallest_area.size or areasize < smallest_area.size then
smallest_area.id = astore_id
smallest_area.size = areasize
end
end
if smallest_area.id then
player_active_areas = tostring(smallest_area.id)
end
-- enter areas mod area
local a_current_areas = {}
if minetest.get_modpath("areas") then
a_current_areas = areas:getAreasAtPos(pos)
for a_id, a_area in pairs( a_current_areas ) do
player_active_areas = player_active_areas .. ", a"..a_id
if a_area.owner == name then
areas_owner = true
break
elseif a_area.open then
areas_open = true
break
else
areas_guest = true
--continue
end
end
end
local privstring = default_privs
if smallest_area.id and toggle_areas.area_privs[smallest_area.id] then
privstring = toggle_areas.area_privs[smallest_area.id]
end
if areas_owner or areas_open then
privstring = privstring .. ", " .. areas_owner_privs
elseif areas_guest then
privstring = privstring .. ", " .. areas_guest_privs
for _, a in pairs(string.split(player_active_areas, ",")) do
a = a:trim()
if string.sub(a, 1, 1) == "a" then
if toggle_areas.area_privs[a] then
privstring = privstring .. ", " .. toggle_areas.area_privs[a]
end
end
end
end
if player_active_areas ~= player_last_active_areas then
minetest.log("warning", "[toggle_areas] player entering new area "..player_last_active_areas.."->"..player_active_areas)
toggle_areas:player_enter_area(player, privstring)
pmeta:set_string("toggle_areas.active_areas", player_active_areas)
end
-- print(dump(pmeta:to_table()))
end
toggle_areas:load_areas()
local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer >= 1 then
for _, player in pairs(minetest.get_connected_players()) do
toggle_areas:update_player(player)
end
end
end)
-- areas mod hud
if minetest.get_modpath("areas") then
local function areas_hud_handler(pos, areas)
local current_areas = toggle_areas.astore:get_areas_for_pos(pos, false, true)
for astore_id, astore_area in pairs( current_areas ) do
if astore_id then
table.insert(areas, {
id = "mod:"..astore_id,
name = astore_area.data,
--owner = "",
})
end
end
end
areas:registerHudHandler(areas_hud_handler)
end