diff options
Diffstat (limited to 'pressure_logic/flowable_node_registry_install.lua')
-rw-r--r-- | pressure_logic/flowable_node_registry_install.lua | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/pressure_logic/flowable_node_registry_install.lua b/pressure_logic/flowable_node_registry_install.lua new file mode 100644 index 0000000..a49c31a --- /dev/null +++ b/pressure_logic/flowable_node_registry_install.lua @@ -0,0 +1,198 @@ +-- flowable node registry: add entries and install ABMs if new flow logic is enabled +-- written 2017 by thetaepsilon + + + +-- use for hooking up ABMs as nodes are registered +local abmregister = pipeworks.flowlogic.abmregister + +-- registration functions +pipeworks.flowables.register = {} +local register = pipeworks.flowables.register + +-- some sanity checking for passed args, as this could potentially be made an external API eventually +local checkexists = function(nodename) + if type(nodename) ~= "string" then error("pipeworks.flowables nodename must be a string!") end + return pipeworks.flowables.list.all[nodename] +end + +local insertbase = function(nodename) + if checkexists(nodename) then error("pipeworks.flowables duplicate registration!") end + pipeworks.flowables.list.all[nodename] = true + -- table.insert(pipeworks.flowables.list.nodenames, nodename) + if pipeworks.toggles.pressure_logic then + abmregister.flowlogic(nodename) + end +end + +local regwarning = function(kind, nodename) + local tail = "" + if not pipeworks.toggles.pressure_logic then tail = " but pressure logic not enabled" end + --pipeworks.logger(kind.." flow logic registry requested for "..nodename..tail) +end + +-- Register a node as a simple flowable. +-- Simple flowable nodes have no considerations for direction of flow; +-- A cluster of adjacent simple flowables will happily average out in any direction. +register.simple = function(nodename) + insertbase(nodename) + pipeworks.flowables.list.simple[nodename] = true + table.insert(pipeworks.flowables.list.simple_nodenames, nodename) + regwarning("simple", nodename) +end + +-- Register a node as a directional flowable: +-- has a helper function which determines which nodes to consider valid neighbours. +register.directional = function(nodename, neighbourfn) + insertbase(nodename) + pipeworks.flowables.list.directional[nodename] = { neighbourfn = neighbourfn } + regwarning("directional", nodename) +end + + + +local checkbase = function(nodename) + if not checkexists(nodename) then error("pipeworks.flowables node doesn't exist as a flowable!") end +end + +local duplicateerr = function(kind, nodename) error(kind.." duplicate registration for "..nodename) end + + + +-- Registers a node as a fluid intake. +-- intakefn is used to determine the water that can be taken in a node-specific way. +-- Expects node to be registered as a flowable (is present in flowables.list.all), +-- so that water can move out of it. +-- maxpressure is the maximum pipeline pressure that this node can drive; +-- if the input's node exceeds this the callback is not run. +-- possible WISHME here: technic-driven high-pressure pumps +register.intake = function(nodename, maxpressure, intakefn) + -- check for duplicate registration of this node + local list = pipeworks.flowables.inputs.list + checkbase(nodename) + if list[nodename] then duplicateerr("pipeworks.flowables.inputs", nodename) end + list[nodename] = { maxpressure=maxpressure, intakefn=intakefn } + regwarning("intake", nodename) +end + + + +-- Register a node as a simple intake: +-- tries to absorb water source nodes from it's surroundings. +-- may exceed limit slightly due to needing to absorb whole nodes. +register.intake_simple = function(nodename, maxpressure) + register.intake(nodename, maxpressure, pipeworks.flowlogic.check_for_liquids_v2) +end + + + +-- Register a node as an output. +-- Expects node to already be a flowable. +-- upper and lower thresholds have different meanings depending on whether finite liquid mode is in effect. +-- if not (the default unless auto-detected), +-- nodes above their upper threshold have their outputfn invoked (and pressure deducted), +-- nodes between upper and lower are left idle, +-- and nodes below lower have their cleanup fn invoked (to say remove water sources). +-- the upper and lower difference acts as a hysteresis to try and avoid "gaps" in the flow. +-- if finite mode is on, upper is ignored and lower is used to determine whether to run outputfn; +-- cleanupfn is ignored in this mode as finite mode assumes something causes water to move itself. +register.output = function(nodename, upper, lower, outputfn, cleanupfn) + if pipeworks.flowables.outputs.list[nodename] then + error("pipeworks.flowables.outputs duplicate registration!") + end + checkbase(nodename) + pipeworks.flowables.outputs.list[nodename] = { + upper=upper, + lower=lower, + outputfn=outputfn, + cleanupfn=cleanupfn, + } + -- output ABM now part of main flow logic ABM to preserve ordering. + -- note that because outputs have to be a flowable first + -- (and the installation of the flow logic ABM is conditional), + -- registered output nodes for new_flow_logic is also still conditional on the enable flag. + regwarning("output node", nodename) +end + +-- register a simple output: +-- drains pressure by attempting to place water in nearby nodes, +-- which can be set by passing a list of offset vectors. +-- will attempt to drain as many whole nodes as there are positions in the offset list. +-- for meanings of upper and lower, see register.output() above. +-- non-finite mode: +-- above upper pressure: places water sources as appropriate, keeps draining pressure. +-- below lower presssure: removes it's neighbour water sources. +-- finite mode: +-- same as for above pressure in non-finite mode, +-- but only drains pressure when water source nodes are actually placed. +register.output_simple = function(nodename, upper, lower, neighbours) + local outputfn = pipeworks.flowlogic.helpers.make_neighbour_output_fixed(neighbours) + local cleanupfn = pipeworks.flowlogic.helpers.make_neighbour_cleanup_fixed(neighbours) + register.output(nodename, upper, lower, outputfn, cleanupfn) +end + + + +-- common base checking for transition nodes +-- ensures the node has only been registered once as a transition. +local transition_list = pipeworks.flowables.transitions.list +local insert_transition_base = function(nodename) + checkbase(nodename) + if transition_list[nodename] then duplicateerr("base transition", nodename) end + transition_list[nodename] = true +end + + + +-- register a simple transition set. +-- expects a table with nodenames as keys and threshold pressures as values. +-- internally, the table is sorted by value, and when one of these nodes needs to transition, +-- the table is searched starting from the lowest (even if it's value is non-zero), +-- until a value is found which is higher than or equal to the current node pressure. +-- ex. nodeset = { ["mod:level_0"] = 0, ["mod:level_1"] = 1, --[[ ... ]] } +local simpleseterror = function(msg) + error("register.transition_simple_set(): "..msg) +end +local simple_transitions = pipeworks.flowables.transitions.simple + +register.transition_simple_set = function(nodeset, extras) + local set = {} + if extras == nil then extras = {} end + + local length = #nodeset + if length < 2 then simpleseterror("nodeset needs at least two elements!") end + for index, element in ipairs(nodeset) do + if type(element) ~= "table" then simpleseterror("element "..tostring(index).." in nodeset was not table!") end + local nodename = element[1] + local value = element[2] + if type(nodename) ~= "string" then simpleseterror("nodename "..tostring(nodename).."was not a string!") end + if type(value) ~= "number" then simpleseterror("pressure value "..tostring(value).."was not a number!") end + insert_transition_base(nodename) + if simple_transitions[nodename] then duplicateerr("simple transition set", nodename) end + -- assigning set to table is done separately below + + table.insert(set, { nodename=nodename, threshold=value }) + end + + -- sort pressure values, smallest first + local smallest_first = function(a, b) + return a.threshold < b.threshold + end + table.sort(set, smallest_first) + + -- individual registration of each node, all sharing this set, + -- so each node in the set will transition to the correct target node. + for _, element in ipairs(set) do + --pipeworks.logger("register.transition_simple_set() after sort: nodename "..element.nodename.." value "..tostring(element.threshold)) + simple_transitions[element.nodename] = set + end + + -- handle extra options + -- if mesecons rules table was passed, set for each node + if extras.mesecons then + local mesecons_rules = pipeworks.flowables.transitions.mesecons + for _, element in ipairs(set) do + mesecons_rules[element.nodename] = extras.mesecons + end + end +end |