@@ -10,8 +10,8 @@ local network_node_arrays = {"PR_nodes","BA_nodes","RE_nodes"}
10
10
technic .active_networks = {}
11
11
local networks = {}
12
12
technic .networks = networks
13
- local cables = {}
14
- technic .cables = cables
13
+ local technic_cables = {}
14
+ technic .cables = technic_cables
15
15
16
16
local poshash = minetest .hash_node_position
17
17
local hashpos = minetest .get_position_from_hash
@@ -38,9 +38,9 @@ function technic.merge_networks(net1, net2)
38
38
assert (type (net2 ) == " table" , " Invalid net2 for technic.merge_networks" )
39
39
assert (net1 ~= net2 , " Deadlock recipe: net1 & net2 equals for technic.merge_networks" )
40
40
-- Move data in cables table
41
- for node_id ,cable_net_id in pairs (cables ) do
41
+ for node_id ,cable_net_id in pairs (technic_cables ) do
42
42
if cable_net_id == net2 .id then
43
- cables [node_id ] = net1 .id
43
+ technic_cables [node_id ] = net1 .id
44
44
end
45
45
end
46
46
-- Move data in machine tables
90
90
91
91
-- Destroy network data
92
92
function technic .remove_network (network_id )
93
- for pos_hash ,cable_net_id in pairs (cables ) do
93
+ for pos_hash ,cable_net_id in pairs (technic_cables ) do
94
94
if cable_net_id == network_id then
95
- cables [pos_hash ] = nil
95
+ technic_cables [pos_hash ] = nil
96
96
end
97
97
end
98
98
networks [network_id ] = nil
99
99
technic .active_networks [network_id ] = nil
100
100
end
101
101
102
- -- Remove machine or cable from network
103
- function technic .remove_network_node (network_id , pos )
104
- local network = networks [network_id ]
105
- if not network then return end
106
- -- Clear hash tables, cannot use table.remove
107
- local node_id = poshash (pos )
108
- cables [node_id ] = nil
109
- network .all_nodes [node_id ] = nil
110
- -- TODO: All following things can be skipped if node is not machine
111
- -- check here if it is or is not cable
112
- -- or add separate function to remove cables and move responsibility to caller
113
- -- Clear indexed arrays, do NOT leave holes
114
- local machine_removed = false
115
- for _ ,tblname in ipairs (network_node_arrays ) do
116
- local tbl = network [tblname ]
117
- for i =# tbl ,1 ,- 1 do
118
- local mpos = tbl [i ]
119
- if mpos .x == pos .x and mpos .y == pos .y and mpos .z == pos .z then
120
- table.remove (tbl , i )
121
- machine_removed = true
122
- break
123
- end
124
- end
125
- end
126
- if machine_removed then
127
- -- Machine can still be in world, just not connected to any network. If so then disable it.
128
- local node = minetest .get_node (pos )
129
- technic .disable_machine (pos , node )
130
- end
131
- end
132
-
133
102
function technic .sw_pos2network (pos )
134
- return cables [poshash ({x = pos .x ,y = pos .y - 1 ,z = pos .z })]
103
+ return technic_cables [poshash ({x = pos .x ,y = pos .y - 1 ,z = pos .z })]
135
104
end
136
105
137
106
function technic .pos2network (pos )
138
- return cables [poshash (pos )]
107
+ return technic_cables [poshash (pos )]
139
108
end
140
109
141
110
function technic .network2pos (network_id )
@@ -208,38 +177,176 @@ function technic.disable_machine(pos, node)
208
177
end
209
178
end
210
179
211
- --
212
- -- Network overloading (incomplete cheat mitigation)
213
- --
214
- local overload_reset_time = tonumber (technic .config :get (" network_overload_reset_time" ))
215
- local overloaded_networks = {}
180
+ local function match_cable_tier_filter (name , tiers )
181
+ -- Helper to check for set of cable tiers
182
+ if tiers then
183
+ for _ , tier in ipairs (tiers ) do if technic .is_tier_cable (name , tier ) then return true end end
184
+ return false
185
+ end
186
+ return technic .get_cable_tier (name ) ~= nil
187
+ end
216
188
217
- local function overload_network (network_id )
218
- local network = networks [network_id ]
219
- if network then
220
- network .supply = 0
221
- network .battery_charge = 0
189
+ local function get_neighbors (pos , tiers )
190
+ local tier_machines = tiers and technic .machines [tiers [1 ]]
191
+ local is_cable = match_cable_tier_filter (minetest .get_node (pos ).name , tiers )
192
+ local network = is_cable and technic .networks [technic .pos2network (pos )]
193
+ local cables = {}
194
+ local machines = {}
195
+ local positions = {
196
+ {x = pos .x + 1 , y = pos .y , z = pos .z },
197
+ {x = pos .x - 1 , y = pos .y , z = pos .z },
198
+ {x = pos .x , y = pos .y + 1 , z = pos .z },
199
+ {x = pos .x , y = pos .y - 1 , z = pos .z },
200
+ {x = pos .x , y = pos .y , z = pos .z + 1 },
201
+ {x = pos .x , y = pos .y , z = pos .z - 1 },
202
+ }
203
+ for _ ,connected_pos in ipairs (positions ) do
204
+ local name = minetest .get_node (connected_pos ).name
205
+ if tier_machines and tier_machines [name ] then
206
+ table.insert (machines , connected_pos )
207
+ elseif match_cable_tier_filter (name , tiers ) then
208
+ local cable_network = technic .networks [technic .pos2network (connected_pos )]
209
+ table.insert (cables ,{
210
+ pos = connected_pos ,
211
+ network = cable_network ,
212
+ })
213
+ if not network then network = cable_network end
214
+ end
222
215
end
223
- overloaded_networks [ network_id ] = minetest . get_us_time () + ( overload_reset_time * 1000 * 1000 )
216
+ return network , cables , machines
224
217
end
225
- technic .overload_network = overload_network
226
218
227
- local function reset_overloaded (network_id )
228
- local remaining = math.max (0 , overloaded_networks [network_id ] - minetest .get_us_time ())
229
- if remaining == 0 then
230
- -- Clear cache, remove overload and restart network
231
- technic .remove_network (network_id )
232
- overloaded_networks [network_id ] = nil
219
+ function technic .place_network_node (pos , tiers , name )
220
+ -- Get connections and primary network if there's any
221
+ local network , cables , machines = get_neighbors (pos , tiers )
222
+ if not network then
223
+ -- We're evidently not on a network, nothing to add ourselves to
224
+ return
225
+ end
226
+
227
+ -- Attach to primary network, this must be done before building branches from this position
228
+ technic .add_network_node (pos , network )
229
+ if not match_cable_tier_filter (name , tiers ) then
230
+ if technic .machines [tiers [1 ]][name ] == technic .producer_receiver then
231
+ -- FIXME: Multi tier machine like supply converter should also attach to other networks around pos.
232
+ -- Preferably also with connection rules defined for machine.
233
+ -- nodedef.connect_sides could be used to generate these rules.
234
+ -- For now, assume that all multi network machines belong to technic.producer_receiver group:
235
+ -- Get cables and networks around PR_RE machine
236
+ local _ , machine_cables , _ = get_neighbors (pos )
237
+ for _ ,connection in ipairs (machine_cables ) do
238
+ if connection .network and connection .network .id ~= network .id then
239
+ -- Attach PR_RE machine to secondary networks (last added is primary until above note is resolved)
240
+ technic .add_network_node (pos , connection .network )
241
+ end
242
+ end
243
+ else
244
+ -- Check connected cables for foreign networks, overload if machine was connected to multiple networks
245
+ for _ , connection in ipairs (cables ) do
246
+ if connection .network and connection .network .id ~= network .id then
247
+ technic .overload_network (connection .network .id )
248
+ technic .overload_network (network .id )
249
+ end
250
+ end
251
+ end
252
+ -- Machine added, skip all network building
253
+ return
254
+ end
255
+
256
+ -- Attach neighbor machines if cable was added
257
+ for _ ,machine_pos in ipairs (machines ) do
258
+ technic .add_network_node (machine_pos , network )
259
+ end
260
+
261
+ -- Attach neighbor cables
262
+ for _ ,connection in ipairs (cables ) do
263
+ if connection .network then
264
+ if connection .network .id ~= network .id then
265
+ -- Remove network if position belongs to another network
266
+ -- FIXME: Network requires partial rebuild but avoid doing it here if possible.
267
+ -- This might cause problems when merging two active networks into one
268
+ technic .remove_network (network .id )
269
+ technic .remove_network (connection .network .id )
270
+ connection .network = nil
271
+ end
272
+ else
273
+ -- There's cable that does not belong to any network, attach whole branch
274
+ technic .add_network_node (connection .pos , network )
275
+ technic .add_network_branch ({connection .pos }, network )
276
+ end
277
+ end
278
+ end
279
+
280
+ -- Remove machine or cable from network
281
+ local function remove_network_node (network_id , pos )
282
+ local network = networks [network_id ]
283
+ if not network then return end
284
+ -- Clear hash tables, cannot use table.remove
285
+ local node_id = poshash (pos )
286
+ technic_cables [node_id ] = nil
287
+ network .all_nodes [node_id ] = nil
288
+ -- TODO: All following things can be skipped if node is not machine
289
+ -- check here if it is or is not cable
290
+ -- or add separate function to remove cables and move responsibility to caller
291
+ -- Clear indexed arrays, do NOT leave holes
292
+ local machine_removed = false
293
+ for _ ,tblname in ipairs (network_node_arrays ) do
294
+ local tbl = network [tblname ]
295
+ for i =# tbl ,1 ,- 1 do
296
+ local mpos = tbl [i ]
297
+ if mpos .x == pos .x and mpos .y == pos .y and mpos .z == pos .z then
298
+ table.remove (tbl , i )
299
+ machine_removed = true
300
+ break
301
+ end
302
+ end
303
+ end
304
+ if machine_removed then
305
+ -- Machine can still be in world, just not connected to any network. If so then disable it.
306
+ local node = minetest .get_node (pos )
307
+ technic .disable_machine (pos , node )
233
308
end
234
- -- Returns 0 when network reset or remaining time if reset timer has not expired yet
235
- return remaining
236
309
end
237
- technic .reset_overloaded = reset_overloaded
238
310
239
- local function is_overloaded (network_id )
240
- return overloaded_networks [network_id ]
311
+ function technic .remove_network_node (pos , tiers , name )
312
+ -- Get the network and neighbors
313
+ local network , cables , machines = get_neighbors (pos , tiers )
314
+ if not network then return end
315
+
316
+ if not match_cable_tier_filter (name , tiers ) then
317
+ -- Machine removed, skip cable checks to prevent unnecessary network cleanups
318
+ for _ ,connection in ipairs (cables ) do
319
+ if connection .network then
320
+ -- Remove machine from all networks around it
321
+ remove_network_node (connection .network .id , pos )
322
+ end
323
+ end
324
+ return
325
+ end
326
+
327
+ if # cables == 1 then
328
+ -- Dead end cable removed, remove it from the network
329
+ remove_network_node (network .id , pos )
330
+ -- Remove neighbor machines from network if cable was removed
331
+ if match_cable_tier_filter (name , tiers ) then
332
+ for _ ,machine_pos in ipairs (machines ) do
333
+ local net , _ , _ = get_neighbors (machine_pos , tiers )
334
+ if not net then
335
+ -- Remove machine from network if it does not have other connected cables
336
+ remove_network_node (network .id , machine_pos )
337
+ end
338
+ end
339
+ end
340
+ else
341
+ -- TODO: Check branches around and switching stations for branches:
342
+ -- remove branches that do not have switching station. Switching stations not tracked but could be easily tracked.
343
+ -- remove branches not connected to another branch. Individual branches not tracked, requires simple AI heuristics.
344
+ -- move branches that have switching station to new networks without checking or loading actual nodes in world.
345
+ -- To do all this network must be aware of individual branches and switching stations, might not be worth it...
346
+ -- For now remove whole network and let ABM rebuild it
347
+ technic .remove_network (network .id )
348
+ end
241
349
end
242
- technic .is_overloaded = is_overloaded
243
350
244
351
--
245
352
-- Functions to traverse the electrical network
@@ -248,18 +355,18 @@ technic.is_overloaded = is_overloaded
248
355
-- Add a machine node to the LV/MV/HV network
249
356
local function add_network_machine (nodes , pos , network_id , all_nodes , multitier )
250
357
local node_id = poshash (pos )
251
- local net_id_old = cables [node_id ]
358
+ local net_id_old = technic_cables [node_id ]
252
359
if net_id_old == nil or (multitier and net_id_old ~= network_id and all_nodes [node_id ] == nil ) then
253
360
-- Add machine to network only if it is not already added
254
361
table.insert (nodes , pos )
255
362
-- FIXME: Machines connecting to multiple networks should have way to store multiple network ids
256
- cables [node_id ] = network_id
363
+ technic_cables [node_id ] = network_id
257
364
all_nodes [node_id ] = pos
258
365
return true
259
366
elseif not multitier and net_id_old ~= network_id then
260
367
-- Do not allow running from multiple networks, trigger overload
261
- overload_network (network_id )
262
- overload_network (net_id_old )
368
+ technic . overload_network (network_id )
369
+ technic . overload_network (net_id_old )
263
370
local meta = minetest .get_meta (pos )
264
371
meta :set_string (" infotext" ,S (" Network Overloaded" ))
265
372
end
@@ -268,15 +375,15 @@ end
268
375
-- Add a wire node to the LV/MV/HV network
269
376
local function add_cable_node (pos , network )
270
377
local node_id = poshash (pos )
271
- if not cables [node_id ] then
272
- cables [node_id ] = network .id
378
+ if not technic_cables [node_id ] then
379
+ technic_cables [node_id ] = network .id
273
380
network .all_nodes [node_id ] = pos
274
381
if network .queue then
275
382
table.insert (network .queue , pos )
276
383
end
277
- elseif cables [node_id ] ~= network .id then
384
+ elseif technic_cables [node_id ] ~= network .id then
278
385
-- Conflicting network connected, merge networks if both are still in building stage
279
- local net2 = networks [cables [node_id ]]
386
+ local net2 = networks [technic_cables [node_id ]]
280
387
if net2 and net2 .queue then
281
388
technic .merge_networks (network , net2 )
282
389
end
@@ -288,7 +395,7 @@ local function add_network_node(network, pos, machines)
288
395
technic .get_or_load_node (pos )
289
396
local name = minetest .get_node (pos ).name
290
397
291
- if technic .is_tier_cable (name , network .tier ) then
398
+ if technic .get_cable_tier (name ) == network .tier then
292
399
add_cable_node (pos , network )
293
400
elseif machines [name ] then
294
401
if machines [name ] == technic .producer then
438
545
--
439
546
local node_technic_run = {}
440
547
minetest .register_on_mods_loaded (function ()
548
+ for name , tiers in pairs (technic .machine_tiers ) do
549
+ local nodedef = minetest .registered_nodes [name ]
550
+ local on_construct = type (nodedef .on_construct ) == " function" and nodedef .on_construct
551
+ local on_destruct = type (nodedef .on_destruct ) == " function" and nodedef .on_destruct
552
+ local place_node = technic .place_network_node
553
+ local remove_node = technic .remove_network_node
554
+ minetest .override_item (name , {
555
+ on_construct = on_construct
556
+ and function (pos ) on_construct (pos ) place_node (pos , tiers , name ) end
557
+ or function (pos ) place_node (pos , tiers , name ) end ,
558
+ on_destruct = on_destruct
559
+ and function (pos ) on_destruct (pos ) remove_node (pos , tiers , name ) end
560
+ or function (pos ) remove_node (pos , tiers , name ) end ,
561
+ })
562
+ end
441
563
for name , _ in pairs (technic .machine_tiers ) do
442
564
if type (minetest .registered_nodes [name ].technic_run ) == " function" then
443
565
node_technic_run [name ] = minetest .registered_nodes [name ].technic_run
0 commit comments