Commit d4712b8
Subsystem 2a: live events poller + #events alerts + event !commands (#13)
* feat(2a): add map-marker snapshot, dimensions, and MapMarkersChangedEvent
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(2a): add GetMapMarkers/GetMapDimensions to the connection seam + fake
* feat(2a): poll map markers in the connected window and publish diffs
Adds MarkerPollInterval to ConnectionOptions (default 10s) and a
PollMarkersAsync loop to ConnectionSupervisor: fetches map dimensions
once on connect, polls markers on the configured interval, diffs each
result against the previous snapshot, and publishes MapMarkersChangedEvent
on the event bus. The first poll is a silent baseline; failed polls retain
the previous snapshot without producing a spurious diff. Three integration
tests verify the silent baseline, the added-marker publish, and the
failed-poll snapshot-retention contract.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(2a): strengthen marker-poll baseline test + deterministic fake script
- FakeRustSocketSource: add source-level EnqueueMarkers that pre-stages
marker lists and transfers them to FakeConnection at Create time,
eliminating the setup race between test code and the poll loop.
- FakeConnection: add per-connection ConcurrentQueue<IReadOnlyList<
MapMarkerSnapshot>> with "hold last" behaviour mirroring NextHeartbeat;
EnqueueMarkers on the connection available for post-connect injection.
Existing MarkersResult fallback preserved for Task-2 / no-script callers.
- First_marker_poll_is_a_silent_baseline: rewritten to script poll 1+2 with
a CargoShip (baseline + no-change) and poll 3 with CargoShip+Heli; waits
for the definite heli-added event as the race-free signal proving both
baseline suppression and diff correctness.
- Marker_added_on_a_later_poll_publishes_changed_event: scripted via source
queue before EnsureConnectionAsync; asserts exact MapDimensions(4000,4000,
500) from the FakeConnection default.
- Failed_marker_poll_retains_previous_snapshot: polls 1+2 scripted via
source queue; MarkersThrow used post-event for the throw/recover cycle;
hold-last means recovery sees the same CargoShip → no spurious event.
- ConnectionOptions.MarkerPollInterval: init → set for IOptions binding.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(2a): scaffold Features.Events project + GridReference helper
* feat(2a): add MarkerEventClassifier mapping deltas to domain events
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(2a): add in-memory EventStateStore + IEventState read-seam
* feat(2a): add EventEmbedRenderer + EN/FR event localization
Implements the pure event rendering layer: EventLocalizationCatalog with EN/FR
strings for cargo, helicopter, and Chinook events; IEventLocalizer/EventLocalizer
for localization; EventEmbedRenderer to build Discord embeds with grid references.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(2a): EventRelay, #events poster/locator, hosted service, DI + Workspace spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(2a): register Events feature + MarkerPollInterval option in the host
* feat(2a): add !cargo/!heli/!chinook/!events in-game command handlers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(2a): document the #events channel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(2a): derive grid row count from Height, not Width (final review)
GridReference computed the row count from Width and never read Height/
OceanMargin — correct only because Rust maps are square. Derive each axis
from its own dimension so the grid math is correct by construction.
Behavior-preserving for square maps; GridReference tests unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(2a): address Copilot review on PR #13
- EventEmbedRenderer + EventsCommandHandler: throw ArgumentOutOfRangeException
on an unknown MapEventKind instead of silently falling back to the chinook
key (fail-fast if a future kind is added).
- IRustServerConnection.GetMapMarkersAsync: correct the stale "all kinds /
MarkerKind.Other" XML doc — the mapped facade only surfaces cargo/heli/chinook.
- RustPlusSocketSource.AddMarkers: skip markers with null X/Y instead of
substituting (0,0), which would diff as a phantom spawn/despawn at the origin.
- DiscordEventChannelPoster: forward the CancellationToken via
RequestOptions.CancelToken (and rethrow OperationCanceledException so a
shutdown cancel isn't logged as a post failure).
- running-locally.md: chinook only alerts on spawn (cargo/heli on enter+leave) —
reword the #events description to match actual behavior.
- EventStateStoreTests: rename the un-alerted-removal test for clarity
(behavior was already correct).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>1 parent b83fe3d commit d4712b8
56 files changed
Lines changed: 2171 additions & 3 deletions
File tree
- docs/development
- src
- RustPlusBot.Abstractions
- Connections
- Events
- RustPlusBot.Features.Commands
- Handlers
- Localization
- RustPlusBot.Features.Connections
- Listening
- Supervisor
- RustPlusBot.Features.Events
- Classifying
- Formatting
- Hosting
- Posting
- Relaying
- Rendering
- State
- RustPlusBot.Features.Workspace
- Localization
- Locating
- Specs
- RustPlusBot.Host
- tests
- RustPlusBot.Abstractions.Tests/Connections
- RustPlusBot.Features.Commands.Tests
- Handlers
- RustPlusBot.Features.Connections.Tests
- Fakes
- RustPlusBot.Features.Events.Tests
- Classifying
- Formatting
- Relaying
- Rendering
- State
- RustPlusBot.Features.Workspace.Tests/Locating
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
| |||
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| 22 | + | |
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
41 | 45 | | |
42 | 46 | | |
43 | 47 | | |
| |||
Lines changed: 36 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
Lines changed: 36 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
Lines changed: 46 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
0 commit comments