From d61803b65f22b5cd32f7938c64578b04dd437154 Mon Sep 17 00:00:00 2001
From: Auke Kok <sofar@foo-projects.org>
Date: Sat, 12 Mar 2016 20:19:37 -0800
Subject: [PATCH] Fire: move fire node removal out of ABM.

Because the fire nodes are not removed 100% when there are
no more burnable nodes nearby, they can potentially stay around
for very, very long times, leading to ABM trains every 5 seconds
for no good reason (only 1 in 16 will be removed every interval).

A much better method to remove fire nodes is to remove them by
timer, and give removal a 100% chance if no flammable nodes are
adjacent. This makes fire cleanup a lot faster and more natural,
and will reduce the amount of ABM hits making fire overall more
responsive.

We also remove the 1 in 4 chance and fold the removal of flammable
nodes into the ABM chance.

There's some low hanging fruit cleanups in here as well.
---
 mods/fire/init.lua | 56 +++++++++++++++-------------------------------
 1 file changed, 18 insertions(+), 38 deletions(-)

diff --git a/mods/fire/init.lua b/mods/fire/init.lua
index 457f6b5..832b701 100644
--- a/mods/fire/init.lua
+++ b/mods/fire/init.lua
@@ -28,14 +28,24 @@ minetest.register_node("fire:basic_flame", {
 	sunlight_propagates = true,
 	damage_per_second = 4,
 	groups = {igniter = 2, dig_immediate = 3, not_in_creative_inventory = 1},
+	on_timer = function(pos)
+		local f = minetest.find_node_near(pos, 1, {"group:flammable"})
+		if not f then
+			minetest.remove_node(pos)
+			return
+		end
+		-- restart timer
+		return true
+	end,
 	drop = "",
 
 	on_construct = function(pos)
-		minetest.after(0, fire.on_flame_add_at, pos)
+		minetest.get_node_timer(pos):start(math.random(30, 60))
+		minetest.after(0, fire.update_sounds_around, pos)
 	end,
 
 	on_destruct = function(pos)
-		minetest.after(0, fire.on_flame_remove_at, pos)
+		minetest.after(0, fire.update_sounds_around, pos)
 	end,
 
 	on_blast = function()
@@ -169,32 +179,6 @@ function fire.update_sounds_around(pos)
 end
 
 
--- Update fire sounds on flame node construct or destruct
-
-function fire.on_flame_add_at(pos)
-	fire.update_sounds_around(pos)
-end
-
-
-function fire.on_flame_remove_at(pos)
-	fire.update_sounds_around(pos)
-end
-
-
--- Return positions for flames around a burning node
-
-function fire.find_pos_for_flame_around(pos)
-	return minetest.find_node_near(pos, 1, {"air"})
-end
-
-
--- Detect nearby extinguishing nodes
-
-function fire.flame_should_extinguish(pos)
-	return minetest.find_node_near(pos, 1, {"group:puts_out_fire"})
-end
-
-
 -- Extinguish all flames quickly with water, snow, ice
 
 minetest.register_abm({
@@ -239,31 +223,27 @@ else
 		catch_up = false,
 		action = function(p0, node, _, _)
 			-- If there is water or stuff like that around node, don't ignite
-			if fire.flame_should_extinguish(p0) then
+			if minetest.find_node_near(p0, 1, {"group:puts_out_fire"}) then
 				return
 			end
-			local p = fire.find_pos_for_flame_around(p0)
+			local p = minetest.find_node_near(p0, 1, {"air"})
 			if p then
 				minetest.set_node(p, {name = "fire:basic_flame"})
 			end
 		end,
 	})
 
-	-- Remove basic flames and flammable nodes
+	-- Remove flammable nodes
 
 	minetest.register_abm({
 		nodenames = {"fire:basic_flame"},
+		neighbors = "group:flammable",
 		interval = 5,
-		chance = 6,
+		chance = 18,
 		catch_up = false,
 		action = function(p0, node, _, _)
-			-- If there are no flammable nodes around flame, remove flame
 			local p = minetest.find_node_near(p0, 1, {"group:flammable"})
-			if not p then
-				minetest.remove_node(p0)
-				return
-			end
-			if math.random(1, 3) == 1 then
+			if p then
 				-- remove flammable nodes around flame
 				local node = minetest.get_node(p)
 				local def = minetest.registered_nodes[node.name]