-- creative_regions mod by h3ndrik creative_regions = {} local mod_storage = minetest.get_mod_storage() creative_regions.astore = AreaStore() creative_regions.region_privs = {} areas_owner_privs = minetest.settings:get("creative_regions.owner_privs") or "+creative, +fast, +fly" areas_guest_privs = minetest.settings:get("creative_regions.guest_privs") or "-fly, -fast" noregion_privs = minetest.settings:get("creative_regions.noregion_privs") or "-creative, +fast, -fly" default_privs = minetest.settings:get("creative_regions.default_privs") or "+creative, +fast, +fly" function creative_regions:load_regions() self.astore:from_file(minetest.get_worldpath().."/creative_regions_regions") creative_regions.region_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 = "Testregion" -- local astore_id = self.astore:insert_area(edge1, edge2, tostring(data)) -- -- creative_regions:set_region_privs(astore_id, "+creative, +fast, +fly") end function creative_regions:save_regions() self.astore:to_file(minetest.get_worldpath().."/creative_regions_regions") local datastr = minetest.serialize(creative_regions.region_privs) if not datastr then minetest.log("error", "[creative_regions] Failed to serialize region_privs data!") return end mod_storage:set_string("astore_privs", datastr) end function creative_regions:set_region_privs(id, privs_string) creative_regions.region_privs[tostring(id)] = privs_string end minetest.register_chatcommand("creative_region", { params = " , , ", description = "Set a creative region 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, region_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 = region_name local astore_id = creative_regions.astore:insert_area(edge1, edge2, tostring(data)) if astore_id then creative_regions:set_region_privs(tostring(astore_id), nil) minetest.chat_send_player(name, "[creative_regions] New region set. ID: " .. astore_id) creative_regions:save_regions() return true, "Done" else return false, "Failed" end end, }) minetest.register_chatcommand("creative_region_privs", { params = ", ", description = "Set privstring for creative region", 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, _, region_id, privstring = param:find("^([+-]?%a?%d+)%s*,%s*(.+)$") if not found then return false, "Syntax error" end if privstring and region_id then creative_regions:set_region_privs(tostring(region_id), privstring) minetest.chat_send_player(name, "[creative_regions] Privstring set for region " .. region_id .. ": " .. privstring) creative_regions:save_regions() return true, "Done" else return false, "Failed" end end, }) minetest.register_chatcommand("creative_region_rm", { params = "", description = "Remove a creative region", 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, _, region_id = param:find("^([+-]?%d+)%s*$") if not found then return false, "Syntax error" end local success = creative_regions.astore:remove_area(tonumber(region_id)) if success then minetest.chat_send_player(name, "[creative_regions] Region " .. region_id .. "removed") creative_regions:set_region_privs(tostring(region_id), nil) else minetest.chat_send_player(name, "[creative_regions] Error removing region " .. region_id) end creative_regions:save_regions() return true, "Done." end, }) function creative_regions: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 creative_regions:add_privs_from_string(table, str) end function creative_regions:is_areas_mod(area_id) area_id = tostring(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 creative_regions:get_region_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 creative_regions: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 creative_regions: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 creative_regions: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("creative_regions.saved_privs", minetest.serialize(privs)) end function creative_regions:restore_player_privs(player) local name = player:get_player_name() local pmeta = player:get_meta() local privs = minetest.deserialize(pmeta:get_string("creative_regions.saved_privs")) if privs then minetest.set_player_privs(name, privs) pmeta:set_string("creative_regions.saved_privs", nil) end end function creative_regions: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 creative_regions: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 = creative_regions:initial_stuff() for _, stack in ipairs(initial_items) do inv:add_item("main", stack) end end end function creative_regions:player_enter_region(player, privstring) local name = player:get_player_name() local has_creative = minetest.check_player_privs(name, {creative=true}) local privs_grant, privs_revoke = creative_regions: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") creative_regions:save_player_inventory(player, "saved_survival") creative_regions: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") creative_regions:save_player_inventory(player, "saved_creative") creative_regions: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 creative_regions: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("creative_regions.active_regions") local player_last_active_regions = pmeta:get_string("creative_regions.active_regions") or "-1" local player_active_regions = "-1" local areas_owner = false local areas_guest = false local areas_open = false local smallest_region = {} local smallest_areas_area = {} if minetest.check_player_privs(name, { protection_bypass=true }) then --minetest.chat_send_player(name, "Changed region. You have protection_bypass priv") return end -- enter region local current_regions = self.astore:get_areas_for_pos(pos, true, true) for astore_id, astore_area in pairs( current_areas ) do local regionsize = creative_regions:get_region_size(astore_area) if not smallest_region.size or regionsize < smallest_region.size then smallest_region.id = tostring(astore_id) smallest_region.size = regionsize end end if smallest_region.id then player_active_regions = tostring(smallest_region.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 = creative_regions:get_areas_area_size(a_area) if not smallest_areas_area.size or areasize < smallest_areas_area.size then smallest_areas_area.id = tostring(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 = noregion_privs if smallest_region.id then if creative_regions.region_privs[tostring(smallest_region.id)] then privstring = creative_regions.region_privs[tostring(smallest_region.id)] else privstring = default_privs end 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_regions, ",")) do a = a:trim() if string.sub(a, 1, 1) == "a" then if creative_regions.region_privs[a] then privstring = privstring .. ", " .. creative_regions.region_privs[a] end end end if smallest_areas_area.size and smallest_region.size then if smallest_region.size <= smallest_areas_area.size then privstring = privstring .. ", " .. creative_regions.region_privs[tostring(smallest_region.id)] end end end if player_active_regions ~= player_last_active_regions then creative_regions:player_enter_region(player, privstring) pmeta:set_string("creative_regions.active_regions", player_active_regions) end -- print(dump(pmeta:to_table())) end creative_regions:load_regions() local timer = 0 minetest.register_globalstep(function(dtime) timer = timer + dtime if timer >= 1 then for _, player in pairs(minetest.get_connected_players()) do creative_regions:update_player(player) end end end) -- areas mod hud if minetest.get_modpath("areas") then local function areas_hud_handler(pos, areas) local current_regions = creative_regions.astore:get_areas_for_pos(pos, false, true) for astore_id, astore_area in pairs( current_regions ) 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