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.
361 lines
11 KiB
361 lines
11 KiB
-- 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"
|
|
noarea_privs = minetest.settings:get("switch_creative.noarea_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 = "<x> <y> <z>, <x> <y> <z>, <text>",
|
|
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 = "<id>, <text>",
|
|
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 = tostring(area_id)
|
|
if privstring and area_id then
|
|
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."
|
|
else
|
|
return false, "Failed."
|
|
end
|
|
end,
|
|
})
|
|
|
|
minetest.register_chatcommand("creative_area_rm", {
|
|
params = "<id>",
|
|
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 = noarea_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
|
|
|