CleverRaven / Cataclysm-DDA

Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.
http://cataclysmdda.org
Other
10.11k stars 4.11k forks source link

Large "stacks" of food never freeze in freezer #60865

Open AJimmyU opened 1 year ago

AJimmyU commented 1 year ago

Describe the bug

Having 1000 chunks meat stacked in a freezer will cause these chunks to never move beyond cold status.

Steps to reproduce

  1. put 1000 chunks of meat into a turned on freezer 1 Z level underground
  2. observe chunks of meat becoming cold but never frozen

Expected behavior

Freezer making meat frozen.

Screenshots

No response

Versions and configuration

Additional context

Potentially another bug at play, as accidentally moving contents of my freezer onto a nearby tile caused many "cold" items that were fine for weeks to immediately become rotten as if all the time they were in the freezer passed at the same time.

borsek commented 1 year ago

Can confirm stuff going immediately rotten after moving from a freezer. Also happened with (sealed) salted meat slices - first eaten slice would be ok, the second in the pack would insta rot.

PatrikLundell commented 1 year ago

/confirmed

It's not connected to stack size, but rather on some "random" factor. I've got frozen, unfrozen, and hot(!) food in a fridge weeks after it being placed there.

The bug where things rot immediately after being removed from a fridge is (probably) a separate one, as it (can?) happens to food regardless of whether it's cold or not. The work around for that is to craft your meal (or eat it cold) directly from the fridge (i.e. not remove the food first). Based on having food rot while crafting (when relighting the fire that went out when cooking meat that was going old in the open), I suspect the crafting has to be uninterrupted.

Terrorforge commented 1 year ago

There is definitely a correlation between stack size and freeze time. I created stacks of 10, 100 and 1000 chunks of meat to test. image

After 24h. The stack of 10 is frozen, the others merely "cold". image

About 48h, the stack of 100 is frozen. image

After 4 days, the stack of 1000 is frozen. image

So the huge stack did freeze eventually. How long did you wait to conclude it just "never" froze? In that that time, did you leave the area where your freezer was for significant periods of time? It's just a hunch, but these problems could be related to the temperature and/or rotting status not being handled properly when the food leaves the reality bubble before it's properly frozen, which would be much more likely with huge stacks.

PatrikLundell commented 1 year ago

It looks like a very promising investigation lead, @Terrorforge!

A long time (weeks, or possibly months, could even be a season, and I don't think I've got any stack with a count of 1000). Things were thrown into the freezer as soon as they'd been crafted (or, in the case of companion crafting, the crafter had been recalled and delivered the product). I generally leave the base camp in the morning after assigning the day's activities and eating breakfast, so it's rare to be in the camp for 24 hours at a time (has happened very occasionally when crafting something).

Thus, if leaving the reality bubble screws the timers up it would explain the randomness, and if cooling down time is connected to the stack size it would explain why it seems to be so inconsistent when coupled with reality bubble exits.

Checking the contents of the freezer: Edit: Added debug data last temp, temp, and spec ener after the counts

borsek commented 1 year ago

So, if I understand correctly:

Could this simply be fixed by freezing a stack of items as fast as a single item? In other words, the code would take item mass instead of stack mass when the freezing operation is calculated?

PatrikLundell commented 1 year ago

It is a real world thing that a large volume of things thrown into a freezer at once causes the temperature inside to rise, and thus take longer to freeze things (and potentially thawing others partially), while larger items take longer to freeze than a set of smaller ones. However, that can be a bit complicated to implement properly, so in the absence of such logic the work around suggested by @borsek could be implemented (assuming our assumptions of how the code works is correct).

However, the big issue is really the reality bubble interaction, which shouldn't leave items in limbo, but rather freezing them down properly.

borsek commented 1 year ago

I definitely agree that my suggestion is a simplification, but I'm sure accurate temperature interaction would kill CPUs - dwarf fortress has a fairly complex system, but it kills performance absolutely and completely.

On that note, stuff like ethanol and antiseptic shouldn't freeze at -10 (assuming antiseptic is ethanol and not iodine-based, even then it should withstand several degrees C negative), so there's realism missing there too.

Do we even have freezing points set or planned for stuff?

Hirmuolio commented 1 year ago

When items are out of reality bubble they do not get processed. When you return to area after long while the temperatures get processed retroactively (IIRC max 2 days into past in 1 hour chunks. Time beyond that is mostly ignored).
Bigger items heat/cool slower. This is very much intentional.

The temperature calculations are pretty much as realistic as they can be with the info avalable for use. The temperature is just calculated relatively slowly (once every 10 minutes per item) so it isn't big performance impact. (fun fact: The process of finding items for temperature processing is much bigger performance impact than temperature calculations themself).

Items get their freezing points from their material. Items can also override their own freezing point in json (see alcohol drinks).

Problems with freezers/fridges have existed for long time but nobody has been able to find reliable reproduction steps.

If you enable debug mode you can see exact temperature of the item (in kelvins).

It would be useful to know what it is on the items that experience the bug.
If the temperatures are "sensible but wrong" (for example outdoor, underground, freezer, fridge, oven temperatures) that would point to some logic error in code.
Or if the temperatures are complete nonsense (extremely cold/hot) that would point to some over/underflow/math error in code.

PatrikLundell commented 1 year ago

I don't know how to display item temperatures.

However, my impression is that temperatures just have ceased to be processed, rather than them being set incorrectly.

Hirmuolio commented 1 year ago

Debug mode key is not bound do anything. Press ?, search for "toggle debug mode" and bind some useless key to it.

Press that bound key. Turn debug mode on (there are other options that can be ignored). Look at the item.

For the temperature bug the interesting values are:

PatrikLundell commented 1 year ago

Thanks for the instructions, @Hirmuolio. I've updated my previous post listing contents with last temp, temp, and spec ener for the first few and last few items. I can do the rest if required, but it's tedious and I'm lazy.

Edit: Added fresh, not cold scrap of meat to the mentioned post for a value that should be a bit above freezing, and it is.

Hirmuolio commented 1 year ago

I somehow managed to trigger some bug maybe. And the findings make things even more confusing.

The steps I roughly took to trigger the bug. Not sure which ones are necessary (maybe the save+load was all that was needed but I'm not going to test that right now):

  1. Setup a base with freezer, batteries and panels.
  2. Turn freezer on and put food in it.
  3. Debug teleport away. Move time forwards by a season. Teleport back.
  4. Everything works fine.
  5. Teleport away, walk around a bit and get autosaved.
  6. Close and reopen. Load the save.
  7. Teleport to the base again. The food in freezer is broken.

None of the foods in the freezer were getting processed. For some reason the active item cache was completely empty. Creating new items would add the new items into the cache. And taking food out would make them process. But the food that were in the freezer did not get processed at all.

This bug also persisted through save and load cycle.

But now the part where things get weird. This bug happens only on certain versions of the game!

If I load the save on build I build with Visual Studio 2022 the bug happens. If I load the save on cdda-windows-tiles-x64-msvc-2022-09-09-1750 the bug happens. But if I load the save on cdda-windows-tiles-x64-2022-09-09-1750 the bug does not happen and items in freezer process normally.

Here is the save: temp test.zip

  1. Load the save, enable debug mode and look at the items in the freezer. Check that most of them have their last temp value at around 13000000.
  2. Wait 30 minutes.
  3. Look at the item again. If the last temp value has not changed then the bug has occured and items do not get processed. If the last temp value changes then the bug did not occur.
akrieger commented 1 year ago

I got as far as verifying that the freezer contents are being loaded into active_items here https://github.com/CleverRaven/Cataclysm-DDA/blob/master/src/savegame_json.cpp#L3445-L3450 because I initially suspected a json load order issue. Some parts of the code depend on JsonObject members being read in a certain order, given you said the cross build seems to work but MSVC didn't made me suspect that. Unfortunately, I'm lost after this point.

Hirmuolio commented 1 year ago

I did some more debugging. It seems like the items are correctly loaded into the active item cache. But for some reason fetching the items from the cache causes the cache to be emptied.

Here test code: https://github.com/CleverRaven/Cataclysm-DDA/compare/master...Hirmuolio:Cataclysm-DDA:fixtemp

(Early return to skip some irrelevant stuff so it doesn't trigger breakpoints.) The first cur_veh.active_items.empty() returns false. The items are in the active item cache and everything works as it should. Then cur_veh.active_items.get_for_processing() returns empty vector. The secondcur_veh.active_items.empty() returns true. There are no longer anything in the active item cache.

ANickelN commented 1 year ago

Not sure if helpful, but just wanted to chime in and say that this has been a big issue in my games, although the solution doesn't seem to be too evident from reading previous comments.

robob27 commented 1 year ago

Lots of similar investigation happening in #58824. I think these issues both have the same root cause.

@akrieger I confirmed the same thing as you, and then confirmed that the refresh() call below that wipes the active_items.

I pushed up something that seems to fix it in #60952 just not sure if it's the right fix.

Edit: Okay, parts of this issue have the same root cause. Like the last_temp values being all over the place is related to the stuff I mentioned above. There does seem to be a separate issue thing (maybe not issue? as someone said larger volumes of stuff added to a freezer all at once would take longer to freeze) with very large stacks of items though.

Hirmuolio commented 1 year ago

About the large stacks.

In the temperature calculations the heat loss/gain is based on surface area which in turn is based on volume. Temperature change per energy change is based on mass.

When you stack items their mass is simply added together. So two 0.3 kg meat chunks has mass of 0.6 kg.

But surface area behaves differently. The relation is not linear. It involves raising the volume to power of 2/3 (simply assumes all items to be cube shaped). One meat chunk has volume of 250 ml and has surface term of 39.6 (technically this should be multiplied by 6 but we can ignore a constant like that). Two meat chunks have total volume of 500 ml and surface term of 62.99.

So two chunks of meat has 2x the mass but only 1.5x surface area. So it cools down much slower.

For N number of items in stack the mass is N times but the surface area is N^(2/3) times. As N gets bigger the difference alsop becomes bigger.

1000 chunks of meat has 1000x mass but only 100x surface area. So it releases energy 100x as fast as single chunk of meat. But it requires 1000x energy change to have same temperature change as single chunk of meat.

Also the freezer is not very cold. It is only at -5 celcius. It was written for vehicle minifreezer. Maybe proper appliance freezers should me made colder?

Most foods are pretty similar to water in their stats. So you can ask yourself "how long does it take for 300 L of water (1000x chunks of meat) to freeze at -5 celcius temperature". It takes a long time.

chrispikula commented 1 year ago

So, huh, why is it so warm in freezers? IRL, they are generally between -18 and -23 c (0 -> -10 F), so, yeah, it's no wonder things go bad in them.

Terrorforge commented 1 year ago

Afaik, this behavior is more or less accurate to reality. Heat exchange is largely a function of surface area (and thermal conductance), and the square-cube law means the volume (and thus mass) increases faster than surface area as an object gets larger.

But it gets weird because it's treating all the meat chunks in a stack as one item, and items are handled individually. So if for example you have two stacks of 100 and two freezers, you can freeze them faster by splitting the stacks so each freezer has two stacks of 50 instead of one stack of 100.

Which gets weirder still when you consider that a chunk of meat is an arbitrary unit. It's about a porkchop's worth, but the game doesn't really distinguish between 8 porkchops and one pork roast.

PatrikLundell commented 1 year ago

The problem comes from a stack considered to be a single item from the game's perspective when it comes to cooling, and it stacks items without you being able to stop it (well, you can game it by placing e.g. stacks of 10 in at intervals to get them to get different temperature and rot timers, and thus not stack). In real life you wouldn't place your chunks as a compact mass, but rather spread it out as much as possible to expose as much of the surface area to the cold as possible.

However splitting a 100 stack in two and putting each in a different freezer is going to cause freezing to be faster in real life because each freezer has a limited freezing capacity.

I also suspect a health inspector in any somewhat civilized country would reject the game freezer temperatures as being dangerously high.

chrispikula commented 1 year ago

So, could we, as a workaround, change freezing s.t. it looks at item stack counts when trying to figure out freezing time?
Or to look at the volume/mass of the default, singular item, rather than the quantity? (That way skips division math.)

(Only for non-fluids, of course. Probably just default to keeping items with charges the same, overall.)

Hirmuolio commented 1 year ago

That would be possible. It would make freezing happen faster but it would also make melting happen faster. So it would cancel out usually.

It doesn't usually matter if item freezes fast or slow. As soon as it is in the freezer the rotting stops (rot is mostly based on environment temperature).

borsek commented 1 year ago

Glad you all arrived at the simple resolution I presented 8 days ago.