local function round(x) if x >= 0 then return math.floor(x+0.5) else return math.ceil(x-0.5) end end local function wakeup(pos,share) --called to test if a node needs to be woken up local node = minetest.get_node(pos) if (minetest.get_item_group(node.name, "sparktech_energy_wakeup") >= 1) then local ntype = minetest.get_item_group(node.name, "spaktech_energy_type") local meta = minetest.get_meta(pos) local energy = meta:get_int("energy") if (energy == share) then return end -- only makes sense if we actually change the energy in the block if ntype == 2 then if energy == 0 then minetest.get_node_timer(pos):start(0.5) end elseif ntype == 4 then if minetest.get_item_group(node.name, "sparktech_energy_wakeup") == energy then -- set the value to when you want to be woken up key minetest.get_node_timer(pos):start(0.5) end end end end -- 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 net_get_slaves(master) local slaves = {} local meta = minetest.get_meta(master) local slave_s = meta:get_string("net_master") slave_s = string.sub(slave_s, 2) local slave_s_dict = string.split(slave_s, "|") for _, val in pairs(slave_s_dict) do local cor = string.split(val, ":") slaves[#slaves + 1] = { x=tonumber(cor[1]), y=tonumber(cor[2]), z=tonumber(cor[3])} end return slaves end local function net_distribute(pos) -- sparktech_energy_type types: -- 2 - Producer (gets emptied) -- 3 - Storage (backup / overflow) -- 4 - Consumer (gets filled) local nodes = net_get_slaves(pos) nodes[#nodes +1] = pos -- all nodes are in local now -- Gather all information we need for the three node types local energy_pr = 0 local energy_st = 0 local energy_co = 0 local max_energy_pr = 0 local max_energy_st = 0 local max_energy_co = 0 for x = 1, #nodes do local ntype = minetest.get_item_group(minetest.get_node(nodes[x]).name, "sparktech_energy_type") local nenergy = minetest.get_meta(nodes[x]):get_int("energy") local nenergy_max = minetest.get_item_group(minetest.get_node(nodes[x]).name, "sparktech_energy_max") if ntype == 2 then energy_pr = energy_pr + nenergy max_energy_pr = max_energy_pr + nenergy_max elseif ntype == 3 then energy_st = energy_st + nenergy max_energy_st = max_energy_st + nenergy_max elseif ntype == 4 then energy_co = energy_co + nenergy max_energy_co = max_energy_co + nenergy_max end end -- now we know all energy in the system, now to distribute it local pr_new = energy_pr local st_new = energy_st local co_new = energy_co -- How much energy is available to be put into storage / is missing to fill up the consumers local prod_buf = energy_pr - (max_energy_co - energy_co) -- Producers -> Consumers transfer if prod_buf >= 0 then -- Fill up the consumers to their limit pr_new = prod_buf co_new = co_new + (energy_pr - prod_buf) else -- Empty the producers into the consumers pr_new = 0 co_new = co_new + energy_pr end -- Storage -> Consumers and Producers -> Storage transfers if prod_buf < 0 then -- Fill up the consumers with energy in storage local sto_buf = energy_st + prod_buf if sto_buf >= 0 then st_new = sto_buf co_new = co_new + energy_st - sto_buf else st_new = 0 co_new = co_new + energy_st end else -- Store excess energy into storage local st_cap = max_energy_st - energy_st if st_cap >= prod_buf then pr_new = 0 st_new = st_new + prod_buf else pr_new = prod_buf - st_cap st_new = st_new + st_cap end end -- Now the new energy distribution is known -- Apply the later to be improved (maybe) share system to all node types local share_pr = pr_new / max_energy_pr; local share_st = st_new / max_energy_st; local share_co = co_new / max_energy_co; for x = 1, #nodes do local meta = minetest.get_meta(nodes[x]) local node = minetest.get_node(nodes[x]) local ntype = minetest.get_item_group(node.name, "sparktech_energy_type") local nmax = minetest.get_item_group(node.name, "sparktech_energy_max") if ntype == 2 then --produces wakeup(nodes[x], round(share_pr * nmax)) -- TODO: test this meta:set_int("energy", round(share_pr * nmax)) elseif ntype == 3 then --stores meta:set_int("energy", round(share_st * nmax)) elseif ntype == 4 then --consumes wakeup(nodes[x], round(share_co * nmax)) meta:set_int("energy", round(share_co * nmax)) end end end local function filter(pos)-- function is called severall times, only run if this is a master node local meta = minetest.get_meta(pos) local net_master = meta:get_string("net_master") if (net_master == nil or net_master == "") then -- if it is not set this is NOT a master node, so we can ignore it eh return else net_distribute(pos) end end minetest.register_abm({ nodenames = {"group:sparktech_net_trigger"}, interval = 1.0, chance = 1, catch_up = true, action = function(pos, node, active_object_count, active_object_count_wider) filter(pos) end })