1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-04 09:42:30 +02:00

Change biter corpse remover.

The biter corpse remover was attempting to be clever about removing corpses and only remove them when they exceeded a certain threshold per chunk. For some reason it is no longer working and I can't figure out why.
So I replaced it with a simpler approach. Now we keep track of the corpses in a queue. When the queue size exceeds the threshold we remove and destroy the oldest corpse.
This commit is contained in:
James Gillham 2021-01-10 15:21:25 +00:00
parent cb2b142e42
commit 21ec6fb120
2 changed files with 28 additions and 104 deletions

View File

@ -402,8 +402,7 @@ global.config = {
-- when biter corpses in an area are above a threshold, remove the desired amount
biter_corpse_remover = {
enabled = true,
chunk_size = 3, -- size of chunk in tiles
corpse_threshold = 3 -- number of corpses allowed on surface inside chunk
max_queue_size = 200 -- The number of corpses to keep in the queue before removing the oldest.
},
turret_active_delay = {
enabled = true,

View File

@ -1,117 +1,42 @@
-- dependencies
local Event = require 'utils.event'
local Global = require 'utils.global'
local table = require 'utils.table'
local remove = table.remove
local pairs = pairs
local next = next
local Queue = require 'utils.queue'
local biter_utils_conf = global.config.biter_corpse_remover
local queue_push = Queue.push
local queue_pop = Queue.pop
local queue_size = Queue.size
-- Factorio removes corpses that hit 15 minutes anyway
local max_corpse_age = 15 * 60 * 60
local kills_per_cleanup = 500
-- config table for the max queue size
-- Change at runtime with /sc global.config.biter_corpse_remover.max_queue_size = 100
local biter_corpse_remover = global.config.biter_corpse_remover
-- x -> y -> array of {entity, tick}
local corpse_chunks = {}
local cleanup_count = {kills_per_cleanup}
local corpse_queue = Queue.new()
Global.register(
{
corpse_chunks = corpse_chunks,
cleanup_count = cleanup_count
},
function(tbl)
corpse_chunks = tbl.corpse_chunks
cleanup_count = tbl.cleanup_count
Global.register(corpse_queue, function(tbl)
corpse_queue = tbl
end)
local function entity_died(event)
if not event.unit_number then
return
end
)
-- cleans up the stored list of corpses and chunks
local function remove_outdated_corpses(now)
-- loop each stored chunk
for x, column in pairs(corpse_chunks) do
for y, corpses in pairs(column) do
local count = #corpses
for i = count, 1, -1 do
if corpses[i].tick < now then
remove(corpses, i)
count = count - 1
end
end
if count == 0 then
column[y] = nil
end
local corpses = event.corpses
for i = 1, #corpses do
local corpse = corpses[i]
if corpse.valid then
queue_push(corpse_queue, corpse)
end
end
if next(column) == nil then
corpse_chunks[x] = nil
local to_remove = queue_size(corpse_queue) - biter_corpse_remover.max_queue_size
for _ = 1, to_remove do
local corpse = queue_pop(corpse_queue)
if corpse.valid then
corpse.destroy()
end
end
end
local function biter_died(event)
local prot = event.prototype
-- Only trigger on dead units
if prot.type ~= 'unit' then
return
end
local entity = event.corpses[1]
-- Ensure there is actually a corpse
if entity == nil then
return
end
local tick = event.tick
-- Chance to clean up old corpses and chunks
local cuc = cleanup_count[1] - 1
if cuc <= 0 then
remove_outdated_corpses(tick)
cleanup_count[1] = kills_per_cleanup
else
cleanup_count[1] = cuc
end
--Calculate the chunk position
local chunk_size = biter_utils_conf.chunk_size
local pos = entity.position
local x, y = pos.x, pos.y
x = x - (x % chunk_size)
y = y - (y % chunk_size)
-- check global table has this position, add if not
local corpse_chunks_column = corpse_chunks[x]
if corpse_chunks_column == nil then
corpse_chunks_column = {}
corpse_chunks[x] = corpse_chunks_column
end
local corpses = corpse_chunks_column[y]
if corpses == nil then
corpses = {}
corpse_chunks_column[y] = corpses
end
-- Add this entity
local count = #corpses + 1
corpses[count] = {
entity = entity,
tick = tick + max_corpse_age
}
-- Cleanup old corpse if above threshold
if count > biter_utils_conf.corpse_threshold then
local old_entity = remove(corpses, 1).entity
if old_entity.valid then
old_entity.destroy()
end
end
end
Event.add(defines.events.on_post_entity_died, biter_died)
Event.add(defines.events.on_post_entity_died, entity_died)