Skip to content

FoodTracker

Choose a tag to compare

@Boarlock Boarlock released this 28 Aug 00:57
· 29 commits to master since this release

Big update for base mod, even though the original version you could play with it the constant errors from the base game about destroyed food had to be fixed. The issue is completely resolved now and this update has been tested thoroughly.

- Fixed the 0.002–0.005 nutrition / false-interruption issue

This was the biggest bug from v1.0, essentially due to timing inconsistencies with the game's tick system, the mod was going out-of-sync with the vanilla game. Specifically with our wrapped ChewIngestible toil and vanilla's FinalizeIngest(). The interruption handler could run even though vanilla was only a few ticks away from completing the ingestion. So I added a completion threshold, if consumption is over 99.5% then FoodTracker doesn't touch it, it doesn't invoke the interruption handler, it doesn't manipulate the food Thing, it lets vanilla own the Thing lifecycle. This specifically prevents FoodTracker from interfering with vanilla when the ingestion is effectively finished. This does mean interruption can happen past this point that FoodTracker misses, but 99.5% on a normal meal (0.9 nutrition) is about 0.002 nutrition, which in game ticks translate to 1-3 most likely. It'd be very difficult to consistently interrupt you pawns eating jobs 2 ticks from completion.

- Redesigned IngestionState

Since vanilla destroys the object in a pawns hands when a pawn is drafted and then un-drafted (especially while standing on a food stack), postfixing the ChewIngestible() method would not capture certain variables that FoodTracker needed. Specifically the Food Thing object, this also meant it couldn't derive the foodDef with food.def (because it's destroyed), couldn't query .stackCount, couldn't access our nutrition component, etc.. So now it captures anything it needs during the Prefix portion (when it normally calculates eating duration).
Food Thing reference, ThingDef, nutrition, etc.. Anything derived from the food Thing that may become unavailable later should be captured before vanilla can invalidate it.

- Moved ValidateFoodEatingAttempt() into the Prefix

I specifically changed validation to happen as early as possible. The Prefix now determines whether the eating attempt is something FoodTracker should care about before doing unnecessary work. This also could help performance.

- Made the helper methods defensive

Essentially all the Helper methods that receive a Thing food reference checks to see if it has been destroyed. All the logging and references have been safely nullified, so it shouldn't throw an exception even if something totally unexpected occurs.

- Reworked nutrition application

I discovered that directly doing pawn.needs.food.CurLevel += nutrition; wasn't the best way to apply the correction. The new nutrition application accounts for how much hunger the pawn actually has. So FoodTracker no longer blindly pushes nutrition into the pawn beyond its maximum and keeps the nutrition record synchronized with the actual amount applied.

- Cleaned up naming and code organization

I went through the code and renamed methods to make their responsibilities more explicit. The overall intent was to make it much easier to understand. What validates an eating attempt, what tracks an ingestion, what recovers destroyed food, etc.. I was trying to tighten the separation of responsibilities.

Things to work on still:

1. Removing redundant XML component dependency where possible

This is part of a broader redesign thinking around compatibility. I want to eliminate the second part because it created unnecessary compatibility concerns with modded meals, whether the other mod already has a node, load order, XPath targeting. The new direction was that full meals shouldn't need to carry thetracking component at all. FoodTracker can track the full meal through code and only the partial meals needs the actual partial nutrition component.

Secondary Bug Fixes:
These are small fixes that cropped up during development and I was able to iron out relatively easily.

Fixing the __state, local state assignment mistake that caused the NullReferenceException.
Correcting stack handling in the replacement path after discovering the captured Thing represented the whole stack.
Refining the destroyed-food recovery behavior.
Cleaning up logging so it uses stable food definitions rather than misleading historical Thing.Label values such as MealSurvivalPack x9.

Tested
Testing zero nutrition/zero items eaten edge cases.
Testing lone meals vs. stacked meals.
Testing destroyed Thing vs. surviving Thing paths.
Testing batch foods extensively.

Full Changelog: v1.0...v1.1.0