This repository has been archived on 2020-05-24. You can view files and clone it, but cannot push or open issues or pull requests.
minetest-mod-sparktech/sparkcore/lua/energy_distrib.lua

165 lines
5.2 KiB
Lua

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