#110 Refresh signs on chunk load#142
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR closes the stale-marker cleanup gap by reconciling tracked signs when their chunk loads: if a cached sign key no longer corresponds to a live SignBlockEntity in that chunk (e.g., chunk regen / external edits), the marker is removed using existing SignManager.remove(...) logic.
Changes:
- Add a chunk-granularity secondary index (
SignChunkKey/SignChunkIndex) to map chunk → trackedSignEntryKeys for O(1) lookup. - Update
SignManagerto maintain the chunk index alongside the existing flatsignCache, and exposegetKeysInChunk(...). - Register
ServerChunkEvents.CHUNK_LOADto detect and remove stale markers on chunk load; add unit tests for the new index/key utilities.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignChunkKey.java | Defines chunk key computation (16-block chunk math) for indexing signs by chunk. |
| src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignChunkIndex.java | Implements the chunk→keys index used to avoid scanning the full sign cache on chunk load. |
| src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignManager.java | Maintains the new chunk index during add/remove/reload and exposes chunk-key querying. |
| src/main/java/com/tpwalke2/bluemapsignmarkers/BlueMapSignMarkersMod.java | Hooks chunk-load event and removes tracked entries that no longer have a sign block entity. |
| src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignChunkKeyTest.java | Unit tests for chunk-key math (origin, boundaries, negative coords, dimension isolation). |
| src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignChunkIndexTest.java | Unit tests for index add/remove/query/clear behavior across chunks and dimensions. |
| plans/sign-storage-refactor-options.md | Documents why in-memory sign storage stays flat and evaluates alternative layouts. |
| plans/chunk-load-sign-reconciliation-plan.md | Design plan documenting the chunk-load reconciliation approach and performance constraints. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Detect and remove sign markers whose sign block no longer exists in the world when its chunk reloads — closing the last gap in stale-marker cleanup (issue #110).
Why
The existing removal mixin only fires for an in-game block change on a loaded chunk. A sign that vanishes any other way (external region-file deletion/regen, backup restore, manual NBT edit) leaves its cache entry and BlueMap marker orphaned forever. #109's region-sharded storage was built specifically so this follow-up would have something cheap to query against.
Changes
SignChunkKey/SignChunkIndex(new,core/signs, plain Java) — chunk-granularity (16-block) lookup from chunk → tracked sign keys, so reconciliation never scans the full sign cache. Kept separate from the persistence-layerSignRegionKey(512-block region math is a file-layout concern, not a runtime lookup one).SignManager— maintainschunkIndexalongside the existing flat cache (add/remove/reload hooks); exposesgetKeysInChunk(...).BlueMapSignMarkersMod— registersServerChunkEvents.CHUNK_LOAD; on load, checks each tracked sign in that chunk still has a liveSignBlockEntity, and removes (via the existingSignManager.remove) any that don't, logged at INFO since it signals an unattended/external change. Deliberately does not skip newly-generated chunks — that's exactly the "region file deleted externally" case this targets.SignManager's in-memory storage (kept flat, per that doc's recommendation).Testing
./gradlew test— newSignChunkKeyTest(12 cases) andSignChunkIndexTestcover chunk-boundary math and index add/remove/isolation/clear behavior../gradlew build— full build passes../gradlew runServer, not automatable — touches live Minecraft/Fabric types):a. Place a sign, restart the server, confirm the marker is unchanged and no spurious removal is logged.
b. Place a sign, stop the server, delete that sign's chunk region file (forces a regen) or remove the block via NBT editor, restart, walk into the chunk — confirm the INFO log line appears and the stale marker disappears from BlueMap.
c. Repeat with signs in two dimensions at the same x/z to confirm dimension isolation.