#198 Allow players to set color via adding dye on signs - #205
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
V5 migration can discard valid entries when one entry is null, and disabled groups still perform unnecessary dye recomputation.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds opt-in, player-controlled colors for multi-point markers using sign dyes.
Changes:
- Adds
allowPlayerColorsand dye-based color resolution. - Persists front/back dye state through the V6 format.
- Adds live dye detection, tests, and documentation.
File summaries
| File | Description |
|---|---|
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignTransitionResolverTest.java |
Tests dye-triggered transitions. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignManagerTest.java |
Updates dye-aware fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignLinesParserTest.java |
Updates marker-group fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignEntryTest.java |
Tests dye equality behavior. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignEntryHelperTest.java |
Tests side-specific dye selection. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/ShapeGroupResolverTest.java |
Updates sign fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/SignRegionPartitionerTest.java |
Updates persisted-entry fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/RegionShardedSignEntryWriterTest.java |
Verifies V6 output. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/RegionShardedSignEntryLoaderTest.java |
Updates V6 fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/VersionedFileSignEntryLoaderTest.java |
Tests V5-to-V6 migration. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/Version6ConverterTest.java |
Tests dye backfilling. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/Version3ConverterTest.java |
Updates marker-group fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/Version1SignEntryLoaderTest.java |
Updates legacy fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/LegacySignFileMigratorTest.java |
Updates migration fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/ParsingContextTest.java |
Updates marker-group fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/LineGroupResolverTest.java |
Updates sign fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/ExtrudeGroupResolverTest.java |
Updates sign fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/ColorResolverTest.java |
Tests dye color resolution. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/markers/MarkerSetIdentifierCollectionTest.java |
Updates group fixtures. |
src/test/java/com/tpwalke2/bluemapsignmarkers/core/bluemap/actions/ActionFactoryTest.java |
Tests explicit color parameters. |
src/test/java/com/tpwalke2/bluemapsignmarkers/config/ConfigProviderTest.java |
Tests player-color configuration. |
src/main/java/com/tpwalke2/bluemapsignmarkers/mixin/SignBlockEntityInject.java |
Detects live sign mutations. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignTransitionResolver.java |
Resolves colors during transitions. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignManager.java |
Preserves incoming dye state. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignHelper.java |
Reads sign-side dyes. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignEntryHelper.java |
Selects the effective dye. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/SignEntry.java |
Adds persisted dye fields. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/SignFileVersions.java |
Adds persistence V6. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/RegionShardedSignEntryWriter.java |
Writes V6 files. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/models/SignEntryV5.java |
Freezes the V5 schema. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/VersionedFileSignEntryLoader.java |
Adds V6 migration paths. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/Version6Converter.java |
Backfills undyed values. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/Version5Converter.java |
Produces frozen V5 entries. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/Version1SignEntryLoader.java |
Extends legacy migration to V6. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/ColorResolver.java |
Implements dye precedence and alpha preservation. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/markers/MarkerGroup.java |
Adds allowPlayerColors. |
src/main/java/com/tpwalke2/bluemapsignmarkers/core/bluemap/actions/ActionFactory.java |
Accepts resolved colors. |
src/main/java/com/tpwalke2/bluemapsignmarkers/config/persistence/LoadingMarkerGroupV2.java |
Loads the new option. |
src/main/java/com/tpwalke2/bluemapsignmarkers/config/persistence/LoadingBMSMConfigV2.java |
Supplies its default value. |
src/main/java/com/tpwalke2/bluemapsignmarkers/config/ConfigProvider.java |
Resolves and validates the option. |
src/main/java/com/tpwalke2/bluemapsignmarkers/common/ColorUtils.java |
Adds RGBA hex formatting. |
README.md |
Documents player colors and examples. |
agent-context/README.md |
Updates the context index. |
agent-context/plans/player-marker-colors/spec.md |
Defines the feature specification. |
agent-context/plans/player-marker-colors/map.md |
Records design decisions. |
agent-context/plans/player-marker-colors/issues/08-end-to-end-player-dyed-markers.md |
Tracks integration work. |
agent-context/plans/player-marker-colors/issues/07-colour-resolution-logic.md |
Tracks resolver work. |
agent-context/plans/player-marker-colors/issues/06-live-dye-change-detection.md |
Tracks mutation detection. |
agent-context/plans/player-marker-colors/issues/05-config-flag-and-persisted-dye.md |
Tracks configuration and persistence. |
agent-context/plans/player-marker-colors/issues/04-write-spec-document.md |
Records specification completion. |
agent-context/plans/player-marker-colors/issues/03-recompute-trigger-design.md |
Documents recomputation design. |
agent-context/plans/player-marker-colors/issues/02-config-schema-for-opt-in-flag.md |
Documents configuration design. |
agent-context/plans/player-marker-colors/issues/01-dye-glow-event-hooks-research.md |
Documents hook research. |
agent-context/context/testing.md |
Updates testing guidance. |
agent-context/context/core-pipeline.md |
Documents dye processing. |
agent-context/context/config-and-persistence.md |
Documents configuration and V6 storage. |
agent-context/context/architecture.md |
Updates verification metadata. |
Review details
Suppressed comments (3)
agent-context/context/testing.md:276
- This coverage summary states the opposite of the tested and implemented behavior.
v2ContentStillMigratesWhenTheBackupFailsasserts a non-null converted result, and every V2–V5 branch logs the backup failure and continues migration. Update the summary so future maintainers do not infer that backup failure triggers the V1 fallback.
relying on Gson's nulls to coincidentally route there (ticket 05); and the `V2`/`V3`/`V4`/`V5` branches returning
`null` (falls through to the V1 loader) rather than proceeding, if backing up to
`.v2.bak`/`.v3.bak`/`.v4.bak`/`.v5.bak` fails (ticket 02).
agent-context/plans/player-marker-colors/spec.md:32
- The listed interaction items contradict the next paragraph: ink sacs and glow ink sacs only toggle glowing text, and
hasGlowingText()is not consumed by this feature. Only dye items alterSignText.getColor(), so describe those as the color input.
A player dyes a member sign (right-clicking it with a dye, ink sac, or glow ink sac item — vanilla mechanic,
no new UI). The sign's dye is read from `SignText.getColor()` (a `DyeColor`, default `BLACK` for an undyed
src/test/java/com/tpwalke2/bluemapsignmarkers/core/signs/ColorResolverTest.java:76
- The feature specification explicitly calls for coverage of winner removal handing off to the next-earliest dyed member, but the new tests only cover choosing the earliest winner while it remains present. Add the removal case so this core conflict-resolution guarantee cannot regress.
- Files reviewed: 57/57 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
There are two confirmed null-safety/robustness issues in core logic/persistence loading that can cause runtime exceptions or processing failures on malformed persisted data.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
src/main/java/com/tpwalke2/bluemapsignmarkers/core/signs/persistence/loaders/VersionedFileSignEntryLoader.java:103
- The V6+ load path returns the deserialized array as-is, which can include
nullelements if the JSON array containsnull. Downstream code iterates and dereferences entries (e.g., membership resolvers), so filteringnullelements here prevents a single bad entry from breaking loading/processing.
- Files reviewed: 57/57 changed files
- Comments generated: 1
- Review effort level: Lite
What
Lets players set a LINE/SHAPE/EXTRUDE marker's colour by dyeing one of its member signs, instead of only an admin editing
lineColor/fillColorin config.Why
Player-placed trails/regions/buildings currently all render in one admin-chosen colour per group; this gives players a way to customize their own markers' colour in-game without touching config.
Changes
allowPlayerColorsfield on marker groups (LINE/SHAPE/EXTRUDEonly; defaultfalse), wired throughMarkerGroup,ConfigProvider(parsing, defaults, type-mismatch warning), and config persistence models.ColorResolver: among a marker's current members, the earliest-placed member with a non-undyed (non-black) colour wins; only hue comes from the dye, alpha still comes from the group's configuredlineColor/fillColor. Re-evaluated on every membership/dye change.ActionFactory's line/shape/extrude action builders now take resolvedlineColor/fillColorinstead of reading them straight off theMarkerGroup.SignEntrygains persisted front/back dye fields;SignEntryHelpergains dye read/compare helpers (UNDYED_DYEsentinel,getDye).SignBlockEntityInjectmixin hook onSignBlockEntity.updateText(in addition to the existingupdateSignTexthook) to detect dye/ink-sac/glow-ink-sac applications, which don't go throughupdateSignText; a reentrancy flag prevents double-dispatch when a plain text edit also passes throughupdateTextinternally.SignEntryV5→ V6 viaVersion6Converter(adds the two dye fields, backfilled toUNDYED_DYEfor older entries);SignFileVersions,Version1SignEntryLoader,Version5Converter,VersionedFileSignEntryLoaderupdated for the new version.ColorUtils.toHex(r,g,b,a)added as the inverse ofparseHex.agent-context/docs and.scratch/issue files updated/added for this feature;README.mddocuments the new field and addsallowPlayerColors: trueto the LINE/SHAPE/EXTRUDE examples.Testing
./gradlew test— full unit suite, including newColorResolverTestandVersion6ConverterTest, plus updates to existing tests touched by the newMarkerGroup/SignEntryfields (ConfigProviderTest,ActionFactoryTest,SignEntryTest,SignEntryHelperTest,SignTransitionResolverTest,VersionedFileSignEntryLoaderTest, etc.)./gradlew runServer, place LINE/SHAPE/EXTRUDE signs withallowPlayerColors: true, dye a member sign and confirm the marker's colour updates; verify a black dye has no visible effect and falls back to the group's configured colour.