ITEMS/mcl_fire: Fix fire spread to not freeze the game #234
No reviewers
Labels
No Label
blocker
bug
code quality
confirmed
critical
discussion
high priority
incompatibility
incomplete feature
invalid
low priority
missing feauture
needs testing
packet spam
performance
project
regression
translations
unconfirmed
in review
ready for review
No Milestone
No project
No Assignees
3 Participants
Due Date
No due date set.
Depends on
#258 MAPGEN/mcl_structures: Add (theoretically) fireproof test structure
Mineclonia/Mineclonia
Reference: Mineclonia/Mineclonia#234
Loading…
Reference in New Issue
No description provided.
Delete Branch "fix-fire"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
TRACKING ISSUE: #174
Fire spread in Mineclonia is currently so inefficient that it quickly locks up a cpu preventing new clients to join. While this is just slow in singleplayer it makes multiplayer completely non functional (if there is a loaded large fire).
Solution
tl;dr: replace node timers with abms like the original fire mod from mtg does (which this was clearly adapted from).
Details
The information in the minecraft wiki is fairly incomplete but what is available there (i.e. the distances fire will spread) was implemented here. There is no information in there about how often or what chances there are for fire spread so the original abm values from mtg for "chance" and "interval" were taken.
Testing Steps
Note you can use any other map seed but "fire" on flat mapgen has a conveniently placed dense forest right at spawn.
Reproducing
Testing fix
(or just take the one you just started)it has to be a new world because the old one's fires will still have the old laggy node timers.does not max out no matter how large you make the fire.impact is negligible compared to the situation before (what do i know what slow cpus you guys have lol)Testing functionality / regressions
note that rain extinguishing fire code path is part of mcl_weather and was not touched here.
cpu b like "what fire"
35c375894c
to5183a307b1
@cora your testing instructions don't mention anywhere the blocktype that can catch on fire by fire spread but never burns up, like crafting tables
i'm not sure that was ever implemented. if it was i dont think it was in mcl_fire
theres a whole thing about how long nodes burn and how likely it is they will catch fire - flammable nodes have an "encouragement" value in minecraft apparently - but yeah that is not implemented.
we'd have to go through all node definitions and add such values i suppose
mmmh the crafting table thing does look like it worked before though. i'll have a look.
ITEMS/mcl_fire: fix fire spread to not freeze the gameto WIP: ITEMS/mcl_fire: fix fire spread to not freeze the game6cbe063667
to8ebc3b3089
*fix node ... lol
WIP: ITEMS/mcl_fire: fix fire spread to not freeze the gameto ITEMS/mcl_fire: fix fire spread to not freeze the gameturns out this is in the node definitions ( group flammable=-1 )
8ebc3b3089
toedb88c8be1
First: This is amazing! I can now have big fires without any lag (so far).
Second: I set fire to several two nodes high plants (e.g. rose bush) and beds.
When a two node high plant burns, it is possible for only one node to be deleted.
When a bed burns not the entire bed is deleted, making it possible to have half-beds.
should both be fixed now. The first one was sth i didn't properly understand (update falling node for the node above burnt out node) and the second was wrong all along: flammable value for beds was wrong
Rebase this branch on the current
master
branch please.cb05936f9e
toec0d7e3787
ec0d7e3787
to42a026a6ac
I rebased this on master just now.
Lol
after some testing, I found a few fire related bugs using the fire branch. I did not test whether they also exist on master.
in creative mode you can stand in the edge of the fire without getting hurt even though your screen fills up with fire. this should not happen
fire does not hurt fast enough when a player or mob is inside a fire source
fire should not extinguish due to water that is diagonally below it
sometimes fire spreads to air with no adjacent block around it. I will make screenshots later. it keeps spreading diagonally below itself despite when only touching other nodes diagonally. this is all not supposed to happen according to minecraft rules. basically I built this thing and it was catching on fire https://minecraft.fandom.com/wiki/Fire?file=Fire-safe-building.png
I am not suggesting that these all need to be fixed before this PR can be approved. I simply want to document it for future reference, and perhaps some of them are caused by this PR.
In creative mode, fire has always been burned players for only a very short time. Not sure if this is useful.
I think you mean this:
https://static.wikia.nocookie.net/minecraft_gamepedia/images/e/ea/Fire-safe-building.png/revision/latest?cb=20200819123501
Fire damage is not part of this i don't think.
This can prob easily be fixed in this pr - no idea about before - mmmh but i think i didnt touch that abm - i'll have a look
Mmmh well the fire spread is implemented p much exactly like the wiki explained or maybe i misunderstood something - but yeah ig it would be good if that building is actually fire safe.
yeah for the water thing its this abm it seems:
42a026a6ac/mods/ITEMS/mcl_fire/init.lua (L327)
I didn't change that but i suppose it would be easy to check ... also the fire node has an on_flood function so not sure why this abm is even needed. I'll try today or tomorrow.
@cora firstly, on_flood does not cover all the cases, because fire should also extinguish if there is water next to it, even if it cannot reach onto the block.
secondly, here is a screenshot of my safe house. the fire was in the node where I have now placed the orange glass. it had the same shape as the other fire, as if it was burning on top of a node. I don't have a screenshot of it because I keep instinctively putting it out. I shhould note that it seems to always be in the southwest direction of the fire. with this glass block in place, the fire was still able to spread, but I did not catch where it spread first.
update: the fire also spread northwest, it was probably just coincidence. unless there is a problem with the randomness in fire spread that it always prefers to spread in a certain direction
here is a screenshot of the fire
@cora fire should only be able to spread to an airblock that is touching a full face of the flammable block. in this case fire seems to also be spreading to airblocks that are only touching by 1 corner.
here where it says "including diagonals" they mean the fire can spread diagonally, not that it can be diagonal of a flammable block.
@cora great fix. next bug: in my testing, the crafting bench is not catching on fire, despite being near a fire in the dangerous area. afaik crafting benches should catch on fire just like any other flammable block, regardless of whether it burns up or not
mmmh i thought i fixed that. i'll have a look lol
@cora this reddit post and its comments might have some useful information about fire spread timings, if you are interested https://www.reddit.com/r/technicalminecraft/comments/jm8tf0/details_of_the_fire_spreading_algorithm/
Well i am dum lol
I read it a bit fast but from what I saw it has the exact no-info the wiki has: fire has an age property of 1-15 - great? but when does it increment?
The algorithm likely cant be copied 1:1 with abms anyways - if anything it can be close on average which is probably the reason why the previous implementation used node timers.
I do think thats probably out of scope though - some time I'll probably rewrite the whole fire thing to take encouragement and flammability into account - i made a prototype with it and it looked really good:
Yeah so looking at the helpful file some guy posted it's incremented p much randomly - i'd say the best we can do is have someone look at actual mc fires and tune the abm chance and interval so it looks similarly
looking at yt minecraft fires it needs to spread a bit faster i suppose.
Just for future generation i do like to point out getting all 6 adjacent nodes can relatively easily be done without that hideous static table as well:
I think that #258 should be merged before this.
Meanwhile, I will be testing this now.
88060c76c3
to06229b5963
ITEMS/mcl_fire: fix fire spread to not freeze the gameto ITEMS/mcl_fire: Fix fire spread to not freeze the gameI rebased this branch on master, and also fixed typos in commit messages and whitespace errors.
06229b5963
to6c2fb98160
It seems to me that the fire spread has a slight bias, as the first time the adjacents are checked in
has_flammable()
, they are not shuffled properly.Thus, the first fire check is always checking the adjacents in this order:
Additionally, the Fisher-Yates shuffle that is implemented in the function
shuffle_adjacents()
is usingmath.random()
without the random number generator being initialized before inmcl_fire
.Both of this together should make fire spread in a deterministic way, but only in case no one else initializes the random number generator.
Is this intented behaviour or an oversight?
To illustrate why a random number generator needs to be initialized, here is an example program:
This program shuffles a list of numbers using
shuffle_adjacens
from this PR.On my computer, it always outputs:
You can seed the random number generator with the current time using
math.randomseed(os.time())
. If you insert such a function call in the program in my post above at any point beforeshuffle_adjacents()
is called, the values get shuffled the same only during the same second (since then the seed is the same).I chatted with @cora about this and she thinks it is not a big deal that fire spread is deterministic. She also said said that she is not going to change this PR anymore.
I am thinking about adopting this PR to fix the RNG issue and whatever else we find.
If you think it through it really isn't a big deal in practise, while in theory being deterministic like this yeah, it's still going to be very hard to predict (and tbh impossible if another fire is happening outside the players rendering distance).
However this is obviously an oversight. The point is that I am quite tired of sporadic interest and then weeks of nothing so I said I will probably not fix an inconsequential detail like this (now).
I mean I can do it but please test the rest first and tell me everything you want changed and don't wait 2 weeks to find the next detail.
Ok!
Btw. right now it is even more deterministic and it never seemed to bother anyone. At least I shuffle the adjacents.
Btw. if you want it "totally" random adding a randomseed is not enough. The aircube thing is likely biased in one direction (prob -/- idk) even though i doubt you could spot the difference.
Just to spell it out here: Current fire is shit and you have created something much better.
I will look into if I can notice it. Generally I would like fire spread either to be totally deterministic to help with automated tests or I want it to be ”believably random”, i.e. people should not be able to figure out where the fire (even the first fire on some server) spreads.
Well you still prefer the "shit" version obviously if there is even a single thing about the "better" one you do not like lol. (e.g. bc it's "deterministic" even though the old version is even more so lol) Let me know when you're done then i'll fix the remaining issues.
Will do!
Reproducing
I had to check the mapgen flag “decorations” to get a forest to burn.
Minetest maxed out one CPU immediately, so I turned on opaque leaves.
That setting made rendering speed jump from 5 to 7fps to 25 to 27fps!
flint and steel noises
A small fire made rendering go down to 12fps and maxed out 2 of 2 CPUs.
The small fire also partially burned itself out, within a dense forest.
A large fire did not change much, except that the server would lag too.
At some point it would take a while until a right-clicked tree ignited.
Additionally, the server would not react to console commands anymore …
My PC got 4°C hotter from handling fires – less than any Matrix client.
After quitting Minetest, the server would hang around in the background.
So Minetest made my PC lag after I had closed the GUI. Extremely cursed!
Testing fix
Again, I activated the mapgen flag “decorations” to get a forest to burn.
I started a small fire at first, to compare differences.
The fps dropped only a bit – they went from 27 to 24.
(This was, of course, while not looking at a fire.)
No CPUs were maxed out in this step of testing the PR.
Additionally, I got very few ABM starvation warnings.
The small fire did not burn itself out, it grew larger!
In gameplay terms, the new fire seems much more useful:
I was able to create clearing in the woods by using it.
Testing functionality / regressions
flint and steel noises
Using a fire charge item works too.
This works.
Lava is mcl_core:lava_source by the way.
Is flowing lava not intended to spawn fires though?
I like this a lot.
verify that fires without flammable nodes adjacent eventually go out.
verify that water extinguishes fire (mcl_buckets:bucket_water)
Punching fire extinguishes it.
Throwing water bottles extinguishes the fire.
Dropping water or river water directly on fire extinguishes it.
Any fire node close to a water note is extinguished, even when it is diagonally.
Is this intended behaviour? It seems a bit weird to me that fire does not need to touch the water.
This does not work in all cases.
Directly setting netherrack on fire creates eternal fire. I assume this is what you meant?
Placing or pushing or pulling netherrack under normal fire does it not turn into eternal fire though.
I am not sure if that ever worked, so if you do not want to fix it in this PR, I will open an issue later.
Note that I also verified that eternal fire is created above magma and bedrock (in the End).
This works. I tested it with the forest from the beginning.
Tested in overworld and Nether.
This works.
I did not place the crafting table over lava, but it did catch fire from an adjacent normal fire.
Note. Rain extinguishing fire works fine with the code from this PR though.
Additional notes
I think your patch is somehow making Minetest repeatedly allocating a lot of memory, leading to lag – but I have no idea how.
After about 20 to 30 minutes, Minetest started allocating RAM – 100 MB every few seconds, when I burned stuff in singlenode.
After some time, this maxes out the server memory, at which point the server either frees the memory or (rarely) crashes.
While the server is allocating memory, it is lagging noticeably – even when not many fires are present.
While even small fires on the master branch max out CPUs, I was not able to reproduce the problem there.
Also, do you see any way to clear up the lag left by previous fires? Will it burn itself away?
I am now convinced that the “stone clouds” in the Void, End, and Nether are the result of lag.
This patch is really good and enables giant fires without noticeable lag.
However … I suspect it introduces or triggers a severe memory leak.
A problem with the memory leak is that it makes the game laggy.
So once the leak is fixed, I think this PR is finished.
Edit: Alternatively, convince me that the leak does not exist or should be handled elsewhere.
I made a screencast of
htop
displaying the memory usage of Minetest with the code from this PR.My test setup was a singlenode world in which I placed two of the structures from the schematic in the attached zip file using schemedit. I then set them on fire and waited.
Note the weird RAM behaviour. Also note that both CPUs are pegged at about 100%.
well no idea.
No idea how to do either of that. I can't even seem to reproduce this. But it does sound fairly serious so i guess you'll stay with the freezes.
ITEMS/mcl_fire: Fix fire spread to not freeze the gameto WIP: ITEMS/mcl_fire: Fix fire spread to not freeze the gameIf I copy the
map.sqlite
in the attached zip into a Mineclonia singlenode world with the seedfire
and use the code from this PR, on my computer Minetest will gobble up RAM immedately, like it is the most delicious of meals.Could you please try doing the same and look what happens?
To me, neither the original fire nor the patched fire seem remotely usable right now.
let's hope this fixes it
I think the memory leak is fixed. I have now twice run games in which a lot of stuff burned without node timers. Memory use was essentially constant over 40 minutes each time, regardless of how big the fire got. Good work!
3dfe8d1d2e
to15fb5064c1
WIP: ITEMS/mcl_fire: Fix fire spread to not freeze the gameto ITEMS/mcl_fire: Fix fire spread to not freeze the gameFire looks a bit nicer now that it dies out faster than before.
I still have encountered no CPU or RAM issues after having fires run for over 30 minutes several times. I will now retest the stuff from before and then probably approve it.
There are still two isssues with fire spread that have to be addressed:
Fire spread in protected areas. How to handle it? I will open an issue,
Fires dying out near unloaded nodes. In my opinion, they should not die.
You may wonder why I did not continue with the testing.
The answer is, unfortunately, in the attached image.
I used flint & steel, then Minetest filled my RAM.
(No … this does not make any sense at all to me.)
It seems that the RAM filling behavior only happens on x86 for me.
On x86_64, I got a segfault instead, after I used the flint & steel.
I was able to get the following traceback on a x86_64 machine:
The above two-node-arrangement bug happens only with code from this PR, but not on whatever runs on oysterity, i.e. this is definitely a bug that got introduced somewhere in this PR.
Seems that cora found and fixed it. My testing will continue now.
cd0f863e6b
toa685986fb4
a685986fb4
tof5ba6f5649
I edited two commit messages. Will test again.
I have tested this a lot. @cora has fixed all the bugs I found.
This is clearly better than what we had before.