-- 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