From 5d09ec311c314b195d23c24f599328d26727512a Mon Sep 17 00:00:00 2001 From: cora Date: Thu, 10 Feb 2022 15:05:35 +0100 Subject: [PATCH] Extinguish fire using an ABM instead of timers Even the mitigated timers seem to have lead to slow memory leaks. Once Minetest has used up all the RAM, it will free some, then quickly use memory up again, then repeat it ad nauseum, requiring 100% CPU. On a PC with 2GB of RAM this could be reliably triggered by having a fire burn a forest for 20 to 30 minutes. This patch removes fire node timers completely and instead extinguishes fire using an ABM. --- mods/ITEMS/mcl_fire/init.lua | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/mods/ITEMS/mcl_fire/init.lua b/mods/ITEMS/mcl_fire/init.lua index 8e2383da..3926513e 100644 --- a/mods/ITEMS/mcl_fire/init.lua +++ b/mods/ITEMS/mcl_fire/init.lua @@ -95,10 +95,6 @@ local spawn_fire = function(pos, age) minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z}) end -local function fire_timer(pos) - return minetest.get_node_timer(pos):start(math.random(30, 60)) -end - minetest.register_node("mcl_fire:fire", { description = S("Fire"), _doc_items_longdesc = fire_help, @@ -131,15 +127,6 @@ minetest.register_node("mcl_fire:fire", { end, drop = "", sounds = {}, - on_timer= function(pos) - local p=has_flammable(pos) - if not p or minetest.get_item_group(minetest.get_node(p).name, "flammable") == -1 then - minetest.remove_node(pos) - return - end - -- Restart timer - return true - end, -- Turn into eternal fire on special blocks, light Nether portal (if possible), start burning timer on_construct = function(pos) local bpos = {x=pos.x, y=pos.y-1, z=pos.z} @@ -154,7 +141,6 @@ minetest.register_node("mcl_fire:fire", { mcl_portals.light_nether_portal(pos) end spawn_smoke(pos) - fire_timer(pos) end, on_destruct = function(pos) mcl_particles.delete_node_particlespawners(pos) @@ -433,6 +419,25 @@ else -- Fire enabled end, }) + minetest.register_abm({ + label = "Remove fires", + nodenames = {"mcl_fire:fire"}, + interval = 12, + chance = 4, + catch_up = false, + action = function(pos) + local p=has_flammable(pos) + if p then + local n=minetest.get_node_or_nil(p) + if n and minetest.get_item_group(n.name, "flammable") < 1 then + minetest.remove_node(pos) + end + else + minetest.remove_node(pos) + end + end, + }) + -- Remove flammable nodes around basic flame minetest.register_abm({ label = "Remove flammable nodes", @@ -455,7 +460,6 @@ else -- Fire enabled def._on_burn(p) elseif fgroup ~= -1 then spawn_fire(p) - fire_timer(p) minetest.check_for_falling(p) end end