Repository navigation
perf: rewrite scanned food only when it would look different - #124
Conversation
The inventory scan rebuilt and rewrote every unheld food stack each time it scanned its owner (about every 4 s on Main), only to store the new clock and aged numbers. Food ages by the wall clock from its stored clock, values and remainder, so leaving those alone ages it exactly the same and nothing a player sees changes. TagManager now hands TLibs a scan() answer: - It reads the item's meta once and parses the food once. - FoodScan ages it to now and writes the slot only for a new tag step, lost warmth or broken lore (the old rules, also used for held food), a clock that is missing, ahead or not on a whole second (set once, as the first rewrite used to), or a rebuild that would differ in anything but the clock data (lore or model after a reload or update). - It tells TLibs when the unchanged food can next show a new step or lose its warmth (a second early), so the slot is skipped until then. Held food is checked every scan, as it was; non-food waits for the item to change. - Food with a sauce keeps the old rewrite on every scan: a sauce stores no clock or remainder of its own, so it only ages when the food is rewritten and changing that would change how fast sauces age. - LegacyFishScan only checks matching fish every scan, other slots wait for their item to change. - /cooking reload asks TLibs to rescan every slot so new config shows at once. Needs TLibs 2.7.0 (ItemScanHandler.scan and ItemScanService.rescanAll); the pin is bumped from 2.6.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Findings
|
| Layer / File(s) | Summary |
|---|---|
Food scan contract and ageing src/main/java/net/tfminecraft/cooking/item/FoodItem.java, src/main/java/net/tfminecraft/cooking/utils/FoodScan.java, src/test/java/net/tfminecraft/cooking/utils/FoodScanTest.java |
FoodItem.fromItem accepts caller-provided metadata. FoodScan updates food state and schedules checks around the next visible ageing change. Tests cover rewrite behaviour, clocks, lore, and scheduling. |
TagManager scan and inventory updates src/main/java/net/tfminecraft/cooking/manager/TagManager.java, src/test/java/net/tfminecraft/cooking/manager/* |
TagManager delegates scans to FoodScan, writes non-air results to valid inventory slots, and returns the recheck time. New tests cover scan inputs and slot updates; three prior update tests are removed. |
Reload and legacy fish scan handling src/main/java/net/tfminecraft/cooking/Cooking.java, src/main/java/net/tfminecraft/cooking/fishing/LegacyFishScan.java, src/test/java/net/tfminecraft/cooking/CookingLifecycleTest.java, src/test/java/net/tfminecraft/cooking/fishing/LegacyFishScanSkipTest.java |
Cooking.reloadAll() rescans items when ItemScanService is available. LegacyFishScan returns WHEN_CHANGED for non-matching stacks and updates matching stacks on every scan. Tests verify both changes. |
TLibs version update
| Layer / File(s) | Summary |
|---|---|
Update configured TLibs version pom.xml |
The configured TLibs version changes from 2.6.0 to 2.7.0. |
Estimated code review effort: 3 (Moderate) | ~25 minutes
Change: Refactor
Sequence Diagram(s)
sequenceDiagram
participant TagManager
participant FoodScan
participant Inventory
TagManager->>FoodScan: Pass stack, metadata, food item, and held status
FoodScan-->>TagManager: Return replacement item and recheck time
TagManager->>Inventory: Write non-air result to a valid slot
Suggested reviewers: ryanbarlow97
Merge Risk: 
Moderate · up to 96efb
-
This change depends on a TLibs 2.7.0 release that has not been published. Builds of this revision fail until that release exists. After release, servers must also update TLibs together with Cooking, or Cooking's reload and inventory scanning can break. Publish TLibs 2.7.0 and coordinate the rollout before merging.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
|
@coderabbitai review |
Action performed
|
…it would look different (#126) * perf: rewrite food on meat hooks, baking trays and troughs only when it would look different The meat hook, baking tray and trough timers rebuilt and rewrote every food in their slots each second (model, lore, carve state, display item, hook display transform, furniture save) only to store the new clock and aged numbers. On Main at 15+ players that was ~11 s of main thread per hour (meat hooks alone 5.5 s/h). Food ages by the wall clock from its stored clock, values and remainder, so the slots now use the inventory scan's rule (FoodScan, #124): SlotAging writes a slot only for a new tag step, lost warmth, broken lore, a clock to set, or a rebuild that would differ (with the furniture's model), and otherwise leaves it resting until a second before it can next look different. Any change to the item ends the rest, as do /cooking reload and /iareload (ItemRef.clearCache). Food with a sauce keeps the old every-second rewrite. Carving reads the roast's numbers into the cuts and starts the roast left on the hook on a new clock, so it now ages the roast to now first; before, those numbers were at most a second old. Plates keep the old rewrite: adding a sauce copies the plated food onto a new clock and sauces only age when the food is rewritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Age a glazed roast to now explicitly and let /iareload end rests from any thread Review: glazing relied on addOrModifyTrack aging the roast first; say it outright like carving does. forgetAll may run from the ItemsAdder load event, so it now moves a generation on instead of clearing the server thread's map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep glazing as it was and save oven bake time with the autosave Review: aging the roast before the glaze checks changed fire-pit glazing (a roast gone off by the clock was refused); addOrModifyTrack already ages it before the glaze track goes on, as before. The tray timer used to mark baking trays dirty every second, which also saved the oven's per-slot bake time with the minute autosave; the oven now marks the tray itself while that time runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: bread taken from a resting tray slot is aged to now before it is made Hot Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: XxFran10xX <318299142+XxFran10xX@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…it would look different (#126) * perf: rewrite food on meat hooks, baking trays and troughs only when it would look different The meat hook, baking tray and trough timers rebuilt and rewrote every food in their slots each second (model, lore, carve state, display item, hook display transform, furniture save) only to store the new clock and aged numbers. On Main at 15+ players that was ~11 s of main thread per hour (meat hooks alone 5.5 s/h). Food ages by the wall clock from its stored clock, values and remainder, so the slots now use the inventory scan's rule (FoodScan, #124): SlotAging writes a slot only for a new tag step, lost warmth, broken lore, a clock to set, or a rebuild that would differ (with the furniture's model), and otherwise leaves it resting until a second before it can next look different. Any change to the item ends the rest, as do /cooking reload and /iareload (ItemRef.clearCache). Food with a sauce keeps the old every-second rewrite. Carving reads the roast's numbers into the cuts and starts the roast left on the hook on a new clock, so it now ages the roast to now first; before, those numbers were at most a second old. Plates keep the old rewrite: adding a sauce copies the plated food onto a new clock and sauces only age when the food is rewritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Age a glazed roast to now explicitly and let /iareload end rests from any thread Review: glazing relied on addOrModifyTrack aging the roast first; say it outright like carving does. forgetAll may run from the ItemsAdder load event, so it now moves a generation on instead of clearing the server thread's map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep glazing as it was and save oven bake time with the autosave Review: aging the roast before the glaze checks changed fire-pit glazing (a roast gone off by the clock was refused); addOrModifyTrack already ages it before the glaze track goes on, as before. The tray timer used to mark baking trays dirty every second, which also saved the oven's per-slot bake time with the minute autosave; the oven now marks the tray itself while that time runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: bread taken from a resting tray slot is aged to now before it is made Hot Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: XxFran10xX <318299142+XxFran10xX@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 46458b5)
Why
Every 2 ticks the TLibs item scan hands each food in a player's inventory to TagManager, which parsed it, aged it to now and wrote it back into the slot. The stored clock moves every second, so every food was rebuilt and re-set once a second even when nothing a player sees had changed. On Main's 11-02 spark profiles that was 6.6 s/h in TagManager plus 2.1 s/h matching and 0.8 s/h in the legacy fish scan, inside TLibs' ~14 s/h
ItemScanService.pulse.Change
Uses the new TLibs
ItemScanHandler.scanresult (TF-Minecraft/TLibs#50, release 2.7.0):utils/FoodScan. A food ages by the wall clock from its stored clock, value and remainder, so writing the aged numbers back changes nothing a player sees. The scan now only rewrites a food when:TagManagerandLegacyFishScanimplementscan. An unknown food id or a non-food item is skipped until it changes.Cooking.reloadAllcallsItemScanService.get().rescanAll(), so a config reload re-checks every food.FoodItem.fromItem(stack, meta)reuses the meta the scan already read.sameApartFromAging) already ignores the clock, tags and remainder. Identical foods that were never rewritten now keep identical data, so they stack more easily, not less.pom.xmlmoves totlibs.version2.7.0.Depends on TF-Minecraft/TLibs#50: CI can't resolve TLibs 2.7.0 until it is released.
Testing
New
FoodScanTest,TagManagerScanTest,LegacyFishScanSkipTestand a lifecycle case for the reload rescan. Locally 1514 tests run; the 4 failures are the same as onmainon this Windows PC.Dev (TFMCDev01, 11-02, with the TLibs branch), with a bot holding another slot:
(Dev's warmth and freshness age at 1 unit per second.) After
cooking reloadboth items were still correct. No Cooking warnings or errors in the log.Release:
mainalso holds #100–#123, which aren't released, so this goes out as 0.7.2 from v0.7.1 plus this change only (cherry-picked onto a release branch; it applies cleanly). That tree passes the same tests (the 2 failures are this PC's decimal-comma locale, as on v0.7.1) and was Dev-tested with the same results as above.🤖 Generated with Claude Code