-- switch_creative mod by h3ndrik switch_creative = {} local mod_storage = minetest.get_mod_storage() switch_creative.astore = AreaStore() switch_creative.area_privs = {} areas_owner_privs = minetest.settings:get("switch_creative.owner_privs") or "+creative, +fast, +fly" areas_guest_privs = minetest.settings:get("switch_creative.guest_privs") or "-fly, -fast" default_privs = minetest.settings:get("switch_creative.default_privs") or "-creative, +fast, -fly" function switch_creative:load_areas() self.astore:from_file(minetest.get_worldpath().."/switch_creative_areas") switch_creative.area_privs = minetest.deserialize(mod_storage:get_string("astore_privs")) or {} -- 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)) -- -- switch_creative:set_area_privs(astore_id, "+creative, +fast, +fly") end function switch_creative:save_areas() self.astore:to_file(minetest.get_worldpath().."/switch_creative_areas") local datastr = minetest.serialize(switch_creative.area_privs) if not datastr then minetest.log("error", "[switch_creative] Failed to serialize area_privs data!") return end mod_storage:set_string("astore_privs", datastr) end function switch_creative:set_area_privs(id, privs_string) switch_creative.area_privs[id] = privs_string end minetest.register_chatcommand("creative_area", { params = " , , ", description = "Set a switch_creative area from a to b", privs = {server = true}, func = function(name, param) local player = minetest.get_player_by_name(name) if not player then return false, "Player not found" end local found, _, x1, y1, z1, x2, y2, z2, area_name = param:find("^([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s*,%s*([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s*,%s*(.+)$") if not found then return false, "Syntax error" end local edge1 = { x=tonumber(x1), y=tonumber(y1), z=tonumber(z1) } local edge2 = { x=tonumber(x2), y=tonumber(y2), z=tonumber(z2) } local data = area_name local astore_id = switch_creative.astore:insert_area(edge1, edge2, tostring(data)) switch_creative:set_area_privs(astore_id, "+creative, +fast, +fly") minetest.chat_send_player(name, "[creative_area] New area set. ID: " .. astore_id) switch_creative:save_areas() return true, "Done." end, }) minetest.register_chatcommand("creative_area_privs", { params = ", ", description = "Set privstring for switch_creative area", privs = {server = true}, func = function(name, param) local player = minetest.get_player_by_name(name) if not player then return false, "Player not found" end local found, _, area_id, privstring = param:find("^([+-]?%a?%d+)%s*,%s*(.+)$") if not found then return false, "Syntax error" end area_id = tonumber(area_id) switch_creative:set_area_privs(area_id, privstring) minetest.chat_send_player(name, "[creative_area] Privstring set for area " .. area_id .. ": " .. privstring) switch_creative:save_areas() return true, "Done." end, }) minetest.register_chatcommand("creative_area_rm", { params = "", description = "Remove a switch_creative area", privs = {server = true}, func = function(name, param) local player = minetest.get_player_by_name(name) if not player then return false, "Player not found" end local found, _, area_id = param:find("^([+-]?%d+)%s*$") if not found then return false, "Syntax error" end area_id = tonumber(area_id) local success = switch_creative.astore:remove_area(area_id) if success then minetest.chat_send_player(name, "[creative_area] Area " .. area_id .. "removed") else minetest.chat_send_player(name, "[creative_area] Error removing area " .. area_id) end switch_creative:save_areas() return true, "Done." end, }) function switch_creative: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 switch_creative:is_areas_mod(area_id) local is_areas_id = string.sub(id, 1, 2) == "a" local a_id = tonumber( string.sub(id, 2) ) return is_areas_id, a_id end function switch_creative: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 switch_creative:get_areas_area_size(areas_area) local pos1 = areas_area.pos1 local pos2 = areas_area.pos2 local x = math.abs( pos2.x - pos1.x ) local z = math.abs( pos2.z - pos1.x ) return x*z end function switch_creative:initial_stuff() local stuff_string = minetest.settings:get("initial_stuff") or "default:pick_steel,default:axe_steel,default:shovel_steel," .. "default:torch 99,default:cobble 99" local itemtable = {} local items = stuff_string:split(",") for _, stack in ipairs(items) do table.insert(itemtable, ItemStack(stack)) end return itemtable end function switch_creative: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("switch_creative.saved_privs", minetest.serialize(privs)) end function switch_creative:restore_player_privs(player) local name = player:get_player_name() local pmeta = player:get_meta() local privs = minetest.deserialize(pmeta:get_string("switch_creative.saved_privs")) if privs then minetest.set_player_privs(name, privs) pmeta:set_string("switch_creative.saved_privs", nil) end end function switch_creative: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 switch_creative: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) local give_initial = false if not player_items then player_items = {} give_initial = true end inv:set_list("main", player_items) if give_initial then local initial_items = switch_creative:initial_stuff() for _, stack in ipairs(initial_items) do inv:add_item("main", stack) end end end function switch_creative: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 = switch_creative: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") switch_creative:save_player_inventory(player, "saved_survival") switch_creative:restore_player_inventory(player, "saved_creative") if minetest.get_modpath("unified_inventory") then unified_inventory.set_inventory_formspec(player, unified_inventory.default) end elseif has_creative and privs_revoke.creative then minetest.chat_send_player(name, "You entered survival mode") switch_creative:save_player_inventory(player, "saved_creative") switch_creative: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 switch_creative: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("switch_creative.active_areas") local player_last_active_areas = pmeta:get_string("switch_creative.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 = {} local smallest_areas_area = {} if minetest.check_player_privs(name, { protection_bypass=true }) then --minetest.chat_send_player(name, "Changed area. You have 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 = switch_creative: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 local areasize = switch_creative:get_areas_area_size(a_area) if not smallest_areas_area.size or areasize < smallest_areas_area.size then smallest_areas_area.id = a_id smallest_areas_area.size = areasize end 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 switch_creative.area_privs[smallest_area.id] then privstring = switch_creative.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 switch_creative.area_privs[a] then privstring = privstring .. ", " .. switch_creative.area_privs[a] end end end if smallest_areas_area.size and smallest_area.size then if smallest_area.size <= smallest_areas_area.size then privstring = privstring .. ", " .. switch_creative.area_privs[smallest_area.id] end end end if player_active_areas ~= player_last_active_areas then switch_creative:player_enter_area(player, privstring) pmeta:set_string("switch_creative.active_areas", player_active_areas) end -- print(dump(pmeta:to_table())) end switch_creative: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 switch_creative: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 = switch_creative.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