From c3627551b091d27819c242da204ed1e9dd8f15f0 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 30 Sep 2017 23:42:26 +0100 Subject: move all current new_flow_logic code to dedicated sub-directory --- new_flow_logic/abms.lua | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 new_flow_logic/abms.lua (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua new file mode 100644 index 0000000..7360668 --- /dev/null +++ b/new_flow_logic/abms.lua @@ -0,0 +1,123 @@ +-- reimplementation of new_flow_logic branch: processing functions +-- written 2017 by thetaepsilon + + + +local flowlogic = {} +pipeworks.flowlogic = flowlogic + + + +-- borrowed from above: might be useable to replace the above coords tables +local make_coords_offsets = function(pos, include_base) + local coords = { + {x=pos.x,y=pos.y-1,z=pos.z}, + {x=pos.x,y=pos.y+1,z=pos.z}, + {x=pos.x-1,y=pos.y,z=pos.z}, + {x=pos.x+1,y=pos.y,z=pos.z}, + {x=pos.x,y=pos.y,z=pos.z-1}, + {x=pos.x,y=pos.y,z=pos.z+1}, + } + if include_base then table.insert(coords, pos) end + return coords +end + + + +-- local debuglog = function(msg) print("## "..msg) end + + + +-- new version of liquid check +-- accepts a limit parameter to only delete water blocks that the receptacle can accept, +-- and returns it so that the receptacle can update it's pressure values. +-- this should ensure that water blocks aren't vanished from existance. +-- will take care of zero or negative-valued limits. +local check_for_liquids_v2 = function(pos, limit) + if not limit then + limit = 6 + end + local coords = make_coords_offsets(pos, false) + local total = 0 + for index, tpos in ipairs(coords) do + if total >= limit then break end + local name = minetest.get_node(tpos).name + if name == "default:water_source" then + minetest.remove_node(tpos) + total = total + 1 + end + end + return total +end +flowlogic.check_for_liquids_v2 = check_for_liquids_v2 + + + +local label_pressure = "pipeworks.water_pressure" +local label_haspressure = "pipeworks.is_pressure_node" +flowlogic.balance_pressure = function(pos, node) + -- debuglog("balance_pressure() "..node.name.." at "..pos.x.." "..pos.y.." "..pos.z) + -- check the pressure of all nearby nodes, and average it out. + -- for the moment, only balance neighbour nodes if it already has a pressure value. + -- XXX: maybe this could be used to add fluid behaviour to other mod's nodes too? + + -- unconditionally include self in nodes to average over + local meta = minetest.get_meta(pos) + local currentpressure = meta:get_float(label_pressure) + meta:set_int(label_haspressure, 1) + local connections = { meta } + local totalv = currentpressure + local totalc = 1 + + -- then handle neighbours, but if not a pressure node don't consider them at all + for _, npos in ipairs(make_coords_offsets(pos, false)) do + local neighbour = minetest.get_meta(npos) + local haspressure = (neighbour:get_int(label_haspressure) ~= 0) + if haspressure then + local n = neighbour:get_float(label_pressure) + table.insert(connections, neighbour) + totalv = totalv + n + totalc = totalc + 1 + end + end + + local average = totalv / totalc + for _, targetmeta in ipairs(connections) do + targetmeta:set_float(label_pressure, average) + end +end + + + +flowlogic.run_pump_intake = function(pos, node) + -- try to absorb nearby water nodes, but only up to limit. + -- NB: check_for_liquids_v2 handles zero or negative from the following subtraction + + local properties = pipeworks.flowables.inputs.list[node.name] + local maxpressure = properties.maxpressure + + local meta = minetest.get_meta(pos) + local currentpressure = meta:get_float(label_pressure) + + local intake_limit = maxpressure - currentpressure + local actual_intake = check_for_liquids_v2(pos, intake_limit) + local newpressure = actual_intake + currentpressure + -- debuglog("oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake.." newpressure "..newpressure) + meta:set_float(label_pressure, newpressure) +end + + + +flowlogic.run_spigot_output = function(pos, node) + -- try to output a water source node if there's enough pressure and space below. + local meta = minetest.get_meta(pos) + local currentpressure = meta:get_float(label_pressure) + if currentpressure > 1 then + local below = {x=pos.x, y=pos.y-1, z=pos.z} + local name = minetest.get_node(below).name + if (name == "air") or (name == "default:water_flowing") then + minetest.set_node(below, {name="default:water_source"}) + meta:set_float(label_pressure, currentpressure - 1) + end + end +end -- cgit v1.2.3 From 31741e33e20c2ed366f80c01c7d6b4a6a23e0d4c Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 1 Oct 2017 00:00:33 +0100 Subject: new_flow_logic/abms.lua: run_pump_intake(): use passed-in maxpressure instead of table lookup, pass through in abm_register.lua --- new_flow_logic/abms.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 7360668..ece81c1 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -89,13 +89,10 @@ end -flowlogic.run_pump_intake = function(pos, node) +flowlogic.run_pump_intake = function(pos, node, maxpressure) -- try to absorb nearby water nodes, but only up to limit. -- NB: check_for_liquids_v2 handles zero or negative from the following subtraction - local properties = pipeworks.flowables.inputs.list[node.name] - local maxpressure = properties.maxpressure - local meta = minetest.get_meta(pos) local currentpressure = meta:get_float(label_pressure) -- cgit v1.2.3 From 3486ee319ee4fafbf83c583dd9fedfaed92db7c4 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 1 Oct 2017 00:44:14 +0100 Subject: abms.lua: refactor and generalise run_pump_intake() to allow passing custom intake functions --- new_flow_logic/abms.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index ece81c1..48dcb0b 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -31,12 +31,7 @@ end -- new version of liquid check -- accepts a limit parameter to only delete water blocks that the receptacle can accept, -- and returns it so that the receptacle can update it's pressure values. --- this should ensure that water blocks aren't vanished from existance. --- will take care of zero or negative-valued limits. local check_for_liquids_v2 = function(pos, limit) - if not limit then - limit = 6 - end local coords = make_coords_offsets(pos, false) local total = 0 for index, tpos in ipairs(coords) do @@ -89,15 +84,20 @@ end -flowlogic.run_pump_intake = function(pos, node, maxpressure) - -- try to absorb nearby water nodes, but only up to limit. - -- NB: check_for_liquids_v2 handles zero or negative from the following subtraction +flowlogic.run_input = function(pos, node, maxpressure, intakefn) + -- intakefn allows a given input node to define it's own intake logic. + -- this function will calculate the maximum amount of water that can be taken in; + -- the intakefn will be given this and is expected to return the actual absorption amount. local meta = minetest.get_meta(pos) local currentpressure = meta:get_float(label_pressure) - local intake_limit = maxpressure - currentpressure - local actual_intake = check_for_liquids_v2(pos, intake_limit) + if intake_limit <= 0 then return end + + local actual_intake = intakefn(pos, intake_limit) + if actual_intake <= 0 then return end + if actual_intake >= intake_limit then actual_intake = intake_limit end + local newpressure = actual_intake + currentpressure -- debuglog("oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake.." newpressure "..newpressure) meta:set_float(label_pressure, newpressure) -- cgit v1.2.3 From 463e7a206af8e2b98617b549e3bc6dc5eb181ffc Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 1 Oct 2017 12:25:43 +0100 Subject: new flow logic: abms.lua: start splitting apart spigot code into generalised output ABM --- new_flow_logic/abms.lua | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 48dcb0b..640493a 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -4,6 +4,7 @@ local flowlogic = {} +flowlogic.helpers = {} pipeworks.flowlogic = flowlogic @@ -105,6 +106,43 @@ end +-- flowlogic output helper for spigots +-- tries to place a water block in the world beneath the spigot. +-- threshold checking is assumed to be handled by the node registration; +-- see register_local_pipes.lua for the pipeworks default spigot. +flowlogic.helpers.output_spigot = function(pos, node, currentpressure) + local taken = 0 + local below = {x=pos.x, y=pos.y-1, z=pos.z} + local name = minetest.get_node(below).name + if (name == "air") or (name == "default:water_flowing") then + minetest.set_node(below, {name="default:water_source"}) + taken = taken + 1 + end + return taken +end + + + +flowlogic.run_output = function(pos, node, threshold, outputfn) + -- callback for output devices. + -- takes care of checking a minimum pressure value and updating the node metadata. + -- the outputfn is provided the current pressure and returns the pressure "taken". + -- as an example, using this with the above spigot function, + -- the spigot function tries to output a water source if it will fit in the world. + local meta = minetest.get_meta(pos) + -- sometimes I wonder if meta:get_* returning default values would ever be problematic. + -- though here it doesn't matter, an uninit'd node returns 0, which is fine for a new, empty node. + local currentpressure = meta:get_float(label_pressure) + if currentpressure > threshold then + local takenpressure = outputfn(pos, node, currentpressure) + local newpressure = currentpressure - takenpressure + if newpressure < 0 then currentpressure = 0 end + meta:set_float(label_pressure, newpressure) + end +end + + + flowlogic.run_spigot_output = function(pos, node) -- try to output a water source node if there's enough pressure and space below. local meta = minetest.get_meta(pos) -- cgit v1.2.3 From 9abdeb3d626c702c044d6d621bdea6c43dbd6647 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 1 Oct 2017 20:12:19 +0100 Subject: new flow logic: abms.lua: use flowable nodes registry to determine viable neighbours --- new_flow_logic/abms.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 640493a..66349e9 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -49,8 +49,9 @@ flowlogic.check_for_liquids_v2 = check_for_liquids_v2 +--local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..tostring(vec.y)..sep..tostring(vec.z)..")" end + local label_pressure = "pipeworks.water_pressure" -local label_haspressure = "pipeworks.is_pressure_node" flowlogic.balance_pressure = function(pos, node) -- debuglog("balance_pressure() "..node.name.." at "..pos.x.." "..pos.y.." "..pos.z) -- check the pressure of all nearby nodes, and average it out. @@ -60,16 +61,19 @@ flowlogic.balance_pressure = function(pos, node) -- unconditionally include self in nodes to average over local meta = minetest.get_meta(pos) local currentpressure = meta:get_float(label_pressure) - meta:set_int(label_haspressure, 1) local connections = { meta } local totalv = currentpressure local totalc = 1 -- then handle neighbours, but if not a pressure node don't consider them at all for _, npos in ipairs(make_coords_offsets(pos, false)) do + local nodename = minetest.get_node(npos).name local neighbour = minetest.get_meta(npos) - local haspressure = (neighbour:get_int(label_haspressure) ~= 0) + -- for now, just check if it's in the simple table. + -- TODO: the "can flow from" logic in flowable_node_registry.lua + local haspressure = (pipeworks.flowables.list.simple[nodename]) if haspressure then + --pipeworks.logger("balance_pressure @ "..formatvec(pos).." "..nodename.." "..formatvec(npos).." added to neighbour set") local n = neighbour:get_float(label_pressure) table.insert(connections, neighbour) totalv = totalv + n -- cgit v1.2.3 From dc13ec619f7e49b0e75f845f8baa0559a8b11936 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 1 Oct 2017 20:27:30 +0100 Subject: new flow logic: abms.lua: remove intake limit coercion causing water to be vanished --- new_flow_logic/abms.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 66349e9..afeb3b3 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -29,6 +29,8 @@ end +--local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..tostring(vec.y)..sep..tostring(vec.z)..")" end + -- new version of liquid check -- accepts a limit parameter to only delete water blocks that the receptacle can accept, -- and returns it so that the receptacle can update it's pressure values. @@ -43,14 +45,13 @@ local check_for_liquids_v2 = function(pos, limit) total = total + 1 end end + --pipeworks.logger("check_for_liquids_v2@"..formatvec(pos).." total "..total) return total end flowlogic.check_for_liquids_v2 = check_for_liquids_v2 ---local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..tostring(vec.y)..sep..tostring(vec.z)..")" end - local label_pressure = "pipeworks.water_pressure" flowlogic.balance_pressure = function(pos, node) -- debuglog("balance_pressure() "..node.name.." at "..pos.x.." "..pos.y.." "..pos.z) @@ -100,8 +101,8 @@ flowlogic.run_input = function(pos, node, maxpressure, intakefn) if intake_limit <= 0 then return end local actual_intake = intakefn(pos, intake_limit) + --pipeworks.logger("run_input@"..formatvec(pos).." oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake) if actual_intake <= 0 then return end - if actual_intake >= intake_limit then actual_intake = intake_limit end local newpressure = actual_intake + currentpressure -- debuglog("oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake.." newpressure "..newpressure) -- cgit v1.2.3 From 667eeb7d095f12d5c7e560d161697878ea485433 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 1 Oct 2017 21:04:07 +0100 Subject: new flow logic: abms.lua: generalise spigot output code to support arbitary neighbour lists --- new_flow_logic/abms.lua | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index afeb3b3..a07c390 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -111,19 +111,23 @@ end --- flowlogic output helper for spigots --- tries to place a water block in the world beneath the spigot. --- threshold checking is assumed to be handled by the node registration; --- see register_local_pipes.lua for the pipeworks default spigot. -flowlogic.helpers.output_spigot = function(pos, node, currentpressure) - local taken = 0 - local below = {x=pos.x, y=pos.y-1, z=pos.z} - local name = minetest.get_node(below).name - if (name == "air") or (name == "default:water_flowing") then - minetest.set_node(below, {name="default:water_source"}) - taken = taken + 1 +-- flowlogic output helper implementation: +-- outputs water by trying to place water nodes nearby in the world. +-- neighbours is a list of node offsets to try placing water in. +-- this is a constructor function, returning another function which satisfies the output helper requirements. +flowlogic.helpers.make_neighbour_output = function(neighbours) + return function(pos, node, currentpressure) + local taken = 0 + for _, offset in pairs(neighbours) do + local npos = vector.add(pos, offset) + local name = minetest.get_node(npos).name + if (name == "air") or (name == "default:water_flowing") then + minetest.swap_node(npos, {name="default:water_source"}) + taken = taken + 1 + end + end + return taken end - return taken end @@ -145,19 +149,3 @@ flowlogic.run_output = function(pos, node, threshold, outputfn) meta:set_float(label_pressure, newpressure) end end - - - -flowlogic.run_spigot_output = function(pos, node) - -- try to output a water source node if there's enough pressure and space below. - local meta = minetest.get_meta(pos) - local currentpressure = meta:get_float(label_pressure) - if currentpressure > 1 then - local below = {x=pos.x, y=pos.y-1, z=pos.z} - local name = minetest.get_node(below).name - if (name == "air") or (name == "default:water_flowing") then - minetest.set_node(below, {name="default:water_source"}) - meta:set_float(label_pressure, currentpressure - 1) - end - end -end -- cgit v1.2.3 From 8e53526b545e2dc0a05066fb18f064a394e20740 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 1 Oct 2017 21:20:30 +0100 Subject: new flow logic: abms.lua: rename neighbour output helper to better indicate lack of rotation support --- new_flow_logic/abms.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index a07c390..15adcef 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -115,7 +115,8 @@ end -- outputs water by trying to place water nodes nearby in the world. -- neighbours is a list of node offsets to try placing water in. -- this is a constructor function, returning another function which satisfies the output helper requirements. -flowlogic.helpers.make_neighbour_output = function(neighbours) +-- note that this does *not* take rotation into account. +flowlogic.helpers.make_neighbour_output_fixed = function(neighbours) return function(pos, node, currentpressure) local taken = 0 for _, offset in pairs(neighbours) do -- cgit v1.2.3 From 6f90ee0875dd0f89f460b6ae75acac708a63cb4c Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 13:24:46 +0100 Subject: new flow logic: abms.lua: add companion cleaner helper for neighbour output --- new_flow_logic/abms.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 15adcef..7a720be 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -131,6 +131,21 @@ flowlogic.helpers.make_neighbour_output_fixed = function(neighbours) end end +-- complementary function to the above when using non-finite mode: +-- removes water sources from neighbor positions when the output is "off" due to lack of pressure. +flowlogic.helpers.make_neighbour_cleanup_fixed = function(neighbours) + return function(pos, node, currentpressure) + -- FIXME - this would indiscriminately take blocks while under-pressure, not just one time? + for _, offset in pairs(neighbours) do + local npos = vector.add(pos, offset) + local name = minetest.get_node(npos).name + if (name == "default:water_source") then + minetest.remove_node(pos) + end + end + end +end + flowlogic.run_output = function(pos, node, threshold, outputfn) -- cgit v1.2.3 From 608a9a69808ee58d05dc115b37af1d53b00f0241 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 17:14:50 +0100 Subject: new flow logic: abms.lua: wrap up pressure value accesses behind accessor object --- new_flow_logic/abms.lua | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 7a720be..9e5eb2d 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -53,6 +53,18 @@ flowlogic.check_for_liquids_v2 = check_for_liquids_v2 local label_pressure = "pipeworks.water_pressure" +local get_pressure_access = function(pos) + local metaref = minetest.get_meta(pos) + return { + get = function() + return metaref:get_float(label_pressure) + end, + set = function(v) + metaref:set_float(label_pressure, v) + end + } +end + flowlogic.balance_pressure = function(pos, node) -- debuglog("balance_pressure() "..node.name.." at "..pos.x.." "..pos.y.." "..pos.z) -- check the pressure of all nearby nodes, and average it out. @@ -60,22 +72,23 @@ flowlogic.balance_pressure = function(pos, node) -- XXX: maybe this could be used to add fluid behaviour to other mod's nodes too? -- unconditionally include self in nodes to average over - local meta = minetest.get_meta(pos) - local currentpressure = meta:get_float(label_pressure) - local connections = { meta } + local pressure = get_pressure_access(pos) + local currentpressure = pressure.get() + -- pressure handles to average over + local connections = { pressure } local totalv = currentpressure local totalc = 1 -- then handle neighbours, but if not a pressure node don't consider them at all for _, npos in ipairs(make_coords_offsets(pos, false)) do local nodename = minetest.get_node(npos).name - local neighbour = minetest.get_meta(npos) -- for now, just check if it's in the simple table. -- TODO: the "can flow from" logic in flowable_node_registry.lua local haspressure = (pipeworks.flowables.list.simple[nodename]) if haspressure then + local neighbour = get_pressure_access(npos) --pipeworks.logger("balance_pressure @ "..formatvec(pos).." "..nodename.." "..formatvec(npos).." added to neighbour set") - local n = neighbour:get_float(label_pressure) + local n = neighbour.get() table.insert(connections, neighbour) totalv = totalv + n totalc = totalc + 1 @@ -83,8 +96,8 @@ flowlogic.balance_pressure = function(pos, node) end local average = totalv / totalc - for _, targetmeta in ipairs(connections) do - targetmeta:set_float(label_pressure, average) + for _, target in ipairs(connections) do + target.set(average) end end -- cgit v1.2.3 From 016f9de82f91b61a14ad1bc477ee18b501f77e39 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 17:33:42 +0100 Subject: new flow logic: abms.lua: refactor ABM logic into new master ABM, make balance_pressure() take current pressure and return new pressure --- new_flow_logic/abms.lua | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 9e5eb2d..37b10bc 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -65,17 +65,30 @@ local get_pressure_access = function(pos) } end -flowlogic.balance_pressure = function(pos, node) + + +flowlogic.run = function(pos, node) + -- get the current pressure value. + local nodepressure = get_pressure_access(pos) + local currentpressure = nodepressure.get() + + -- balance pressure with neighbours + currentpressure = flowlogic.balance_pressure(pos, node, currentpressure) + + -- set the new pressure + nodepressure.set(currentpressure) +end + + + +flowlogic.balance_pressure = function(pos, node, currentpressure) -- debuglog("balance_pressure() "..node.name.." at "..pos.x.." "..pos.y.." "..pos.z) - -- check the pressure of all nearby nodes, and average it out. - -- for the moment, only balance neighbour nodes if it already has a pressure value. - -- XXX: maybe this could be used to add fluid behaviour to other mod's nodes too? + -- check the pressure of all nearby flowable nodes, and average it out. - -- unconditionally include self in nodes to average over - local pressure = get_pressure_access(pos) - local currentpressure = pressure.get() -- pressure handles to average over - local connections = { pressure } + local connections = {} + -- unconditionally include self in nodes to average over. + -- result of averaging will be returned as new pressure for main flow logic callback local totalv = currentpressure local totalc = 1 @@ -99,6 +112,8 @@ flowlogic.balance_pressure = function(pos, node) for _, target in ipairs(connections) do target.set(average) end + + return average end -- cgit v1.2.3 From 65b3448796815718275ed3c16af4865e5e005454 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 17:55:14 +0100 Subject: new flow logic: abms.lua: refactor flowlogic.run_output() into a processing stage of flowlogic.run() --- new_flow_logic/abms.lua | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 37b10bc..671a69d 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -68,6 +68,7 @@ end flowlogic.run = function(pos, node) + local nodename = node.name -- get the current pressure value. local nodepressure = get_pressure_access(pos) local currentpressure = nodepressure.get() @@ -75,6 +76,18 @@ flowlogic.run = function(pos, node) -- balance pressure with neighbours currentpressure = flowlogic.balance_pressure(pos, node, currentpressure) + -- if node is an output: run output phase + local output = pipeworks.flowables.outputs.list[nodename] + if output then + currentpressure = flowlogic.run_output( + pos, + node, + currentpressure, + output.upper, + output.lower, + output.outputfn) + end + -- set the new pressure nodepressure.set(currentpressure) end @@ -176,20 +189,18 @@ end -flowlogic.run_output = function(pos, node, threshold, outputfn) - -- callback for output devices. - -- takes care of checking a minimum pressure value and updating the node metadata. +flowlogic.run_output = function(pos, node, currentpressure, upper, lower, outputfn) + -- processing step for water output devices. + -- takes care of checking a minimum pressure value and updating the resulting pressure level -- the outputfn is provided the current pressure and returns the pressure "taken". -- as an example, using this with the above spigot function, -- the spigot function tries to output a water source if it will fit in the world. - local meta = minetest.get_meta(pos) - -- sometimes I wonder if meta:get_* returning default values would ever be problematic. - -- though here it doesn't matter, an uninit'd node returns 0, which is fine for a new, empty node. - local currentpressure = meta:get_float(label_pressure) - if currentpressure > threshold then + local result = currentpressure + if currentpressure > lower then local takenpressure = outputfn(pos, node, currentpressure) local newpressure = currentpressure - takenpressure - if newpressure < 0 then currentpressure = 0 end - meta:set_float(label_pressure, newpressure) + if newpressure < 0 then newpressure = 0 end + result = newpressure end + return result end -- cgit v1.2.3 From 9c770532e6e3cb1157e467015a97aef97a8a8893 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 19:19:09 +0100 Subject: new flow logic: abms.lua: refactor run_input to run as part of master run() ABM --- new_flow_logic/abms.lua | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 671a69d..eb551d8 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -66,6 +66,14 @@ local get_pressure_access = function(pos) end +-- logging is unreliable when something is crashing... +local nilexplode = function(caller, label, value) + if value == nil then + error(caller..": "..label.." was nil") + end +end + + flowlogic.run = function(pos, node) local nodename = node.name @@ -73,6 +81,14 @@ flowlogic.run = function(pos, node) local nodepressure = get_pressure_access(pos) local currentpressure = nodepressure.get() + -- if node is an input: run intake phase + local inputdef = pipeworks.flowables.inputs.list[nodename] + if inputdef then + currentpressure = flowlogic.run_input(pos, node, currentpressure, inputdef) + --debuglog("post-intake currentpressure is "..currentpressure) + --nilexplode("run()", "currentpressure", currentpressure) + end + -- balance pressure with neighbours currentpressure = flowlogic.balance_pressure(pos, node, currentpressure) @@ -131,23 +147,22 @@ end -flowlogic.run_input = function(pos, node, maxpressure, intakefn) +flowlogic.run_input = function(pos, node, currentpressure, inputdef) -- intakefn allows a given input node to define it's own intake logic. -- this function will calculate the maximum amount of water that can be taken in; -- the intakefn will be given this and is expected to return the actual absorption amount. - local meta = minetest.get_meta(pos) - local currentpressure = meta:get_float(label_pressure) + local maxpressure = inputdef.maxpressure local intake_limit = maxpressure - currentpressure - if intake_limit <= 0 then return end + if intake_limit <= 0 then return currentpressure end - local actual_intake = intakefn(pos, intake_limit) + local actual_intake = inputdef.intakefn(pos, intake_limit) --pipeworks.logger("run_input@"..formatvec(pos).." oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake) - if actual_intake <= 0 then return end + if actual_intake <= 0 then return currentpressure end local newpressure = actual_intake + currentpressure - -- debuglog("oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake.." newpressure "..newpressure) - meta:set_float(label_pressure, newpressure) + --debuglog("run_input() end, oldpressure "..currentpressure.." intake_limit "..intake_limit.." actual_intake "..actual_intake.." newpressure "..newpressure) + return newpressure end -- cgit v1.2.3 From 187e755aa5d7f4ddbc68cc2c4d8494051321a3cd Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 21:44:33 +0100 Subject: new flow logic: abms.lua: don't unpack outputdef variables in flowlogic.run(), leave to flowlogic.run_output() --- new_flow_logic/abms.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index eb551d8..6fee744 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -93,15 +93,13 @@ flowlogic.run = function(pos, node) currentpressure = flowlogic.balance_pressure(pos, node, currentpressure) -- if node is an output: run output phase - local output = pipeworks.flowables.outputs.list[nodename] - if output then + local outputdef = pipeworks.flowables.outputs.list[nodename] + if outputdef then currentpressure = flowlogic.run_output( pos, node, currentpressure, - output.upper, - output.lower, - output.outputfn) + outputdef) end -- set the new pressure @@ -204,15 +202,17 @@ end -flowlogic.run_output = function(pos, node, currentpressure, upper, lower, outputfn) +flowlogic.run_output = function(pos, node, currentpressure, outputdef) -- processing step for water output devices. -- takes care of checking a minimum pressure value and updating the resulting pressure level -- the outputfn is provided the current pressure and returns the pressure "taken". -- as an example, using this with the above spigot function, -- the spigot function tries to output a water source if it will fit in the world. + local upper = outputdef.upper + local lower = outputdef.lower local result = currentpressure if currentpressure > lower then - local takenpressure = outputfn(pos, node, currentpressure) + local takenpressure = outputdef.outputfn(pos, node, currentpressure) local newpressure = currentpressure - takenpressure if newpressure < 0 then newpressure = 0 end result = newpressure -- cgit v1.2.3 From bd32b4fca2ee77da1b4b017d3e90a4013d4393a8 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 22:03:53 +0100 Subject: new flow logic: abms.lua: pass finite mode flag to run_output() --- new_flow_logic/abms.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 6fee744..1605ea3 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -75,6 +75,7 @@ end +local finitemode = pipeworks.toggles.finite_water flowlogic.run = function(pos, node) local nodename = node.name -- get the current pressure value. @@ -99,7 +100,8 @@ flowlogic.run = function(pos, node) pos, node, currentpressure, - outputdef) + outputdef, + finitemode) end -- set the new pressure @@ -202,7 +204,7 @@ end -flowlogic.run_output = function(pos, node, currentpressure, outputdef) +flowlogic.run_output = function(pos, node, currentpressure, outputdef, finitemode) -- processing step for water output devices. -- takes care of checking a minimum pressure value and updating the resulting pressure level -- the outputfn is provided the current pressure and returns the pressure "taken". -- cgit v1.2.3 From 07e769d1b92661dc21bf85dee2f788f929fc444e Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 22:07:30 +0100 Subject: new flow logic: abms.lua: pass finite mod flag to output handler callbacks in flowlogic.run_output() --- new_flow_logic/abms.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 1605ea3..a4d5fc3 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -173,7 +173,7 @@ end -- this is a constructor function, returning another function which satisfies the output helper requirements. -- note that this does *not* take rotation into account. flowlogic.helpers.make_neighbour_output_fixed = function(neighbours) - return function(pos, node, currentpressure) + return function(pos, node, currentpressure, finitemode) local taken = 0 for _, offset in pairs(neighbours) do local npos = vector.add(pos, offset) @@ -214,7 +214,7 @@ flowlogic.run_output = function(pos, node, currentpressure, outputdef, finitemod local lower = outputdef.lower local result = currentpressure if currentpressure > lower then - local takenpressure = outputdef.outputfn(pos, node, currentpressure) + local takenpressure = outputdef.outputfn(pos, node, currentpressure, finitemode) local newpressure = currentpressure - takenpressure if newpressure < 0 then newpressure = 0 end result = newpressure -- cgit v1.2.3 From 9ab197af2f6e524be920857c0f152aef84546e37 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 22:21:54 +0100 Subject: new flow logic: abms.lua: implement non-finite mode behaviour for neighbour output helper --- new_flow_logic/abms.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index a4d5fc3..99ccbc6 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -178,9 +178,18 @@ flowlogic.helpers.make_neighbour_output_fixed = function(neighbours) for _, offset in pairs(neighbours) do local npos = vector.add(pos, offset) local name = minetest.get_node(npos).name - if (name == "air") or (name == "default:water_flowing") then + if currentpressure < 1 then break end + -- take pressure anyway in non-finite mode, even if node is water source already. + -- in non-finite mode, pressure has to be sustained to keep the sources there. + -- so in non-finite mode, placing water is dependent on the target node; + -- draining pressure is not. + local canplace = (name == "air") or (name == "default:water_flowing") + if canplace then minetest.swap_node(npos, {name="default:water_source"}) + end + if (not finitemode) or canplace then taken = taken + 1 + currentpressure = currentpressure - 1 end end return taken -- cgit v1.2.3 From d4346919bcb4d2e0c692448bc0a652d55c0fa2a9 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 22:29:17 +0100 Subject: new flow logic: abms.lua: pass initial pressure to run_output() to allow falling-level event detection --- new_flow_logic/abms.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 99ccbc6..babd14e 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -81,6 +81,7 @@ flowlogic.run = function(pos, node) -- get the current pressure value. local nodepressure = get_pressure_access(pos) local currentpressure = nodepressure.get() + local oldpressure = currentpressure -- if node is an input: run intake phase local inputdef = pipeworks.flowables.inputs.list[nodename] @@ -100,6 +101,7 @@ flowlogic.run = function(pos, node) pos, node, currentpressure, + oldpressure, outputdef, finitemode) end @@ -213,7 +215,7 @@ end -flowlogic.run_output = function(pos, node, currentpressure, outputdef, finitemode) +flowlogic.run_output = function(pos, node, currentpressure, oldpressure, outputdef, finitemode) -- processing step for water output devices. -- takes care of checking a minimum pressure value and updating the resulting pressure level -- the outputfn is provided the current pressure and returns the pressure "taken". -- cgit v1.2.3 From f94c93bb59fa151ee90932f53afb82ac6f3aae15 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sat, 7 Oct 2017 22:35:08 +0100 Subject: new flow logic: abms.lua: implement non-finite mode cleanupfn invocation in run_output() --- new_flow_logic/abms.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index babd14e..9197d17 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -224,11 +224,16 @@ flowlogic.run_output = function(pos, node, currentpressure, oldpressure, outputd local upper = outputdef.upper local lower = outputdef.lower local result = currentpressure - if currentpressure > lower then + local threshold = nil + if finitemode then threshold = lower else threshold = upper end + if currentpressure > threshold then local takenpressure = outputdef.outputfn(pos, node, currentpressure, finitemode) local newpressure = currentpressure - takenpressure if newpressure < 0 then newpressure = 0 end result = newpressure end + if (not finitemode) and (currentpressure < lower) and (oldpressure > lower) then + outputdef.cleanupfn(pos, node, currentpressure) + end return result end -- cgit v1.2.3 From 6a25e56336f98be7f91d328d6a75674450aa46a4 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 8 Oct 2017 11:32:08 +0100 Subject: new flow logic: algorithmic and value tuning for non-finite mode --- new_flow_logic/abms.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 9197d17..e83d50e 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -202,12 +202,13 @@ end -- removes water sources from neighbor positions when the output is "off" due to lack of pressure. flowlogic.helpers.make_neighbour_cleanup_fixed = function(neighbours) return function(pos, node, currentpressure) - -- FIXME - this would indiscriminately take blocks while under-pressure, not just one time? + --pipeworks.logger("neighbour_cleanup_fixed@"..formatvec(pos)) for _, offset in pairs(neighbours) do local npos = vector.add(pos, offset) local name = minetest.get_node(npos).name if (name == "default:water_source") then - minetest.remove_node(pos) + --pipeworks.logger("neighbour_cleanup_fixed removing "..formatvec(npos)) + minetest.remove_node(npos) end end end @@ -221,6 +222,7 @@ flowlogic.run_output = function(pos, node, currentpressure, oldpressure, outputd -- the outputfn is provided the current pressure and returns the pressure "taken". -- as an example, using this with the above spigot function, -- the spigot function tries to output a water source if it will fit in the world. + --pipeworks.logger("flowlogic.run_output() pos "..formatvec(pos).." old -> currentpressure "..tostring(oldpressure).." "..tostring(currentpressure).." finitemode "..tostring(finitemode)) local upper = outputdef.upper local lower = outputdef.lower local result = currentpressure @@ -232,7 +234,8 @@ flowlogic.run_output = function(pos, node, currentpressure, oldpressure, outputd if newpressure < 0 then newpressure = 0 end result = newpressure end - if (not finitemode) and (currentpressure < lower) and (oldpressure > lower) then + if (not finitemode) and (currentpressure < lower) and (oldpressure < lower) then + --pipeworks.logger("flowlogic.run_output() invoking cleanup currentpressure="..tostring(currentpressure)) outputdef.cleanupfn(pos, node, currentpressure) end return result -- cgit v1.2.3 From eaf6c33bae0912e15ac190df203b9b250545052b Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 8 Oct 2017 16:19:51 +0100 Subject: new flow logic: abms.lua: implement node transitions --- new_flow_logic/abms.lua | 51 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index e83d50e..6abdd42 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -29,7 +29,7 @@ end ---local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..tostring(vec.y)..sep..tostring(vec.z)..")" end +local formatvec = function(vec) local sep="," return "("..tostring(vec.x)..sep..tostring(vec.y)..sep..tostring(vec.z)..")" end -- new version of liquid check -- accepts a limit parameter to only delete water blocks that the receptacle can accept, @@ -106,6 +106,13 @@ flowlogic.run = function(pos, node) finitemode) end + -- if node has pressure transitions: determine new node + if pipeworks.flowables.transitions.list[nodename] then + local newnode = flowlogic.run_transition(node, currentpressure) + --pipeworks.logger("flowlogic.run()@"..formatvec(pos).." transition, new node name = "..dump(newnode).." pressure "..tostring(currentpressure)) + minetest.swap_node(pos, newnode) + end + -- set the new pressure nodepressure.set(currentpressure) end @@ -240,3 +247,45 @@ flowlogic.run_output = function(pos, node, currentpressure, oldpressure, outputd end return result end + + + +-- determine which node to switch to based on current pressure +flowlogic.run_transition = function(node, currentpressure) + local simplesetdef = pipeworks.flowables.transitions.simple[node.name] + local result = node + local found = false + + -- simple transition sets: assumes all nodes in the set share param values. + if simplesetdef then + -- assumes that the set has been checked to contain at least one element... + local nodename_prev = simplesetdef[1].nodename + local result_nodename = node.name + + for index, element in ipairs(simplesetdef) do + -- find the highest element that is below the current pressure. + local threshold = element.threshold + if threshold > currentpressure then + result_nodename = nodename_prev + found = true + break + end + nodename_prev = element.nodename + end + + -- use last element if no threshold is greater than current pressure + if not found then + result_nodename = nodename_prev + found = true + end + + -- preserve param1/param2 values + result = { name=result_nodename, param1=node.param1, param2=node.param2 } + end + + if not found then + pipeworks.logger("flowlogic.run_transition() BUG no transition definitions found! nodename="..nodename.." currentpressure="..tostring(currentpressure)) + end + + return result +end -- cgit v1.2.3 From d5e3f1cf68a15d7e14cc44eb8e58e49dbb6aa087 Mon Sep 17 00:00:00 2001 From: thetaepsilon-gamedev Date: Sun, 8 Oct 2017 17:38:28 +0100 Subject: new flow logic: implement post-transition hook with mesecons support, add mesecons transition rules for flow sensor --- new_flow_logic/abms.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'new_flow_logic/abms.lua') diff --git a/new_flow_logic/abms.lua b/new_flow_logic/abms.lua index 6abdd42..38ae4b6 100644 --- a/new_flow_logic/abms.lua +++ b/new_flow_logic/abms.lua @@ -111,6 +111,7 @@ flowlogic.run = function(pos, node) local newnode = flowlogic.run_transition(node, currentpressure) --pipeworks.logger("flowlogic.run()@"..formatvec(pos).." transition, new node name = "..dump(newnode).." pressure "..tostring(currentpressure)) minetest.swap_node(pos, newnode) + flowlogic.run_transition_post(pos, newnode) end -- set the new pressure @@ -289,3 +290,26 @@ flowlogic.run_transition = function(node, currentpressure) return result end + +-- post-update hook for run_transition +-- among other things, updates mesecons if present. +-- node here means the new node, returned from run_transition() above +flowlogic.run_transition_post = function(pos, node) + local mesecons_def = minetest.registered_nodes[node.name].mesecons + local mesecons_rules = pipeworks.flowables.transitions.mesecons[node.name] + if minetest.global_exists("mesecon") and (mesecons_def ~= nil) and mesecons_rules then + if type(mesecons_def) ~= "table" then + pipeworks.logger("flowlogic.run_transition_post() BUG mesecons def for "..node.name.."not a table: got "..tostring(mesecons_def)) + else + local receptor = mesecons_def.receptor + if receptor then + local state = receptor.state + if state == mesecon.state.on then + mesecon.receptor_on(pos, mesecons_rules) + elseif state == mesecon.state.off then + mesecon.receptor_off(pos, mesecons_rules) + end + end + end + end +end -- cgit v1.2.3