technic/technic/machines/other/anchor.lua

118 lines
3.9 KiB
Lua

local S = technic.getter
local desc = S("Administrative World Anchor")
local function compute_forceload_positions(pos, meta)
local radius = meta:get_int("radius")
local minpos = vector.subtract(pos, vector.new(radius, radius, radius))
local maxpos = vector.add(pos, vector.new(radius, radius, radius))
local minbpos = {}
local maxbpos = {}
for _, coord in ipairs({"x","y","z"}) do
minbpos[coord] = math.floor(minpos[coord] / 16) * 16
maxbpos[coord] = math.floor(maxpos[coord] / 16) * 16
end
local flposes = {}
for x = minbpos.x, maxbpos.x, 16 do
for y = minbpos.y, maxbpos.y, 16 do
for z = minbpos.z, maxbpos.z, 16 do
table.insert(flposes, vector.new(x, y, z))
end
end
end
return flposes
end
local function currently_forceloaded_positions(meta)
local ser = meta:get_string("forceloaded")
return ser == "" and {} or minetest.deserialize(ser)
end
local function forceload_off(meta)
local flposes = currently_forceloaded_positions(meta)
meta:set_string("forceloaded", "")
for _, p in ipairs(flposes) do
minetest.forceload_free_block(p)
end
end
local function forceload_on(pos, meta)
local want_flposes = compute_forceload_positions(pos, meta)
local have_flposes = {}
for _, p in ipairs(want_flposes) do
if minetest.forceload_block(p) then
table.insert(have_flposes, p)
end
end
meta:set_string("forceloaded", #have_flposes == 0 and "" or minetest.serialize(have_flposes))
end
local function set_display(pos, meta)
local ESC = minetest.formspec_escape
meta:set_string("infotext", S(meta:get_int("enabled") ~= 0 and "%s Enabled" or "%s Disabled"):format(desc))
meta:set_string("formspec",
"size[5,3.5]"..
"item_image[0,0;1,1;technic:admin_anchor]"..
"label[1,0;"..ESC(desc).."]"..
"label[0,1;"..ESC(S("Owner:").." "..meta:get_string("owner")).."]"..
(meta:get_int("locked") == 0 and
"button[3,1;2,1;lock;"..ESC(S("Unlocked")).."]" or
"button[3,1;2,1;unlock;"..ESC(S("Locked")).."]")..
"field[0.25,2.3;1,1;radius;"..ESC(S("Radius:"))..";"..meta:get_int("radius").."]"..
(meta:get_int("enabled") == 0 and
"button[3,2;2,1;enable;"..ESC(S("Disabled")).."]" or
"button[3,2;2,1;disable;"..ESC(S("Enabled")).."]")..
"label[0,3;"..ESC(S("Keeping %d/%d map blocks loaded"):format(
#currently_forceloaded_positions(meta), #compute_forceload_positions(pos, meta)
)).."]")
end
minetest.register_node("technic:admin_anchor", {
description = desc,
drawtype = "normal",
tiles = {"technic_admin_anchor.png"},
is_ground_content = true,
groups = {cracky=3, not_in_creative_inventory=1},
sounds = default.node_sound_stone_defaults(),
after_place_node = function (pos, placer)
local meta = minetest.get_meta(pos)
if placer and placer:is_player() then
meta:set_string("owner", placer:get_player_name())
end
set_display(pos, meta)
end,
can_dig = function (pos, player)
local meta = minetest.get_meta(pos)
return meta:get_int("locked") == 0 or
(player and player:is_player() and player:get_player_name() == meta:get_string("owner"))
end,
on_destruct = function (pos)
local meta = minetest.get_meta(pos)
forceload_off(meta)
end,
on_receive_fields = function (pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
if (meta:get_int("locked") ~= 0 or fields.lock) and
not (sender and sender:is_player() and
sender:get_player_name() == meta:get_string("owner")) then
return
end
if fields.unlock then meta:set_int("locked", 0) end
if fields.lock then meta:set_int("locked", 1) end
if fields.disable or fields.enable or fields.radius then
forceload_off(meta)
if fields.disable then meta:set_int("enabled", 0) end
if fields.enable then meta:set_int("enabled", 1) end
if fields.radius
and string.find(fields.radius, "^[0-9]+$")
and tonumber(fields.radius) < 256 then
meta:set_int("radius", fields.radius)
end
if meta:get_int("enabled") ~= 0 then
forceload_on(pos, meta)
end
end
set_display(pos, meta)
end,
})