Administrative world anchor

This commit is contained in:
Zefram 2014-08-13 19:07:53 +01:00
parent 38e85e9775
commit b001a67979
8 changed files with 198 additions and 0 deletions

View File

@ -725,6 +725,62 @@ the electrical system which is 100% efficient in moving energy around.
To transfer more than 10000 EU/s between networks, connect multiple
supply converters in parallel.
administrative world anchor
---------------------------
A world anchor is an object in the Minetest world that causes the server
to keep surrounding parts of the world running even when no players
are nearby. It is mainly used to allow machines to run unattended:
normally machines are suspended when not near a player. The technic
mod supplies a form of world anchor, as a placable block, but it is not
straightforwardly available to players. There is no recipe for it, so it
is only available if explicitly spawned into existence by someone with
administrative privileges. In a single-player world, the single player
normally has administrative privileges, and can obtain a world anchor
by entering the chat command "/give singleplayer technic:admin\_anchor".
The world anchor tries to force a cubical area, centred upon the anchor,
to stay loaded. The distance from the anchor to the most distant map
nodes that it will keep loaded is referred to as the "radius", and can be
set in the world anchor's interaction form. The radius can be set as low
as 0, meaning that the anchor only tries to keep itself loaded, or as high
as 255, meaning that it will operate on a 511×511×511 cube.
Larger radii are forbidden, to avoid typos causing the server excessive
work; to keep a larger area loaded, use multiple anchors. Also use
multiple anchors if the area to be kept loaded is not well approximated
by a cube.
The world is always kept loaded in units of 16×16×16 cubes,
confusingly known as "map blocks". The anchor's configured radius takes
no account of map block boundaries, but the anchor's effect is actually to
keep loaded each map block that contains any part of the configured cube.
The anchor's interaction form includes a status note showing how many map
blocks this is, and how many of those it is successfully keeping loaded.
When the anchor is disabled, as it is upon placement, it will always
show that it is keeping no map blocks loaded; this does not indicate
any kind of failure.
The world anchor can optionally be locked. When it is locked, only
the anchor's owner, the player who placed it, can reconfigure it or
remove it. Only the owner can lock it. Locking an anchor is useful
if the use of anchors is being tightly controlled by administrators:
an administrator can set up a locked anchor and be sure that it will
not be set by ordinary players to an unapproved configuration.
The server limits the ability of world anchors to keep parts of the world
loaded, to avoid overloading the server. The total number of map blocks
that can be kept loaded in this way is set by the server configuration
item "max\_forceloaded\_blocks" (in minetest.conf), which defaults to
only 16. For comparison, each player normally keeps 125 map blocks loaded
(a radius of 32). If an enabled world anchor shows that it is failing to
keep all the map blocks loaded that it would like to, this can be fixed
by increasing max\_forceloaded\_blocks by the amount of the shortfall.
The tight limit on force-loading is the reason why the world anchor is
not directly available to players. With the limit so low both by default
and in common practice, the only feasible way to determine where world
anchors should be used is for administrators to decide it directly.
subjects missing from this manual
---------------------------------

View File

@ -54,6 +54,12 @@ Out: = Raus:
Slot %d = Fach %d
Itemwise = Einzelstuecke
Stackwise = Ganzer Stapel
Owner: =
Unlocked =
Locked =
Radius: =
Enabled =
Disabled =
## Machine names
# $1: Tier
@ -92,6 +98,7 @@ Fuel-Fired Furnace = Kohle-Ofen
Wind Mill Frame = Windmuehlengeruest
Forcefield = Kraftfeld
Nuclear Reactor Rod Compartment = Brennstabfaecher
Administrative World Anchor =
## Machine-specific
# $1: Pruduced EU
@ -106,6 +113,7 @@ Production at %d%% = Produktion bei %d%%
Choose Milling Program: = Waehle ein Fraesprogramm:
Slim Elements half / normal height: = Schmale Elemente von halber / normaler Hoehe:
Current track %s = Aktueller Titel %s
Keeping %d/%d map blocks loaded =
## CNC
Cylinder = Zylinder

View File

@ -50,6 +50,12 @@ Range = Alcance
Enable/Disable = Habilitar/Deshabilitar
Itemwise =
Stackwise =
Owner: =
Unlocked =
Locked =
Radius: =
Enabled =
Disabled =
## Machine names
# $1: Tier
@ -88,6 +94,7 @@ Fuel-Fired Furnace = Horno a Carbon
Forcefield = Campo de Fuerza
Nuclear Reactor Rod Compartment = Compartimiento para Vara de Reactor Nuclear
Wind Mill Frame = Armazon de Molino de Viento
Administrative World Anchor =
## Machine-specific
# $1: Pruduced EU
@ -100,6 +107,7 @@ Power level = Nivel de Poder
%s. Supply: %d Demand: %d = %s. Alimentacion: %d Demanda: %d
# $1: Production percent
Production at %d%% = Produccion en %d%%
Keeping %d/%d map blocks loaded =
## CNC Machine
Element Edge = Elemento Borde

View File

@ -51,6 +51,12 @@ Out: = Uscita:
Slot %d =
Itemwise = Singolo elemento
Stackwise = pila completa
Owner: =
Unlocked =
Locked =
Radius: =
Enabled =
Disabled =
## Machine names
# $1: Tier
@ -89,6 +95,7 @@ Fuel-Fired Furnace = Fornace a carbone
Wind Mill Frame = Pala eolica
Forcefield = Campo di forza
Nuclear Reactor Rod Compartment = Compartimento combustibile nucleare
Administrative World Anchor =
## Machine-specific
# $1: Pruduced EU
@ -103,6 +110,7 @@ Production at %d%% = Produzione a %d%%
Choose Milling Program: = Scegliere un programma di Fresatura
Slim Elements half / normal height: = Metà elementi sottili / altezza normale:
Current track %s = Traccia corrente %s
Keeping %d/%d map blocks loaded =
## CNC
Cylinder = Cilindro

View File

@ -58,6 +58,12 @@ Itemwise =
Stackwise =
Ignoring Mesecon Signal =
Controlled by Mesecon Signal =
Owner: =
Unlocked =
Locked =
Radius: =
Enabled =
Disabled =
## Machine names
# $1: Tier
@ -97,6 +103,7 @@ Fuel-Fired Furnace =
Wind Mill Frame =
Forcefield =
Nuclear Reactor Rod Compartment =
Administrative World Anchor =
## Machine-specific
# $1: Pruduced EU
@ -111,6 +118,7 @@ Production at %d%% =
Choose Milling Program: =
Slim Elements half / normal height: =
Current track %s =
Keeping %d/%d map blocks loaded =
## CNC
Cylinder =

View File

@ -0,0 +1,109 @@
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)
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;"..minetest.formspec_escape(desc).."]"..
"label[0,1;"..minetest.formspec_escape(S("Owner:").." "..meta:get_string("owner")).."]"..
(meta:get_int("locked") == 0 and
"button[3,1;2,1;lock;"..minetest.formspec_escape(S("Unlocked")).."]" or
"button[3,1;2,1;unlock;"..minetest.formspec_escape(S("Locked")).."]")..
"field[0.25,2.3;1,1;radius;"..minetest.formspec_escape(S("Radius:"))..";"..meta:get_int("radius").."]"..
(meta:get_int("enabled") == 0 and
"button[3,2;2,1;enable;"..minetest.formspec_escape(S("Disabled")).."]" or
"button[3,2;2,1;disable;"..minetest.formspec_escape(S("Enabled")).."]")..
"label[0,3;"..minetest.formspec_escape(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},
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,
})

View File

@ -6,3 +6,4 @@ dofile(path.."/constructor.lua")
if minetest.get_modpath("mesecons_mvps") ~= nil then
dofile(path.."/frames.lua")
end
dofile(path.."/anchor.lua")

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B