forked from Mirrorlandia_minetest/mesecons
Force-load areas with mesecon usage
This is a major speedup for large mesecon machines / structures. Force-loaded areas are stored in a file to be persistent over server reboots. By default, areas are unloaded after 10 minutes (600s) without usage, this can be customized with the mesecon.forceload_timeout setting. Please turn max_forceloaded_blocks up for better performance.
This commit is contained in:
parent
f099b43e11
commit
cfd4f7c287
@ -94,25 +94,8 @@ end
|
|||||||
-- Store and read the ActionQueue to / from a file
|
-- Store and read the ActionQueue to / from a file
|
||||||
-- so that upcoming actions are remembered when the game
|
-- so that upcoming actions are remembered when the game
|
||||||
-- is restarted
|
-- is restarted
|
||||||
|
mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
|
||||||
local wpath = minetest.get_worldpath()
|
|
||||||
local function file2table(filename)
|
|
||||||
local f = io.open(filename, "r")
|
|
||||||
if f==nil then return {} end
|
|
||||||
local t = f:read("*all")
|
|
||||||
f:close()
|
|
||||||
if t=="" or t==nil then return {} end
|
|
||||||
return minetest.deserialize(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function table2file(filename, table)
|
|
||||||
local f = io.open(filename, "w")
|
|
||||||
f:write(minetest.serialize(table))
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
mesecon.queue.actions = file2table(wpath.."/mesecon_actionqueue")
|
|
||||||
|
|
||||||
minetest.register_on_shutdown(function()
|
minetest.register_on_shutdown(function()
|
||||||
mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions)
|
mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
|
||||||
end)
|
end)
|
||||||
|
@ -77,6 +77,8 @@ function mesecon.get_conductor(nodename)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.get_any_outputrules (node)
|
function mesecon.get_any_outputrules (node)
|
||||||
|
if not node then return nil end
|
||||||
|
|
||||||
if mesecon.is_conductor(node.name) then
|
if mesecon.is_conductor(node.name) then
|
||||||
return mesecon.conductor_get_rules(node)
|
return mesecon.conductor_get_rules(node)
|
||||||
elseif mesecon.is_receptor(node.name) then
|
elseif mesecon.is_receptor(node.name) then
|
||||||
@ -85,6 +87,8 @@ function mesecon.get_any_outputrules (node)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.get_any_inputrules (node)
|
function mesecon.get_any_inputrules (node)
|
||||||
|
if not node then return nil end
|
||||||
|
|
||||||
if mesecon.is_conductor(node.name) then
|
if mesecon.is_conductor(node.name) then
|
||||||
return mesecon.conductor_get_rules(node)
|
return mesecon.conductor_get_rules(node)
|
||||||
elseif mesecon.is_effector(node.name) then
|
elseif mesecon.is_effector(node.name) then
|
||||||
@ -182,7 +186,9 @@ end
|
|||||||
|
|
||||||
-- Activation:
|
-- Activation:
|
||||||
mesecon.queue:add_function("activate", function (pos, rulename)
|
mesecon.queue:add_function("activate", function (pos, rulename)
|
||||||
local node = minetest.get_node(pos)
|
local node = mesecon.get_node_force(pos)
|
||||||
|
if not node then return end
|
||||||
|
|
||||||
local effector = mesecon.get_effector(node.name)
|
local effector = mesecon.get_effector(node.name)
|
||||||
|
|
||||||
if effector and effector.action_on then
|
if effector and effector.action_on then
|
||||||
@ -203,7 +209,9 @@ end
|
|||||||
|
|
||||||
-- Deactivation
|
-- Deactivation
|
||||||
mesecon.queue:add_function("deactivate", function (pos, rulename)
|
mesecon.queue:add_function("deactivate", function (pos, rulename)
|
||||||
local node = minetest.get_node(pos)
|
local node = mesecon.get_node_force(pos)
|
||||||
|
if not node then return end
|
||||||
|
|
||||||
local effector = mesecon.get_effector(node.name)
|
local effector = mesecon.get_effector(node.name)
|
||||||
|
|
||||||
if effector and effector.action_off then
|
if effector and effector.action_off then
|
||||||
@ -224,7 +232,9 @@ end
|
|||||||
|
|
||||||
-- Change
|
-- Change
|
||||||
mesecon.queue:add_function("change", function (pos, rulename, changetype)
|
mesecon.queue:add_function("change", function (pos, rulename, changetype)
|
||||||
local node = minetest.get_node(pos)
|
local node = mesecon.get_node_force(pos)
|
||||||
|
if not node then return end
|
||||||
|
|
||||||
local effector = mesecon.get_effector(node.name)
|
local effector = mesecon.get_effector(node.name)
|
||||||
|
|
||||||
if effector and effector.action_change then
|
if effector and effector.action_change then
|
||||||
@ -249,6 +259,8 @@ end
|
|||||||
-- Conductors
|
-- Conductors
|
||||||
|
|
||||||
function mesecon.is_conductor_on(node, rulename)
|
function mesecon.is_conductor_on(node, rulename)
|
||||||
|
if not node then return false end
|
||||||
|
|
||||||
local conductor = mesecon.get_conductor(node.name)
|
local conductor = mesecon.get_conductor(node.name)
|
||||||
if conductor then
|
if conductor then
|
||||||
if conductor.state then
|
if conductor.state then
|
||||||
@ -263,10 +275,13 @@ function mesecon.is_conductor_on(node, rulename)
|
|||||||
return mesecon.get_bit(binstate, bit)
|
return mesecon.get_bit(binstate, bit)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.is_conductor_off(node, rulename)
|
function mesecon.is_conductor_off(node, rulename)
|
||||||
|
if not node then return false end
|
||||||
|
|
||||||
local conductor = mesecon.get_conductor(node.name)
|
local conductor = mesecon.get_conductor(node.name)
|
||||||
if conductor then
|
if conductor then
|
||||||
if conductor.state then
|
if conductor.state then
|
||||||
@ -281,6 +296,7 @@ function mesecon.is_conductor_off(node, rulename)
|
|||||||
return not mesecon.get_bit(binstate, bit)
|
return not mesecon.get_bit(binstate, bit)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -340,7 +356,7 @@ end
|
|||||||
-- some more general high-level stuff
|
-- some more general high-level stuff
|
||||||
|
|
||||||
function mesecon.is_power_on(pos, rulename)
|
function mesecon.is_power_on(pos, rulename)
|
||||||
local node = minetest.get_node(pos)
|
local node = mesecon.get_node_force(pos)
|
||||||
if mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name) then
|
if mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -348,7 +364,7 @@ function mesecon.is_power_on(pos, rulename)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.is_power_off(pos, rulename)
|
function mesecon.is_power_off(pos, rulename)
|
||||||
local node = minetest.get_node(pos)
|
local node = mesecon.get_node_force(pos)
|
||||||
if mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name) then
|
if mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -361,10 +377,11 @@ function mesecon.turnon(pos, link)
|
|||||||
local depth = 1
|
local depth = 1
|
||||||
while frontiers[depth] do
|
while frontiers[depth] do
|
||||||
local f = frontiers[depth]
|
local f = frontiers[depth]
|
||||||
local node = minetest.get_node_or_nil(f.pos)
|
local node = mesecon.get_node_force(f.pos)
|
||||||
|
|
||||||
-- area not loaded, postpone action
|
-- area not loaded, postpone action
|
||||||
if not node then
|
if not node then
|
||||||
|
print("Mesecons: Postponing action!")
|
||||||
mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true)
|
mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true)
|
||||||
elseif mesecon.is_conductor_off(node, f.link) then
|
elseif mesecon.is_conductor_off(node, f.link) then
|
||||||
local rules = mesecon.conductor_get_rules(node)
|
local rules = mesecon.conductor_get_rules(node)
|
||||||
@ -377,7 +394,7 @@ function mesecon.turnon(pos, link)
|
|||||||
local np = vector.add(f.pos, r)
|
local np = vector.add(f.pos, r)
|
||||||
|
|
||||||
-- area not loaded, postpone action
|
-- area not loaded, postpone action
|
||||||
if not minetest.get_node_or_nil(np) then
|
if not mesecon.get_node_force(np) then
|
||||||
mesecon.queue:add_action(np, "turnon", {rulename},
|
mesecon.queue:add_action(np, "turnon", {rulename},
|
||||||
nil, true)
|
nil, true)
|
||||||
else
|
else
|
||||||
@ -407,7 +424,7 @@ function mesecon.turnoff(pos, link)
|
|||||||
local depth = 1
|
local depth = 1
|
||||||
while frontiers[depth] do
|
while frontiers[depth] do
|
||||||
local f = frontiers[depth]
|
local f = frontiers[depth]
|
||||||
local node = minetest.get_node_or_nil(f.pos)
|
local node = mesecon.get_node_force(f.pos)
|
||||||
|
|
||||||
-- area not loaded, postpone action
|
-- area not loaded, postpone action
|
||||||
if not node then
|
if not node then
|
||||||
@ -423,7 +440,7 @@ function mesecon.turnoff(pos, link)
|
|||||||
local np = vector.add(f.pos, r)
|
local np = vector.add(f.pos, r)
|
||||||
|
|
||||||
-- area not loaded, postpone action
|
-- area not loaded, postpone action
|
||||||
if not minetest.get_node_or_nil(np) then
|
if not mesecon.get_node_force(np) then
|
||||||
mesecon.queue:add_action(np, "turnoff", {rulename},
|
mesecon.queue:add_action(np, "turnoff", {rulename},
|
||||||
nil, true)
|
nil, true)
|
||||||
else
|
else
|
||||||
@ -449,7 +466,8 @@ end)
|
|||||||
|
|
||||||
|
|
||||||
function mesecon.connected_to_receptor(pos, link)
|
function mesecon.connected_to_receptor(pos, link)
|
||||||
local node = minetest.get_node(pos)
|
local node = mesecon.get_node_force(pos)
|
||||||
|
if not node then return false end
|
||||||
|
|
||||||
-- Check if conductors around are connected
|
-- Check if conductors around are connected
|
||||||
local rules = mesecon.get_any_inputrules(node)
|
local rules = mesecon.get_any_inputrules(node)
|
||||||
@ -476,7 +494,7 @@ function mesecon.find_receptor_on(pos, link)
|
|||||||
local depth = 1
|
local depth = 1
|
||||||
while frontiers[depth] do
|
while frontiers[depth] do
|
||||||
local f = frontiers[depth]
|
local f = frontiers[depth]
|
||||||
local node = minetest.get_node_or_nil(f.pos)
|
local node = mesecon.get_node_force(f.pos)
|
||||||
|
|
||||||
if not node then return false end
|
if not node then return false end
|
||||||
if mesecon.is_receptor_on(node.name) then return true end
|
if mesecon.is_receptor_on(node.name) then return true end
|
||||||
@ -503,8 +521,9 @@ function mesecon.find_receptor_on(pos, link)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule
|
function mesecon.rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule
|
||||||
local outputnode = minetest.get_node(output)
|
local outputnode = mesecon.get_node_force(output)
|
||||||
local inputnode = minetest.get_node(input)
|
local inputnode = mesecon.get_node_force(input)
|
||||||
|
|
||||||
local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode)
|
local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode)
|
||||||
local inputrules = mesecon.get_any_inputrules (inputnode)
|
local inputrules = mesecon.get_any_inputrules (inputnode)
|
||||||
if not outputrules or not inputrules then
|
if not outputrules or not inputrules then
|
||||||
@ -522,12 +541,13 @@ function mesecon.rules_link(output, input, dug_outputrules) --output/input are p
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.rules_link_rule_all(output, rule)
|
function mesecon.rules_link_rule_all(output, rule)
|
||||||
local input = vector.add(output, rule)
|
local input = vector.add(output, rule)
|
||||||
local inputnode = minetest.get_node(input)
|
local inputnode = mesecon.get_node_force(input)
|
||||||
local inputrules = mesecon.get_any_inputrules (inputnode)
|
local inputrules = mesecon.get_any_inputrules (inputnode)
|
||||||
if not inputrules then
|
if not inputrules then
|
||||||
return {}
|
return {}
|
||||||
@ -540,13 +560,14 @@ function mesecon.rules_link_rule_all(output, rule)
|
|||||||
table.insert(rules, inputrule)
|
table.insert(rules, inputrule)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return rules
|
return rules
|
||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.rules_link_rule_all_inverted(input, rule)
|
function mesecon.rules_link_rule_all_inverted(input, rule)
|
||||||
--local irule = mesecon.invertRule(rule)
|
--local irule = mesecon.invertRule(rule)
|
||||||
local output = vector.add(input, rule)
|
local output = vector.add(input, rule)
|
||||||
local outputnode = minetest.get_node(output)
|
local outputnode = mesecon.get_node_force(output)
|
||||||
local outputrules = mesecon.get_any_outputrules (outputnode)
|
local outputrules = mesecon.get_any_outputrules (outputnode)
|
||||||
if not outputrules then
|
if not outputrules then
|
||||||
return {}
|
return {}
|
||||||
@ -566,7 +587,7 @@ function mesecon.rules_link_anydir(pos1, pos2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.is_powered(pos, rule)
|
function mesecon.is_powered(pos, rule)
|
||||||
local node = minetest.get_node(pos)
|
local node = mesecon.get_node_force(pos)
|
||||||
local rules = mesecon.get_any_inputrules(node)
|
local rules = mesecon.get_any_inputrules(node)
|
||||||
if not rules then return false end
|
if not rules then return false end
|
||||||
|
|
||||||
@ -578,7 +599,8 @@ function mesecon.is_powered(pos, rule)
|
|||||||
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
|
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
|
||||||
for _, rname in ipairs(rulenames) do
|
for _, rname in ipairs(rulenames) do
|
||||||
local np = vector.add(pos, rname)
|
local np = vector.add(pos, rname)
|
||||||
local nn = minetest.get_node(np)
|
local nn = mesecon.get_node_force(np)
|
||||||
|
|
||||||
if (mesecon.is_conductor_on(nn, mesecon.invertRule(rname))
|
if (mesecon.is_conductor_on(nn, mesecon.invertRule(rname))
|
||||||
or mesecon.is_receptor_on(nn.name)) then
|
or mesecon.is_receptor_on(nn.name)) then
|
||||||
table.insert(sourcepos, np)
|
table.insert(sourcepos, np)
|
||||||
@ -589,7 +611,7 @@ function mesecon.is_powered(pos, rule)
|
|||||||
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
|
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
|
||||||
for _, rname in ipairs(rulenames) do
|
for _, rname in ipairs(rulenames) do
|
||||||
local np = vector.add(pos, rname)
|
local np = vector.add(pos, rname)
|
||||||
local nn = minetest.get_node(np)
|
local nn = mesecon.get_node_force(np)
|
||||||
if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
|
if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
|
||||||
or mesecon.is_receptor_on (nn.name)) then
|
or mesecon.is_receptor_on (nn.name)) then
|
||||||
table.insert(sourcepos, np)
|
table.insert(sourcepos, np)
|
||||||
|
@ -201,3 +201,75 @@ function mesecon.flipstate(pos, node)
|
|||||||
|
|
||||||
return newstate
|
return newstate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- File writing / reading utilities
|
||||||
|
local wpath = minetest.get_worldpath()
|
||||||
|
function mesecon.file2table(filename)
|
||||||
|
local f = io.open(wpath..DIR_DELIM..filename, "r")
|
||||||
|
if f == nil then return {} end
|
||||||
|
local t = f:read("*all")
|
||||||
|
f:close()
|
||||||
|
if t == "" or t == nil then return {} end
|
||||||
|
return minetest.deserialize(t)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mesecon.table2file(filename, table)
|
||||||
|
local f = io.open(wpath..DIR_DELIM..filename, "w")
|
||||||
|
f:write(minetest.serialize(table))
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Forceloading: Force server to load area if node is nil
|
||||||
|
local BLOCKSIZE = 16
|
||||||
|
|
||||||
|
-- convert node position --> block hash
|
||||||
|
local function hash_blockpos(pos)
|
||||||
|
return minetest.hash_node_position({
|
||||||
|
x = math.floor(pos.x/BLOCKSIZE),
|
||||||
|
y = math.floor(pos.y/BLOCKSIZE),
|
||||||
|
z = math.floor(pos.z/BLOCKSIZE)
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- convert block hash --> node position
|
||||||
|
local function unhash_blockpos(hash)
|
||||||
|
return vector.multiply(minetest.get_position_from_hash(hash), BLOCKSIZE)
|
||||||
|
end
|
||||||
|
|
||||||
|
mesecon.forceloaded_blocks = {}
|
||||||
|
|
||||||
|
-- get node and force-load area
|
||||||
|
function mesecon.get_node_force(pos)
|
||||||
|
local hash = hash_blockpos(pos)
|
||||||
|
|
||||||
|
if mesecon.forceloaded_blocks[hash] == nil then
|
||||||
|
-- if no more forceload spaces are available, try again next time
|
||||||
|
if minetest.forceload_block(pos) then
|
||||||
|
mesecon.forceloaded_blocks[hash] = 0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mesecon.forceloaded_blocks[hash] = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return minetest.get_node_or_nil(pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_globalstep(function (dtime)
|
||||||
|
for hash, time in pairs(mesecon.forceloaded_blocks) do
|
||||||
|
-- unload forceloaded blocks after 10 minutes without usage
|
||||||
|
if (time > mesecon.setting("forceload_timeout", 600)) then
|
||||||
|
minetest.forceload_free_block(unhash_blockpos(hash))
|
||||||
|
mesecon.forceloaded_blocks[hash] = nil
|
||||||
|
else
|
||||||
|
mesecon.forceloaded_blocks[hash] = time + dtime
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Store and read the forceloaded blocks to / from a file
|
||||||
|
-- so that those blocks are remembered when the game
|
||||||
|
-- is restarted
|
||||||
|
mesecon.forceloaded_blocks = mesecon.file2table("mesecon_forceloaded")
|
||||||
|
minetest.register_on_shutdown(function()
|
||||||
|
mesecon.table2file("mesecon_forceloaded", mesecon.forceloaded_blocks)
|
||||||
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user