summaryrefslogtreecommitdiff
path: root/mesecons
diff options
context:
space:
mode:
authorJeija <norrepli@gmail.com>2016-02-19 12:11:38 +0100
committerJeija <norrepli@gmail.com>2016-02-19 12:11:38 +0100
commitcfd4f7c287543f7f14d05e90c106fc14a4be8666 (patch)
tree3f922f979bea4daa8c13a5d91e59199c43811984 /mesecons
parentf099b43e1127c46df0e7e4655ddefd8910c570ef (diff)
downloadmesecons-cfd4f7c287543f7f14d05e90c106fc14a4be8666.tar
mesecons-cfd4f7c287543f7f14d05e90c106fc14a4be8666.tar.gz
mesecons-cfd4f7c287543f7f14d05e90c106fc14a4be8666.tar.bz2
mesecons-cfd4f7c287543f7f14d05e90c106fc14a4be8666.tar.xz
mesecons-cfd4f7c287543f7f14d05e90c106fc14a4be8666.zip
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.
Diffstat (limited to 'mesecons')
-rw-r--r--mesecons/actionqueue.lua21
-rw-r--r--mesecons/internal.lua62
-rw-r--r--mesecons/util.lua72
3 files changed, 116 insertions, 39 deletions
diff --git a/mesecons/actionqueue.lua b/mesecons/actionqueue.lua
index a773008..e300ea7 100644
--- a/mesecons/actionqueue.lua
+++ b/mesecons/actionqueue.lua
@@ -94,25 +94,8 @@ end
-- Store and read the ActionQueue to / from a file
-- so that upcoming actions are remembered when the game
-- is restarted
-
-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")
+mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
minetest.register_on_shutdown(function()
- mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions)
+ mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
end)
diff --git a/mesecons/internal.lua b/mesecons/internal.lua
index 41c5c52..fc1cf8d 100644
--- a/mesecons/internal.lua
+++ b/mesecons/internal.lua
@@ -77,6 +77,8 @@ function mesecon.get_conductor(nodename)
end
function mesecon.get_any_outputrules (node)
+ if not node then return nil end
+
if mesecon.is_conductor(node.name) then
return mesecon.conductor_get_rules(node)
elseif mesecon.is_receptor(node.name) then
@@ -85,6 +87,8 @@ function mesecon.get_any_outputrules (node)
end
function mesecon.get_any_inputrules (node)
+ if not node then return nil end
+
if mesecon.is_conductor(node.name) then
return mesecon.conductor_get_rules(node)
elseif mesecon.is_effector(node.name) then
@@ -182,7 +186,9 @@ end
-- Activation:
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)
if effector and effector.action_on then
@@ -203,7 +209,9 @@ end
-- Deactivation
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)
if effector and effector.action_off then
@@ -224,7 +232,9 @@ end
-- Change
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)
if effector and effector.action_change then
@@ -249,6 +259,8 @@ end
-- Conductors
function mesecon.is_conductor_on(node, rulename)
+ if not node then return false end
+
local conductor = mesecon.get_conductor(node.name)
if conductor then
if conductor.state then
@@ -263,10 +275,13 @@ function mesecon.is_conductor_on(node, rulename)
return mesecon.get_bit(binstate, bit)
end
end
+
return false
end
function mesecon.is_conductor_off(node, rulename)
+ if not node then return false end
+
local conductor = mesecon.get_conductor(node.name)
if conductor then
if conductor.state then
@@ -281,6 +296,7 @@ function mesecon.is_conductor_off(node, rulename)
return not mesecon.get_bit(binstate, bit)
end
end
+
return false
end
@@ -340,7 +356,7 @@ end
-- some more general high-level stuff
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
return true
end
@@ -348,7 +364,7 @@ function mesecon.is_power_on(pos, rulename)
end
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
return true
end
@@ -361,10 +377,11 @@ function mesecon.turnon(pos, link)
local depth = 1
while frontiers[depth] do
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
if not node then
+ print("Mesecons: Postponing action!")
mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true)
elseif mesecon.is_conductor_off(node, f.link) then
local rules = mesecon.conductor_get_rules(node)
@@ -377,7 +394,7 @@ function mesecon.turnon(pos, link)
local np = vector.add(f.pos, r)
-- 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},
nil, true)
else
@@ -407,7 +424,7 @@ function mesecon.turnoff(pos, link)
local depth = 1
while frontiers[depth] do
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
if not node then
@@ -423,7 +440,7 @@ function mesecon.turnoff(pos, link)
local np = vector.add(f.pos, r)
-- 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},
nil, true)
else
@@ -449,7 +466,8 @@ end)
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
local rules = mesecon.get_any_inputrules(node)
@@ -476,7 +494,7 @@ function mesecon.find_receptor_on(pos, link)
local depth = 1
while frontiers[depth] do
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 mesecon.is_receptor_on(node.name) then return true end
@@ -503,8 +521,9 @@ function mesecon.find_receptor_on(pos, link)
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
- local outputnode = minetest.get_node(output)
- local inputnode = minetest.get_node(input)
+ local outputnode = mesecon.get_node_force(output)
+ local inputnode = mesecon.get_node_force(input)
+
local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode)
local inputrules = mesecon.get_any_inputrules (inputnode)
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
+
return false
end
function mesecon.rules_link_rule_all(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)
if not inputrules then
return {}
@@ -540,13 +560,14 @@ function mesecon.rules_link_rule_all(output, rule)
table.insert(rules, inputrule)
end
end
+
return rules
end
function mesecon.rules_link_rule_all_inverted(input, rule)
--local irule = mesecon.invertRule(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)
if not outputrules then
return {}
@@ -566,7 +587,7 @@ function mesecon.rules_link_anydir(pos1, pos2)
end
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)
if not rules then return false end
@@ -578,9 +599,10 @@ function mesecon.is_powered(pos, rule)
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
for _, rname in ipairs(rulenames) do
local np = vector.add(pos, rname)
- local nn = minetest.get_node(np)
- if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
- or mesecon.is_receptor_on (nn.name)) then
+ local nn = mesecon.get_node_force(np)
+
+ if (mesecon.is_conductor_on(nn, mesecon.invertRule(rname))
+ or mesecon.is_receptor_on(nn.name)) then
table.insert(sourcepos, np)
end
end
@@ -589,7 +611,7 @@ function mesecon.is_powered(pos, rule)
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
for _, rname in ipairs(rulenames) do
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))
or mesecon.is_receptor_on (nn.name)) then
table.insert(sourcepos, np)
diff --git a/mesecons/util.lua b/mesecons/util.lua
index e7b6866..3827dce 100644
--- a/mesecons/util.lua
+++ b/mesecons/util.lua
@@ -201,3 +201,75 @@ function mesecon.flipstate(pos, node)
return newstate
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)