142 lines
6.2 KiB
Lua
142 lines
6.2 KiB
Lua
-- internal var net_master stores all slave nodes
|
||
-- sparktech_net_passive = are used to follow nets, do not count towards energy
|
||
-- sparktech_net_trigger = trigger updates
|
||
-- Updates blocks every seconds
|
||
|
||
local function compare_vec(va, vb)
|
||
if va == nil or vb == nil then
|
||
return false
|
||
end
|
||
return va.x == vb.x and va.y == vb.y and va.z == vb.z
|
||
end
|
||
|
||
local function add_node_to_net(pos, master) -- stores node in master meta
|
||
local meta = minetest.get_meta(master)
|
||
-- format x:y:z|x2:y2:z2
|
||
local net_master = meta:get_string("net_master")
|
||
net_master = net_master .. "|" .. pos.x .. ":" .. pos.y .. ":" .. pos.z;
|
||
meta:set_string("net_master", net_master)
|
||
local slavem = minetest.get_meta(pos)
|
||
slavem:set_string("net_master", "")
|
||
end
|
||
|
||
|
||
-- All nodes processed in a build cycle
|
||
-- Keeping track of caller nodes alone allows duplication
|
||
local processed = {}
|
||
|
||
-- The master of the network should not be limited to one branch
|
||
local master = nil
|
||
|
||
local function net_build(pos, callerpos, master_arg)
|
||
-- Option to force the master node
|
||
if (master_arg ~= nil) then
|
||
master = master_arg
|
||
end
|
||
|
||
local onode = minetest.get_node(pos)
|
||
|
||
-- Add node to the list of processed nodes so that it won’t be processed again
|
||
-- A node can show up multiple times in this list!
|
||
processed[#processed + 1] = pos
|
||
|
||
-- LOGIC to check only x sides, can be done eventually lol
|
||
-- e.g furnace only allows from below , or solar panels
|
||
-- before this need api to make cables connect from those side only too! otherwise it makes no sense for viewers
|
||
-- in game
|
||
local top = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||
local bottom = {x = pos.x, y = pos.y - 1, z = pos.z}
|
||
local left = {x = pos.x - 1, y = pos.y, z = pos.z}
|
||
local right = {x = pos.x + 1, y = pos.y, z = pos.z}
|
||
local front = {x = pos.x, y = pos.y, z = pos.z - 1}
|
||
local back = {x = pos.x, y = pos.y, z = pos.z + 1}
|
||
-- if at this point master is set to "none" the master is NOT known!
|
||
-- in this case for every next block it has to be checked if it is a suitable master, if it is place your stuff in it
|
||
for sidename, nodepos in pairs({top=top, bottom=bottom, left=left, right=right, front=front, back=back}) do -- as long as the order of directions is ok its ok
|
||
-- if the position has already been processed ignore it
|
||
local already_processed = false
|
||
for _, cpos in pairs(processed) do
|
||
if compare_vec(cpos, nodepos) then
|
||
already_processed = true
|
||
break
|
||
end
|
||
end
|
||
if (not already_processed) then
|
||
local node = minetest.get_node(nodepos)
|
||
local meta = minetest.get_meta(nodepos)
|
||
local net_passive = minetest.get_item_group(node.name,"sparktech_net_passive")
|
||
if (net_passive == 0 and meta:get_int("sparktech_net_passive") == 1) then
|
||
net_passive = 1
|
||
end
|
||
local net_trigger = minetest.get_item_group(node.name,"sparktech_net_trigger")
|
||
-- net passives are followed along to create the network (aka cables) but they do not get power,
|
||
-- and are not considered by the network
|
||
-- TODO recursion
|
||
local ntrigontrig = (net_trigger == 1 and (minetest.get_item_group(onode.name, "sparktech_net_trigger") == 0)) -- Only allow trigger node if the source node it not a trigger node
|
||
if (net_trigger == 1 and master == nil) then
|
||
master = nodepos;
|
||
meta:set_string("net_master", nil)
|
||
end -- if no master is set the code will just run around checking for one, if it doesnt find one well, doesnt matter, its just cables then
|
||
if (master ~= nil and ntrigontrig and nodepos ~= master) then -- we have a master, so we can store stuff in it :D
|
||
meta:set_string("net_master", nil)
|
||
-- the node is a trigger, so we store their stuff in the master node
|
||
-- at this point it could be the master if we set it above
|
||
add_node_to_net(nodepos, master) -- we set all relevant data for this node, lets continue there
|
||
|
||
-- Now the node shouldn’t be processed by the net_build anymore
|
||
processed[#processed + 1] = nodepos
|
||
end
|
||
if (net_passive ~= 0 or ntrigontrig) then
|
||
net_build(nodepos, pos)
|
||
end
|
||
end
|
||
end
|
||
-- To have a clear enviroment for the next build we clear the processed list at the final return
|
||
-- TODO This will cause problems if another network is build before the previous network finishes building
|
||
-- Only the node triggering a build won’t have a caller
|
||
if (callerpos == nil) then
|
||
processed = {}
|
||
master = nil
|
||
end
|
||
|
||
return -- at this point all nodes have been processed, so we can return to the calling node
|
||
end
|
||
|
||
local function add_node(pos, newnode)
|
||
local meta = minetest.get_meta(pos)
|
||
if (minetest.get_item_group(newnode.name, "sparktech_net_passive") == 1 or meta:get_int("sparktech_net_passive") ~= 0) then
|
||
net_build(pos) -- only call this with none if the node really is not a trigger, otherwise the net will be build from it but it will not be contained
|
||
elseif (minetest.get_item_group(newnode.name, "sparktech_net_trigger") == 1 ) then
|
||
meta:set_string("net_master", nil)
|
||
net_build(pos, nil, pos)
|
||
end
|
||
end
|
||
|
||
minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
||
add_node(pos, newnode)
|
||
end)
|
||
|
||
local function remove_node(pos, oldnode)
|
||
if (minetest.get_item_group(oldnode.name, "sparktech_net_passive") == TRUE) or (minetest.get_item_group(oldnode.name, "sparktech_net_trigger") == TRUE) then
|
||
minetest.debug("removing nodes...")
|
||
local top = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||
local bottom = {x = pos.x, y = pos.y - 1, z = pos.z}
|
||
local left = {x = pos.x - 1, y = pos.y, z = pos.z}
|
||
local right = {x = pos.x + 1, y = pos.y, z = pos.z}
|
||
local front = {x = pos.x, y = pos.y, z = pos.z - 1}
|
||
local back = {x = pos.x, y = pos.y, z = pos.z + 1}
|
||
for sidename, nodepos in pairs({top=top, bottom=bottom, left=left, right=right, front=front, back=back}) do
|
||
local target_node = minetest.get_node(nodepos)
|
||
add_node(nodepos, target_node)
|
||
end
|
||
end
|
||
end
|
||
|
||
minetest.register_on_dignode(function(pos, oldnode, digger)
|
||
remove_node(pos, oldnode) -- FIXME Get rid of this! Somehow detect if a dynamic net_passive node is destroyed instead of updating speculatively
|
||
-- TODO: I am not sure what this is for, just to get every dig in general? but we already dont allow those nodes to be dug, so dunno
|
||
end)
|
||
|
||
sparktech.add_node_to_net = add_node
|
||
sparktech.remove_node_from_net = remove_node
|