Skip to content

Subsystem 2b-ii: per-server map layer toggles + monuments/vendor/players/rig-styling layers (icon render) - #16

Merged
HandyS11 merged 15 commits into
developfrom
feat/map-layers
Jun 18, 2026
Merged

Subsystem 2b-ii: per-server map layer toggles + monuments/vendor/players/rig-styling layers (icon render)#16
HandyS11 merged 15 commits into
developfrom
feat/map-layers

Conversation

@HandyS11

Copy link
Copy Markdown
Owner

Completes subsystem 2's map work, building on 2b (#15). Adds per-server layer settings with a ManageGuild toggle UI in #map, four new render layers, and replaces 2b's drawn glyphs with bundled icon assets. All layers default on.

What's in it

Data & settings

  • ServerMapSettings entity (six per-server bool toggles, default on, FK→RustServer cascade) + MapSettings migration
  • IMapSettingsStore / MapSettingsStore — returns all-on defaults when no row exists (no backfill needed for existing servers)

Render layers (icon-based, replacing 2b's C/H/K glyphs)

  • Monuments — bundled per-monument icons via a token→icon map; unknown tokens skipped
  • Travelling vendor — new MarkerKind.TravellingVendor + surfaced from the marker shim
  • Players — teammate positions from GetTeamInfoAsync (name + alive/online styling); avatars deferred
  • Oil-rig activation styling — reuses 2a-ii IRigState (red ring when a rig is Active)
  • Icons vendored from rustplus-desktop (+ player.png from rustplusplus) as embedded resources; attributed in NOTICE as Facepunch/Rust game art (companion-app fair use)

Toggle UI

  • Persistent ManageGuild control message in #map (six toggle buttons, EN/FR), reconciler-owned and separate from the delete+reposted image — the poster now deletes only its own attachment-bearing image posts so the control message survives
  • Toggling a layer flips one setting, re-renders the control labels, and publishes a new MapSettingsChangedEventMapHostedService repaints immediately (throttled)

Architecture notes

  • MapLayerSettings is Persistence-owned (Persistence does not reference Features.Map); the composer maps it to MapLayerSet
  • MapComposer (singleton) resolves the scoped settings store via a per-call scope — no captive dependency
  • New IRustServerQuery.GetMonumentsAsync seam (the composer reads monuments per-render; 2a-ii only consumed them transiently for rig detection)

Verification

  • Build dotnet build -warnaserror: 0/0
  • Full suite: 367 tests green across 9 assemblies (Map 19→29, Workspace 51→55, Persistence →54, Connections →35)
  • jb cleanupcode --profile=ReformatAndReorder clean; no EF model drift
  • Built subagent-driven (per-task TDD + spec/quality reviews) + a final whole-branch Opus review (no Critical/Important; one forged-input edge hardened before this PR)

Deferred (Minor, non-blocking)

  • Steam profile-picture avatars for the players layer (glyph/icon for now)
  • waterwell.png/powerstation.png embedded without a token mapping (harmless)

🤖 Generated with Claude Code

HandyS11 and others added 14 commits June 18, 2026 18:40
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements the missing MapIcons.Rig(RigKind, bool active) API-contract method
(Task 3 "Produces" list); adds Rig_resolves_for_known_kinds Theory test covering
both RigKind.Small and RigKind.Large. Suppresses RCS1163 on the reserved `active`
parameter with a narrow pragma + explaining remarks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…bucket

- Added MarkerKind.TravellingVendor = 5 to the enum (with XML doc)
- Wired data.TravellingVendorMarkers into GetMapMarkersAsync via AddMarkers
- Activated the deferred MapIcons.Marker TravellingVendor arm (Load("vendor"))
  that was stubbed out pending the enum member; vendor.png already embedded
Adds GetMonumentsAsync(ulong guildId, Guid serverId, CancellationToken)
to IRustServerQuery; ConnectionSupervisor implements it by delegating to
the live socket's internal GetMonumentsAsync or returning [] when no
socket is registered. Includes supervisor test asserting empty result
when no live socket exists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-adds the Renders_the_grid_even_with_no_markers test dropped during
Task 7's MapComposer rewrite. Uses two MapComposer instances (grid-on
vs grid-off, zero markers) and asserts their output PNGs differ,
proving the grid still renders on low-activity / just-connected servers.

Also fixes player label: alive+offline now shows (offline) instead of
(dead); only dead players show (dead).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cosmetic line-wrapping applied by JetBrains CleanupCode 2026.1.2 with
the ReformatAndReorder profile. All 5 touched files are 2b-ii branch
files; no pre-existing drift in unrelated files.

Files reformatted:
- src/RustPlusBot.Features.Map/Composing/MapComposer.cs
- src/RustPlusBot.Persistence/Map/MapSettingsStore.cs
- tests/RustPlusBot.Features.Map.Tests/MapRendererTests.cs
- tests/RustPlusBot.Persistence.Tests/Map/MapSettingsStoreTests.cs
- tests/RustPlusBot.Persistence.Tests/Map/ServerMapSettingsSchemaTests.cs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…er id

Validate the parsed serverId exists in this guild before any persistence.
Resolves the FK-violation/hung-ack edge case noted in the final review.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 18, 2026 17:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the “Subsystem 2b-ii” map slice by adding per-server persisted layer toggles, a persistent ManageGuild map-control UI in #map, and switching the renderer from drawn glyphs to embedded icon assets while expanding the rendered layers (monuments, travelling vendor, players, rig activation styling).

Changes:

  • Add ServerMapSettings persistence (entity + EF migration) and an EF-backed IMapSettingsStore with “all layers on” defaults when no row exists.
  • Add #map control message rendering + interaction handling to toggle layers per server and trigger immediate repaints via MapSettingsChangedEvent.
  • Expand the map render pipeline to support new layers and vendored icons (plus travelling vendor marker kind).

Reviewed changes

Copilot reviewed 42 out of 83 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/RustPlusBot.Persistence.Tests/Map/ServerMapSettingsSchemaTests.cs Verifies ServerMapSettings defaults and cascade delete behavior.
tests/RustPlusBot.Persistence.Tests/Map/MapSettingsStoreTests.cs Tests IMapSettingsStore default/all-on behavior and per-layer updates.
tests/RustPlusBot.Features.Workspace.Tests/Messages/MapControlMessageRendererTests.cs Tests #map control message header + button rendering and FR label.
tests/RustPlusBot.Features.Map.Tests/MarkerGlyphsTests.cs Removes glyph-based marker tests (glyph rendering replaced by icons).
tests/RustPlusBot.Features.Map.Tests/MapRendererTests.cs Updates renderer tests for new layer inputs and adds all-layers render coverage.
tests/RustPlusBot.Features.Map.Tests/MapRegistrationTests.cs Updates DI registration test for new map dependencies (rig state + settings store).
tests/RustPlusBot.Features.Map.Tests/MapLayerSetTests.cs Updates layer-set defaults to “all on” semantics.
tests/RustPlusBot.Features.Map.Tests/MapIconsTests.cs Adds tests for icon resolution/mapping behavior (markers/monuments/rigs/player).
tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs Expands composer tests for settings-driven gathering and new layer seams.
tests/RustPlusBot.Features.Connections.Tests/ServerQueryTests.cs Adds coverage for monuments query behavior without a live socket.
src/RustPlusBot.Persistence/PersistenceServiceCollectionExtensions.cs Registers IMapSettingsStore in persistence DI.
src/RustPlusBot.Persistence/Migrations/BotDbContextModelSnapshot.cs Updates EF snapshot to include ServerMapSettings.
src/RustPlusBot.Persistence/Migrations/20260618164017_MapSettings.Designer.cs Adds migration designer for ServerMapSettings.
src/RustPlusBot.Persistence/Migrations/20260618164017_MapSettings.cs Adds migration creating ServerMapSettings table.
src/RustPlusBot.Persistence/Map/MapSettingsStore.cs Implements EF-backed settings store with all-on defaults.
src/RustPlusBot.Persistence/Map/MapLayer.cs Defines MapLayer enum + MapLayerSettings value object.
src/RustPlusBot.Persistence/Map/IMapSettingsStore.cs Introduces settings store interface.
src/RustPlusBot.Persistence/Configurations/ServerMapSettingsConfiguration.cs EF configuration for ServerMapSettings PK + cascade FK.
src/RustPlusBot.Persistence/BotDbContext.cs Adds DbSet<ServerMapSettings> and applies configuration.
src/RustPlusBot.Features.Workspace/WorkspaceServiceCollectionExtensions.cs Registers MapControlMessageRenderer for reconciler rendering.
src/RustPlusBot.Features.Workspace/WorkspaceKeys.cs Adds WorkspaceMessageKeys.ServerMap.
src/RustPlusBot.Features.Workspace/WorkspaceComponentIds.cs Adds MapTogglePrefix component ID prefix.
src/RustPlusBot.Features.Workspace/Specs/ServerWorkspaceSpecProvider.cs Adds per-server map-control message spec in #map.
src/RustPlusBot.Features.Workspace/Modules/MapComponentModule.cs Handles map layer toggle button interactions + triggers repaint event.
src/RustPlusBot.Features.Workspace/Messages/MapControlMessageRenderer.cs Renders the persistent #map control message with six toggle buttons.
src/RustPlusBot.Features.Workspace/Localization/LocalizationCatalog.cs Adds EN/FR strings for map control header and button labels.
src/RustPlusBot.Features.Map/RustPlusBot.Features.Map.csproj Embeds PNG icon resources for map rendering.
src/RustPlusBot.Features.Map/Rendering/PlayerPlacement.cs Adds placement records for players/monuments/rigs.
src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs Switches to icon rendering and adds monuments/players/rig layers.
src/RustPlusBot.Features.Map/Rendering/MapLayerSet.cs Extends layer set to include players and sets “all on” default.
src/RustPlusBot.Features.Map/Posting/DiscordMapChannelPoster.cs Preserves the control message by deleting only attachment-bearing prior posts.
src/RustPlusBot.Features.Map/Hosting/MapHostedService.cs Adds settings-changed event loop to trigger immediate map repaints.
src/RustPlusBot.Features.Map/Composing/MapComposer.cs Reads per-server settings via scoped store and gathers new layer data.
src/RustPlusBot.Features.Map/Assets/MonumentIconMap.cs Maps monument tokens to icon keys (unknown tokens skipped).
src/RustPlusBot.Features.Map/Assets/MarkerGlyphs.cs Removes glyph-based marker registry (replaced by icons).
src/RustPlusBot.Features.Map/Assets/MapIcons.cs Loads/caches embedded PNG icons for markers/monuments/rigs/player.
src/RustPlusBot.Features.Connections/Supervisor/ConnectionSupervisor.cs Implements IRustServerQuery.GetMonumentsAsync.
src/RustPlusBot.Features.Connections/Listening/RustPlusSocketSource.cs Surfaces travelling vendor marker bucket from Rust+ map markers API.
src/RustPlusBot.Domain/Map/ServerMapSettings.cs Adds persisted per-server map layer settings entity (defaults on).
src/RustPlusBot.Abstractions/Events/MapSettingsChangedEvent.cs Adds event used to request immediate repaint after toggles.
src/RustPlusBot.Abstractions/Connections/MarkerKind.cs Adds TravellingVendor marker kind.
src/RustPlusBot.Abstractions/Connections/IRustServerQuery.cs Adds GetMonumentsAsync query seam.
NOTICE Updates attribution/notice text for bundled icon assets.
Files not reviewed (1)
  • src/RustPlusBot.Persistence/Migrations/20260618164017_MapSettings.Designer.cs: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/RustPlusBot.Features.Map/Rendering/MapRenderer.cs
Copilot review (PR #16): DrawMonuments (and the sibling marker/rig/player
loops) called image.Mutate once per item, building and executing a fresh
ImageSharp processing pipeline each time. Refactor all four layers to draw
every item inside ONE Mutate per layer, so a server with many monuments pays
for one pipeline instead of N. Behaviour-preserving: same icons composited at
the same coordinates in the same order; the cached MapIcons sources are still
only read (drawn onto the target ctx), never mutated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HandyS11
HandyS11 merged commit 8312171 into develop Jun 18, 2026
3 checks passed
@HandyS11
HandyS11 deleted the feat/map-layers branch June 18, 2026 18:06
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.

2 participants