feat/block-state-sidetable #6
No reviewers
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
scope/assets
scope/client
scope/networking
scope/renderer
scope/scripting
scope/server
scope/shared
scope/workspace
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Synvael/synvael!6
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/block-state-sidetable"
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?
What does this PR do?
I added
BlockStateTable, a sparse per-voxel side-band state container incrates/shared/src/world/block_state.rs. It maps a local voxel index to an opaque byte payload capped atMAX_BLOCK_STATE_PAYLOAD_LEN(256 bytes), backed by aBTreeMapso iteration and serialization stay deterministic.I wired the table into
ChunkDataas a newblock_statefield, exposed throughblock_state()andblock_state_mut(). The field is#[serde(skip)]because theSYNCrecord frames it as its own section rather than folding it into the edit-set payload, so a chunk carrying no state costs nothing extra.I extended the
SYNCrecord format (crates/shared/src/save/record.rs) to carry that second section: two more length fields in the header, an optional compressed block-state payload after the chunk payload, and a bump ofCHUNK_FORMAT_VERSIONto 2.encode/decodeshare acompress_section/decompress_sectionpair now instead of duplicating the zstd/postcard logic inline.decoderejects any record whose version doesn't match the current one rather than guessing at an older layout, since there's no migrator yet.I moved
BlockStateErrorout into a dedicatedcrates/shared/src/world/error.rsmodule and wired it intoSaveErrorvia#[from], so a decode-time size violation on the side table surfaces asSaveError::BlockState.Why is this change necessary?
Gameplay features like fluid levels, redstone-equivalent wiring, or growth stages need per-voxel state that doesn't fit the existing single-block-id edit model, without paying the cost of widening every chunk's edit set for voxels that never use it. This lays the storage and persistence groundwork so the Lua API can build state-bearing block types on top of it later.
Scope of Changes
shared
Testing
Automated:
cargo check -p sharedcargo test -p shared(241 passed, 0 failed)cargo clippy --all-targets --all-features -- -D warningscargo fmt --all -- --checkNew tests cover
BlockStateTableinsert/remove/iteration/validation, the oversized-payload rejection path both oninsertand on data deserialized straight from bytes, and record round-tripping with a populated and an empty side table, an unsupported version rejection, and length-mismatch handling on the new section.No manual or in-game verification was done; this is storage/format-only and isn't reachable from gameplay yet.
Additional Context
CHUNK_FORMAT_VERSIONmoved from 1 to 2. There's no migrator for existing saves, consistent with the project's current policy of bumping format versions without one until a world exists off the dev machine. AnySYNCrecord written under version 1 will now fail to decode withSaveError::UnsupportedVersion.ChunkData::is_unmodifieddoes not considerblock_state: a chunk whose voxel edits match the baseline but whose state table is populated is a dirtiness case no caller produces yet, so I left it unhandled rather than guessing at the right behavior.Related Issues
None.
Checklist
dev(or a feature branch offdev) and my PR targetsdev.///doc comments for Rust) where necessary.