666 lines
24 KiB
Lua
666 lines
24 KiB
Lua
local rpath = (...):match("(.-)[^%.]+$")
|
|
local rroot = rpath:match("^([^%.]+%.)")
|
|
local get_reactor_core_power = require(rroot .. "entity.util").get_reactor_core_power
|
|
local mod = require(rpath .. "init")
|
|
local heat_buffer_transition_position = require(rpath .. "buffer").heat_buffer_transition_position
|
|
local heat_buffer_transitions = require(rpath .. "buffer").heat_buffer_transitions
|
|
local netmath = require(rpath .. "math")
|
|
local getpath = netmath.getpath
|
|
local testpath = netmath.testpath
|
|
local is_connected_outside = netmath.is_connected_outside
|
|
local chunk_nodes = netmath.chunk_nodes
|
|
local cell_nodes = netmath. cell_nodes
|
|
local connected_cells = netmath.connected_cells
|
|
local neighbour_cells = netmath.neighbour_cells
|
|
local get_chunk_neighbour = netmath.get_chunk_neighbour
|
|
local get_linked_entities = netmath.get_linked_entities
|
|
local get_entity_neighbour_cells = netmath.get_entity_neighbour_cells
|
|
local clear_heat_network_for_surface = netmath.clear_heat_network_for_surface
|
|
local cleanup_heat_network = netmath.cleanup_heat_network
|
|
local rm_heat_network_cell = netmath.rm_heat_network_cell
|
|
local get_heat_network_cell = netmath.get_heat_network_cell
|
|
local set_heat_network_cell = netmath.set_heat_network_cell
|
|
local get_heat_outlet = netmath.get_heat_outlet
|
|
local set_heat_outlet = netmath.set_heat_outlet
|
|
local isempty = require(rroot .. "util").isempty
|
|
local debug = require(rpath .. "debug")
|
|
local util = require(rpath .. "util")
|
|
local get2d = util.get2d
|
|
local set2d = util.set2d
|
|
local rm2d = util. rm2d
|
|
local sameposition = util.sameposition
|
|
-- local growarea = util. growarea
|
|
-- local subarea = util. subarea
|
|
-- local shrinkarea = util.shrinkarea
|
|
|
|
|
|
local function Coordinates(entity)
|
|
local x,y,z = entity.position.x,entity.position.y,entity.surface.index
|
|
return math.floor(x), math.floor(y), z
|
|
end
|
|
|
|
local CHUNK_SIZE = 32 -- in tiles
|
|
local function ChunkCoordinates(x,y,z)
|
|
return math.floor(x / CHUNK_SIZE), math.floor(y / CHUNK_SIZE), z
|
|
end
|
|
|
|
local function Vector(x,y,z) return {
|
|
x = x,
|
|
y = y,
|
|
z = z,
|
|
} end
|
|
|
|
-- FIXME area not used! could be removed or used to pimp split?
|
|
-- function Area(...) return {
|
|
-- left_top = Vector(...),
|
|
-- right_bottom = Vector(...),
|
|
-- } end
|
|
|
|
local function ChunkArea(x,y) return {
|
|
left_top = Vector(CHUNK_SIZE * (0 + x) - 0, CHUNK_SIZE * (0 + y) - 0),
|
|
right_bottom = Vector(CHUNK_SIZE * (1 + x) - 1, CHUNK_SIZE * (1 + y) - 1),
|
|
} end
|
|
|
|
local function ReactorPosition(entity) return {
|
|
id = entity.unit_number,
|
|
name = entity.name,
|
|
position = Vector(Coordinates(entity)),
|
|
-- cell = HeatNetworkCell(), -- HeatNetworkCell which the reactor belongs to
|
|
} end
|
|
|
|
local function HeatChunk(...) return {
|
|
position = Vector(ChunkCoordinates(...)),
|
|
area = ChunkArea(ChunkCoordinates(...)),
|
|
cells = {}, -- array of HeatNetworkCell indexed by itself
|
|
-- network = HeatNetwork(), -- network this chunk belongs to
|
|
border = {
|
|
[N] = {}, -- array of HeatNetworkCell indexed by x
|
|
[E] = {}, -- array of HeatNetworkCell indexed by y
|
|
[S] = {}, -- array of HeatNetworkCell indexed by x
|
|
[W] = {}, -- array of HeatNetworkCell indexed by y
|
|
},
|
|
count = {
|
|
cell = 0, -- number of HeatNetworkCell
|
|
[N] = 0, -- number of HeatNetworkCell
|
|
[E] = 0, -- number of HeatNetworkCell
|
|
[S] = 0, -- number of HeatNetworkCell
|
|
[W] = 0, -- number of HeatNetworkCell
|
|
},
|
|
} end
|
|
|
|
|
|
-- only required for debugging
|
|
local function HeatNetworkId()
|
|
local i = -1
|
|
for id in pairs(HEAT.ids) do
|
|
i = math.max(i,id)
|
|
end
|
|
local id = i + 1
|
|
HEAT.ids[id] = id
|
|
-- log("create new network " .. tostring(id))
|
|
return id -- uniq number
|
|
end
|
|
|
|
local function HeatNetwork() return {
|
|
id = HeatNetworkId(),
|
|
reactors = {}, -- array of ReactorPosition indexed by entity.unit_number
|
|
chunks = {}, -- array of HeatChunk indexed by x,y
|
|
count = {
|
|
chunk = 0, -- number of HeatChunk
|
|
cell = 0, -- number of HeatNetworkCell
|
|
reactor = 0, -- number of reactors
|
|
},
|
|
} end
|
|
|
|
local function HeatNetworkCell() return {
|
|
-- chunk = HeatChunk(), -- chunk this cell belongs to
|
|
entities = {}, -- matrix of heat-pipe and reactor entities indexed by x,y
|
|
reactors = {}, -- array of ReactorPosition indexed by entity.unit_number
|
|
-- area = Area(), -- bounding box of network
|
|
count = {
|
|
entity = 0, -- number of heat-pipes
|
|
reactor = 0, -- number of reactors
|
|
outlet = 0, -- number of reactor outlets
|
|
},
|
|
} end
|
|
|
|
|
|
|
|
local function set_chunk_borders(chunk, x,y, cell)
|
|
local p = Vector(x,y)
|
|
local count = cell and 1 or -1
|
|
for _,corner in ipairs{'left_top','right_bottom'} do
|
|
for k,v in pairs(p) do
|
|
if chunk.area[corner][k] == v then
|
|
local d = A[corner][k]
|
|
chunk.border[d][p[V[k]]] = cell
|
|
chunk.count[d] = chunk.count[d] + count
|
|
-- log(string.format("%s chunk border in network %s at x=%s y=%s", cell and "add cell to" or "remove cell from", chunk.network.id, x,y))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function get_or_create_heat_network_chunk(x,y,z, network)
|
|
local cx,cy = ChunkCoordinates(x,y,z)
|
|
local chunk = get2d(network.chunks, cx,cy)
|
|
if chunk then return chunk end
|
|
chunk = HeatChunk(x,y,z)
|
|
chunk.network = network
|
|
-- log(string.format("create new chunk in network %s at x=%s y=%s z=%s", network.id, chunk.position.x,chunk.position.y,chunk.position.z))
|
|
set2d(network.chunks, cx,cy, chunk)
|
|
network.count.chunk = network.count.chunk + 1
|
|
return chunk
|
|
end
|
|
|
|
local function create_heat_network_cell(x,y,z, network)
|
|
local chunk = get_or_create_heat_network_chunk(x,y,z, network)
|
|
local cell = HeatNetworkCell()
|
|
-- log(string.format("create heat network cell in network %s at x=%s y=%s z=%s", network.id, x,y,z))
|
|
-- cell.area = growarea(cell.area, Area(x,y))
|
|
network.count.cell = network.count.cell + 1
|
|
chunk.count.cell = chunk.count.cell + 1
|
|
chunk.cells[cell] = cell
|
|
cell.chunk = chunk
|
|
return cell
|
|
end
|
|
|
|
local function create_heat_network(x,y,z)
|
|
local network = HeatNetwork()
|
|
local cell = create_heat_network_cell(x,y,z, network)
|
|
HEAT.network[network.id] = network
|
|
-- log(string.format("created heat network %s", network.id))
|
|
return cell
|
|
end
|
|
|
|
local function remove_heat_network(x,y,z, cell)
|
|
local chunk,network = cell.chunk,cell.chunk.network
|
|
rm_heat_network_cell(x,y,z)
|
|
set_chunk_borders(chunk, x,y, nil)
|
|
-- log(string.format("removed heat network %s", network.id))
|
|
if cell.count.entity + cell.count.reactor + cell.count.outlet > 0 then return end
|
|
chunk.cells[cell] = nil
|
|
chunk.count.cell = chunk.count.cell - 1
|
|
network.count.cell = network.count.cell - 1
|
|
if chunk.count.cell > 0 then return end
|
|
rm2d(network.chunks, chunk.position.x,chunk.position.y)
|
|
network.count.chunk = network.count.chunk - 1
|
|
if network.count.chunk > 0 then return end
|
|
-- network gets garbage collected
|
|
cleanup_heat_network(network.id)
|
|
end
|
|
|
|
|
|
local move_entities
|
|
local function move_cells(cell, position, offset, network, neighbours, inside, last, dst, ignore)
|
|
local old = cell.chunk
|
|
local x,y,z = position.x+offset.x,position.y+offset.y,old.position.z
|
|
if cell == ignore then
|
|
local entity = get2d(cell.entities, x,y)
|
|
if entity then
|
|
if inside[entity] == inside[last] then
|
|
-- log(string.format("leafing recursion cuz cell is connected inside at x=%s y=%s", x,y))
|
|
return
|
|
end
|
|
-- log(string.format("return to crawling at x=%s y=%s", x,y))
|
|
dst = create_heat_network_cell(x,y,z, network)
|
|
move_entities(entity, Vector(x,y), dst,cell, neighbours, inside)
|
|
end
|
|
return -- to crawling
|
|
end
|
|
local new = get_or_create_heat_network_chunk(x,y,z, network)
|
|
if old.network == new.network then return end
|
|
-- log(string.format("move cells into network %s from %s at x=%s y=%s z=%s", network.id,old.network.id, x,y,z))
|
|
cell.chunk = new
|
|
old.cells[cell] = nil
|
|
new.cells[cell] = cell
|
|
old.count.cell = old.count.cell - 1
|
|
new.count.cell = new.count.cell + 1
|
|
old.network.count.cell = old.network.count.cell - 1
|
|
network.count.cell = network.count.cell + 1
|
|
for id,reactor in pairs(cell.reactors) do
|
|
if not network.reactors[id] then
|
|
old.network.reactors[id] = nil
|
|
network.reactors[id] = reactor
|
|
old.network.count.reactor = old.network.count.reactor - 1
|
|
network.count.reactor = network.count.reactor + 1
|
|
end
|
|
end
|
|
if not (old.count.cell > 0) then
|
|
rm2d(old.network.chunks, ChunkCoordinates(x,y))
|
|
old.network.count.chunk = old.network.count.chunk - 1
|
|
end
|
|
neighbour_cells(old, cell, move_cells, network, neighbours, inside, last, dst, ignore)
|
|
set_chunk_borders(old, x,y, nil)
|
|
set_chunk_borders(new, x,y, cell)
|
|
for d in pairs(O) do
|
|
for c,other in pairs(old.border[d]) do
|
|
if other == cell then
|
|
old.border[d][c] = nil
|
|
new.border[d][c] = cell
|
|
old.count[d] = old.count[d] - 1
|
|
new.count[d] = new.count[d] + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
move_entities = function (entity, position, new,old, neighbours, inside) -- salami tactics
|
|
local x,y,z = position.x,position.y,old.chunk.position.z -- use this instead of entity.position which could be in another cell
|
|
if not get2d(old.entities, x,y) then
|
|
local other = get_heat_network_cell(x,y,z)
|
|
if other ~= old then -- found outside
|
|
move_cells(other, position, Vector(0,0), new.chunk.network, neighbours,inside,entity,new,old)
|
|
end
|
|
return
|
|
end
|
|
-- log(string.format("move entity between networks from %s to %s at x=%s y=%s z=%s %s", old.chunk.network.id, new.chunk.network.id, x,y,z, serpent.line{from=old.count,to=new.count}))
|
|
-- new.area = growarea(new.area, Area(x,y))
|
|
if entity.type ~= "reactor" then
|
|
old.count.entity = old.count.entity - 1
|
|
new.count.entity = new.count.entity + 1
|
|
elseif old.reactors[entity.unit_number] then
|
|
old.count.reactor = old.count.reactor - 1
|
|
new.count.reactor = new.count.reactor + 1
|
|
local reactor = old.reactors[entity.unit_number]
|
|
old.reactors[reactor.id] = nil
|
|
new.reactors[reactor.id] = reactor
|
|
reactor.cell = new
|
|
old.chunk.network.reactors[reactor.id] = nil
|
|
new.chunk.network.reactors[reactor.id] = reactor
|
|
old.chunk.network.count.reactor = old.chunk.network.count.reactor - 1
|
|
new.chunk.network.count.reactor = new.chunk.network.count.reactor + 1
|
|
else
|
|
old.count.outlet = old.count.outlet - 1
|
|
new.count.outlet = new.count.outlet + 1
|
|
end
|
|
rm2d(old.entities, x,y)
|
|
set2d(new.entities, x,y, entity)
|
|
if old.chunk.network ~= new.chunk.network then
|
|
get_chunk_neighbour(old, x,y, move_cells, new.chunk.network, neighbours,inside,entity,new,old)
|
|
end
|
|
remove_heat_network(x,y,z, old)
|
|
set_heat_network_cell(x,y,z, new)
|
|
set_chunk_borders(new.chunk, x,y, new)
|
|
neighbours(entity, move_entities, new,old, neighbours, inside)
|
|
end
|
|
|
|
|
|
local function is_border(area,p)
|
|
for _,corner in ipairs{'left_top','right_bottom'} do
|
|
for k,v in pairs(p) do
|
|
if v == area[corner][k] then return true end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
local function counter(cell,_,count) count[cell], count.value = true, count.value + 1 end
|
|
local function insert_table(e,p,a,b) table.insert(a,e) table.insert(b,p) end
|
|
local function split_heat_network_cell(cell,x,y,z,entity)
|
|
local count = {value=0}
|
|
get_entity_neighbour_cells(entity, counter, count)
|
|
if count.value < 2 then return end -- this was the last
|
|
-- log(string.format("try to split network %s at at x=%s y=%s z=%s %s ", cell.chunk.network.id, x,y,z, entity.name))
|
|
-- log(dbgHeatNetwork(cell.chunk.network))
|
|
-- local area
|
|
local others,positions = {},{}
|
|
local outside,inside = get_linked_entities(cell)
|
|
local chunk_neighbours = chunk_nodes(cell.entities, outside)
|
|
local cell_neighbours = cell_nodes(cell.entities)
|
|
chunk_neighbours(entity, insert_table, others, positions)
|
|
local n,c = #others,table_size(count)-1
|
|
-- log(string.format("found %s entities in %s cells inside of %s total", n,c,count.value))
|
|
if n == 0 then return elseif n == 1 then
|
|
if not is_border(cell.chunk.area, Vector(x,y)) then return end
|
|
-- log(string.format("split heat network alone %s", serpent.line{count=cell.count}))
|
|
local connected = false
|
|
get_entity_neighbour_cells(entity, function (neighbour)
|
|
if not connected and cell.chunk ~= neighbour.chunk then
|
|
connected = testpath(cell, neighbour, connected_cells) -- outside
|
|
end
|
|
end)
|
|
if connected then -- outside connected
|
|
-- log(" ... but nothing happens, cuz cells are connected on the outside")
|
|
else
|
|
local p,other = positions[1],others[1]
|
|
local new = create_heat_network(p.x,p.y,z)
|
|
move_entities(other, p, new,cell, cell_neighbours, inside)
|
|
-- log("moved into new network " .. tostring(new.chunk.network.id))
|
|
-- log(dbgHeatNetwork(new.chunk.network))
|
|
end
|
|
return -- weird, lol
|
|
end
|
|
if c > 1 then
|
|
get_entity_neighbour_cells(entity, function (other,p)
|
|
if other ~= cell then
|
|
if not testpath(cell, other, connected_cells) then -- outside
|
|
local new = create_heat_network(p.x,p.y,z)
|
|
move_cells(other, p, Vector(0,0), new.chunk.network, cell_neighbours,new,cell)
|
|
-- log("moved neighbour into new network " .. tostring(new.chunk.network.id))
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
local before = others[n]
|
|
-- log(string.format("split heat network %s", serpent.line{count=cell.count}))
|
|
for i,other in ipairs(others) do
|
|
local p = positions[i]
|
|
if get2d(cell.entities, p.x,p.y) then
|
|
if before and before ~= other then
|
|
local path = getpath(before, other, chunk_neighbours)
|
|
if path and #path == 2 and path[1] == entity then path = nil --[[log"WTF"]] end
|
|
local outside = is_connected_outside(path)
|
|
if path then
|
|
-- log(string.format("found path of length %s %sside", #path, outside and "out" or "in"))
|
|
for _,node in ipairs(path) do
|
|
-- log(node.name .. ": " .. dbgVector(node.position))
|
|
end
|
|
end
|
|
if not path or outside then
|
|
-- TODO determine which half is now smaller then the other and fill-move the smaller one. -- maybe impossibru ? -- maybe with area?
|
|
local network
|
|
if path then -- outside
|
|
if not testpath(before, other, cell_neighbours) then -- inside
|
|
-- log("splitting cell inside network")
|
|
local new = create_heat_network_cell(p.x,p.y,z, cell.chunk.network)
|
|
move_entities(other, p, new,cell, cell_neighbours, inside)
|
|
network = new.chunk.network
|
|
end
|
|
else -- inside
|
|
local new = create_heat_network(p.x,p.y,z)
|
|
move_entities(other, p, new,cell, cell_neighbours, inside)
|
|
network = new.chunk.network
|
|
end
|
|
-- area = growarea(area, new.area)
|
|
other = nil -- skip this before
|
|
if not path then
|
|
-- log("moved into new network " .. tostring(network.id))
|
|
-- log(dbgHeatNetwork(network))
|
|
end
|
|
end
|
|
end
|
|
before = other or before
|
|
end
|
|
end
|
|
-- cell.area = subarea(area, cell.area)
|
|
end
|
|
|
|
|
|
local function network_score(network)
|
|
local count = network.count
|
|
return count.chunk + count.cell + count.reactor
|
|
end
|
|
local function chunk_score(chunk)
|
|
local sum = 0 for _,count in pairs(chunk.count) do sum = sum + count end
|
|
return sum + network_score(chunk.network)
|
|
end
|
|
local function cell_score(cell)
|
|
local count = cell.count
|
|
return 2 * count.entity + count.reactor + count.outlet + chunk_score(cell.chunk)
|
|
end
|
|
|
|
local function merge_heat_chunk(a,b)
|
|
if chunk_score(a) < chunk_score(b) then a,b = b,a end -- spare some work
|
|
-- log(string.format("merge heat chunk at x=%s y=%s z=%s", a.position.x,a.position.y,a.position.z))
|
|
for k,count in pairs(b.count) do
|
|
a.count[k] = a.count[k] + count
|
|
end
|
|
for cell in pairs(b.cells) do
|
|
a.cells[cell] = cell
|
|
cell.chunk = a
|
|
end
|
|
for d,border in pairs(b.border) do
|
|
for c,cell in pairs(border) do
|
|
a.border[d][c] = cell
|
|
end
|
|
end
|
|
return a
|
|
end
|
|
|
|
local function merge_heat_network(a,b)
|
|
local an,bn = a.chunk.network, b.chunk.network
|
|
if an ~= bn then
|
|
if cell_score(a) < cell_score(b) then an,bn = bn,an end -- spare some work
|
|
-- log(string.format("merge heat network %s into %s %s", bn.id, an.id, serpent.line{from=bn.count,to=an.count}))
|
|
for k,count in pairs(bn.count) do
|
|
an.count[k] = an.count[k] + count
|
|
end
|
|
for id,reactor in pairs(bn.reactors) do
|
|
an.reactors[id] = reactor
|
|
end
|
|
for x,xs in pairs(bn.chunks) do
|
|
for y,chunk in pairs(xs) do
|
|
local current = get2d(an.chunks, x,y)
|
|
chunk.network = an
|
|
if current then
|
|
an.count.chunk = an.count.chunk - 1
|
|
chunk = merge_heat_chunk(current, chunk)
|
|
end
|
|
set2d(an.chunks, x,y, chunk)
|
|
end
|
|
end
|
|
cleanup_heat_network(bn.id)
|
|
end
|
|
return a
|
|
end
|
|
|
|
local function merge_heat_network_cells(x,y,z, a,b)
|
|
if not b or b == a then return a end
|
|
if sameposition(a.chunk.position, b.chunk.position) then
|
|
if cell_score(a) < cell_score(b) then a,b = b,a end -- spare some work
|
|
-- log(string.format("merge heat network cells %s into %s %s", b.chunk.network.id, a.chunk.network.id, serpent.line{from=b.count,to=a.count}))
|
|
-- a.area = growarea(a.area, b.area)
|
|
for k,count in pairs(b.count) do
|
|
a.count[k] = a.count[k] + count
|
|
end
|
|
local z = a.chunk.position.z
|
|
for x,xs in pairs(b.entities) do
|
|
for y,entity in pairs(xs) do
|
|
set2d(a.entities, x,y, entity)
|
|
set_heat_network_cell(x,y,z, a)
|
|
set_chunk_borders(b.chunk, x,y, nil)
|
|
set_chunk_borders(a.chunk, x,y, a)
|
|
end
|
|
end
|
|
for _,reactor in pairs(b.reactors) do
|
|
local p = reactor.position
|
|
reactor.cell = a
|
|
a.reactors[reactor.id] = reactor
|
|
end
|
|
for d,border in pairs(b.chunk.border) do
|
|
for c,cell in pairs(border) do
|
|
if cell == b then
|
|
a.chunk.border[d][c] = a
|
|
end
|
|
end
|
|
end
|
|
b.chunk.cells[b] = nil
|
|
b.chunk.count.cell = b.chunk.count.cell - 1
|
|
b.chunk.network.count.cell = b.chunk.network.count.cell - 1
|
|
end
|
|
return merge_heat_network(a,b)
|
|
end
|
|
|
|
|
|
local function add_entity_to_network_cell(x,y,z,entity)
|
|
local cell = create_heat_network(x,y,z)
|
|
local is_reactor = entity.type == 'reactor'
|
|
for i,p,o in heat_buffer_transitions(entity) do
|
|
-- add heat pipe neighbours
|
|
-- log(string.format("looking at x=%s y=%s for heat network cell", o.x,o.y))
|
|
cell = merge_heat_network_cells(x,y,z, cell, get_heat_network_cell(o.x,o.y,z))
|
|
-- add reactor neighbours
|
|
if is_reactor or i == 1 then -- assuming heat pipe is just one tile in size (all connection positions are the same)
|
|
local reactors = get_heat_outlet(p.x,p.y,z, {})
|
|
-- log(string.format("test x=%s y=%s for outlet with %s reactors", p.x,p.y, table_size(reactors)))
|
|
for _,reactor in pairs(reactors) do
|
|
local q = heat_buffer_transition_position(reactor, reactor.position,p)
|
|
cell = merge_heat_network_cells(x,y,z, cell, get_heat_network_cell(q.x,q.y,z))
|
|
end
|
|
end
|
|
end
|
|
set_heat_network_cell(x,y,z, cell)
|
|
set_chunk_borders(cell.chunk, x,y, cell)
|
|
set2d(cell.entities, x,y, entity)
|
|
if is_reactor then
|
|
cell.chunk.network.count.reactor = cell.chunk.network.count.reactor + 1
|
|
cell.count.reactor = cell.count.reactor + 1
|
|
else
|
|
cell.count.entity = cell.count.entity + 1
|
|
end
|
|
-- log(string.format("added cell to network %s at x=%s y=%s z=%s %s", cell.chunk.network.id, x,y,z, serpent.line{count=cell.count}))
|
|
return cell
|
|
end
|
|
|
|
local function remove_entity_from_network_cell(x,y,z,entity,cell)
|
|
local network = cell.chunk.network
|
|
if entity.type ~= "reactor" then
|
|
cell.count.entity = cell.count.entity - 1
|
|
else
|
|
cell.chunk.network.count.reactor = cell.chunk.network.count.reactor - 1
|
|
cell.count.reactor = cell.count.reactor - 1
|
|
end
|
|
rm2d(cell.entities, x,y)
|
|
remove_heat_network(x,y,z, cell)
|
|
if cell.count.entity + cell.count.reactor + cell.count.outlet > 0 then
|
|
split_heat_network_cell(cell, x,y,z, entity)
|
|
end
|
|
-- shrinkarea(cell.area,cell.entities) -- shrink area by entity on border
|
|
-- log(string.format("removed cell from network %s at x=%s y=%s z=%s %s", cell.chunk.network.id, x,y,z, serpent.line{count=cell.count}))
|
|
-- log(dbgHeatNetwork(network))
|
|
end
|
|
|
|
|
|
local function get_heat_network(entity)
|
|
local cell = get_heat_network_cell(Coordinates(entity))
|
|
return cell and cell.chunk.network
|
|
end
|
|
|
|
local function get_connected_reactors(entity)
|
|
local network = get_heat_network(entity)
|
|
return network and network.reactors or {}
|
|
end
|
|
|
|
|
|
local function calculate_corner_index(area, x,y)
|
|
local i = 1
|
|
if x < area.left_top.x or area.right_bottom.x < x then i = i + 1 end
|
|
if y < area.left_top.y or area.right_bottom.y < y then i = i + 2 end
|
|
return i -- {1=(x,y inside area), 2=(x outside area), 3=(y outside area), 4=(x,y outside area)}
|
|
end
|
|
local function add_reactor_to_network(entity)
|
|
if get_reactor_core_power(entity) then return end -- ignore reactor cores
|
|
local x,y,z = Coordinates(entity)
|
|
-- log(string.format("add reactor to network x=%s y=%s z=%s", x,y,z))
|
|
local cell = add_entity_to_network_cell(x,y,z,entity)
|
|
local reactor = ReactorPosition(entity)
|
|
cell.chunk.network.reactors[reactor.id] = reactor
|
|
cell.reactors[reactor.id] = reactor
|
|
reactor.cell = cell
|
|
-- merge outlets
|
|
local corner = {cell} -- up to 4 cells
|
|
for _,p,o in heat_buffer_transitions(entity) do
|
|
local reactors = get_heat_outlet(o.x,o.y,z, {})
|
|
-- log(string.format("outlet at x=%s y=%s z=%s with %s others", o.x,o.y,z, table_size(reactors)))
|
|
reactors[reactor.id] = reactor
|
|
set_heat_outlet(o.x,o.y,z, reactors)
|
|
local i = calculate_corner_index(cell.chunk.area, p.x,p.y)
|
|
local other = corner[i] or create_heat_network_cell(p.x,p.y,z, cell.chunk.network)
|
|
if not get2d(other.entities, p.x,p.y) then
|
|
other.count.outlet = other.count.outlet + 1
|
|
set2d(other.entities, p.x,p.y, entity)
|
|
set_chunk_borders(other.chunk, p.x,p.y, other)
|
|
set_heat_network_cell(p.x,p.y,z, other)
|
|
end
|
|
other = merge_heat_network_cells(p.x,p.y,z, other, get_heat_network_cell(o.x,o.y,z))
|
|
corner[i] = other
|
|
end
|
|
debug.update()
|
|
end
|
|
|
|
|
|
local function remove_reactor_from_network(entity)
|
|
if get_reactor_core_power(entity) then return end -- ignore reactor cores
|
|
local x,y,z = Coordinates(entity)
|
|
local cell = get_heat_network_cell(x,y,z)
|
|
local reactor = cell and cell.reactors[entity.unit_number]
|
|
if not reactor then return end
|
|
-- log(string.format("remove reactor from network cell %s at x=%s y=%s z=%s %s", cell.chunk.network.id, x,y,z, serpent.line{count=cell.count}))
|
|
-- cleanup outlets
|
|
local remove = {}
|
|
for _,p,o in heat_buffer_transitions(entity) do
|
|
local reactors = get_heat_outlet(o.x,o.y,z, {})
|
|
reactors[reactor.id] = nil
|
|
if isempty(reactors) then reactors = nil end
|
|
set_heat_outlet(o.x,o.y,z, reactors)
|
|
set2d(remove, p.x,p.y, get_heat_network_cell(p.x,p.y,z))
|
|
end
|
|
-- remove from cells now cuz of duplicate positions
|
|
for x,xs in pairs(remove) do
|
|
for y,other in pairs(xs) do
|
|
other.count.outlet = other.count.outlet - 1
|
|
remove_heat_network(x,y,z, other)
|
|
set_chunk_borders(other.chunk, x,y)
|
|
rm2d(other.entities, x,y)
|
|
end
|
|
end
|
|
remove_entity_from_network_cell(x,y,z, entity, cell)
|
|
cell.chunk.network.reactors[reactor.id] = nil
|
|
cell.reactors[reactor.id] = nil
|
|
reactor.cell = nil
|
|
debug.update()
|
|
end
|
|
|
|
|
|
local function add_heat_pipe_to_network(entity)
|
|
local x,y,z = Coordinates(entity)
|
|
-- log(string.format("add heat pipe to network cell at x=%s y=%s z=%s", x,y,z))
|
|
add_entity_to_network_cell(x,y,z,entity)
|
|
debug.update()
|
|
end
|
|
|
|
local function remove_heat_pipe_from_network(entity)
|
|
local x,y,z = Coordinates(entity)
|
|
local cell = get_heat_network_cell(x,y,z)
|
|
if not cell then return end
|
|
-- log(string.format("remove heat pipe from network cell %s at x=%s y=%s z=%s %s", cell.chunk.network.id, x,y,z, serpent.line{count=cell.count}))
|
|
remove_entity_from_network_cell(x,y,z, entity, cell)
|
|
debug.update()
|
|
end
|
|
|
|
|
|
local function remove_heat_network_from_surface(z)
|
|
-- log("clear heat networks on surface " .. tostring(z))
|
|
clear_heat_network_for_surface(z)
|
|
debug.update()
|
|
end
|
|
|
|
local function remove_heat_network_from_chunk(x,y,z) -- chunk coords
|
|
-- log(string.format("clear heat networks from chunk at x=%s y=%s z=%s", x,y,z))
|
|
local area = ChunkArea(ChunkCoordinates(x,y,z))
|
|
for x = area.left_top.x, area.right_bottom.x do
|
|
for y = area.left_top.y, area.right_bottom.y do
|
|
local cell = get_heat_network_cell(x,y,z)
|
|
if cell then remove_heat_network(x,y,z, cell) end
|
|
end
|
|
end
|
|
debug.update()
|
|
end
|
|
|
|
|
|
-- circular dependency
|
|
mod.add_reactor = add_reactor_to_network
|
|
mod.add_heat_pipe = add_heat_pipe_to_network
|
|
return { -- exports
|
|
init=mod.init, load=mod.load,
|
|
get = get_heat_network,
|
|
get_connected_reactors = get_connected_reactors,
|
|
add_reactor = add_reactor_to_network,
|
|
remove_reactor = remove_reactor_from_network,
|
|
add_heat_pipe = add_heat_pipe_to_network,
|
|
remove_heat_pipe = remove_heat_pipe_from_network,
|
|
remove_from_surface = remove_heat_network_from_surface,
|
|
remove_from_chunk = remove_heat_network_from_chunk,
|
|
debug = debug,
|
|
}
|