mirror of
https://github.com/mt-mods/pipeworks.git
synced 2024-12-27 19:30:26 +01:00
199 lines
8.1 KiB
Lua
199 lines
8.1 KiB
Lua
-- 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
|