summaryrefslogtreecommitdiff
path: root/new_flow_logic/flowable_node_registry_install.lua
blob: f019dc3ccd27ed3f144bc6cfab216be5c89484b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
-- 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)
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)
	if pipeworks.toggles.pressure_logic then
		abmregister.flowlogic(nodename)
	end
	regwarning("simple", 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)
	local set = {}
	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
end