Skip to content

Read per-item state on conveyors, and count belt items in the item search - #23

Merged
valentinps merged 2 commits into
mainfrom
fix/belt-item-state
Sep 4, 2026
Merged

Read per-item state on conveyors, and count belt items in the item search#23
valentinps merged 2 commits into
mainfrom
fix/belt-item-state

Conversation

@valentinps

Copy link
Copy Markdown
Owner

Two fixes to how items on conveyors are read, both reported against the same part of the parser.

1. Saves with stateful gear on a belt failed to load (#22)

object re-parse failed during index build: object at (3861, 109202): Value 1172451892 at offset 663613945 does not match the expected value 0.

Since save version 44 an item slot carries an itemState flag and, when set, an inline record: an empty level name, the state's type path, and its length-prefixed properties. The per-belt item format already read that; the conveyor chain format — where every belt item actually lives since 1.0 — asserted the flag was zero instead. The first geared-up item on a belt (a jetpack with fuel, a loaded weapon, a gas mask with a filter) turned the rest of the object into drift and took the whole save down with it.

Both formats now skip the record through one helper and keep its span, so the chained-belt delete write-back hands the bytes back verbatim — a jetpack that survives a cut line comes back with its fuel, not empty.

Chain and belt item slots become named structs rather than tuples, which is where the chain slot's trailing float also gets its real name: it's a distance along the line, not an instance id (consecutive gallery items sat exactly 120 cm apart).

2. The item search never counted anything in transit

An item search summed every inventory but nothing riding the belts, so a running factory under-reported by its whole belt network — half the iron ingots on one 54 MB save (166k of 331k), 559k items on another. Items now count against the belt they physically ride, not the chain actor (which has no footprint), so every location listed is a real placed building.

Verification

  • Every map payload across the 22-save corpus is byte-identical to before; the save-index differs only by the belt items the search now counts — nothing lost, no total decreased, no location dropped.
  • New tests/belt_item_state.rs gates the parse, the state spans' byte layout, searchability, and a delete round-trip; editor::apply pins the write-back record layout.
  • The repro save loads in the app with its belt items listed in the item search.

Test corpus bumped to test-saves-v2 (adds the 419 KB repro save; the other three assets are unchanged).

Fixes #22

valentinps and others added 2 commits August 2, 2026 20:15
An item search summed every inventory in the save but nothing in transit,
so a running factory under-reported by everything on its belt network --
half the iron ingots on one 54MB test save (166k of 331k), 559k items on
another.

Since 1.0 a belt line's items live in one ring buffer on the shared
FGConveyorChainActor, each member belt owning a contiguous window of it.
item_location_index now walks those windows and counts each item against
the belt it physically rides -- not the chain actor, which has no
footprint -- so every location the search lists stays a real placed
building at a real position, and belts group next to machines and
containers in the modal like any other holder. Pre-1.0 saves keep items
on the belt actor itself; those count too.

The ring arithmetic moves into queries::conveyor_chain_segment_window,
shared with the belt tooltip's per-segment item list rather than copied.

Tests: the index agrees belt-by-belt with aggregateSelectionInventory
(the independent path behind the tooltip and selection panel), and the
per-belt windows tile each chain's ring exactly -- no slot double-counted
into two belts, none dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A save with anything stateful parked on a belt -- a jetpack with fuel, a
loaded weapon, a gas mask with a filter -- failed to load outright:

  object re-parse failed during index build: object at (3861, 109202):
  Value 1172451892 at offset 663613945 does not match the expected 0.

Since save version 44 an item's slot carries an `itemState` flag and, when
set, an inline record: an empty level name, the state's type path, and its
length-prefixed properties. The per-belt item format already read that; the
conveyor CHAIN format -- which is where every belt item actually lives since
1.0 -- asserted the flag was zero instead, so the first geared-up item on a
belt turned the rest of the object into drift and took the whole save with
it. Reported in #22, reproduced on a save of belts hung with jetpacks, gas
masks and hazmat suits (now map/uploads/belt_item_state.sav).

Both formats now skip the record through one helper and keep its span, so
the chained-belt delete write-back hands the bytes back verbatim: a jetpack
that survives a cut line comes back with its fuel, not empty. Chain and belt
item slots become named structs rather than tuples, which is also where the
chain slot's trailing float gets its real name -- it is a distance along the
line, not an instance id (consecutive gallery items sat exactly 120cm apart).

Verified: every map payload in the corpus is byte-identical to before, the
save-index differs only by the belt items the search now counts (nothing
lost, no total decreased), and the repro save loads in the app with its belt
items listed in the item search.

Fixes #22

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@valentinps
valentinps merged commit b70048b into main Sep 4, 2026
2 checks passed
@valentinps
valentinps deleted the fix/belt-item-state branch September 4, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Item with state on belt doesn't work - from u/Schattenfluegel

1 participant