Implement UIEventSubscriber with per-player Wisper attachment to domain objects #299

Closed
opened 2026-03-16 01:59:24 +00:00 by freemo · 0 comments
Owner

Metadata

Key Value
Branch feature/m2-ui-event-subscriber
Commit Message feat: implement UIEventSubscriber with per-player Wisper attachment
Parent Epic #298 — UI Event Subscription System

Background and Context

Aethyr uses the Wisper gem for pub/sub eventing within the game engine. Domain objects (Player, Room, Area, CombatInstance, Calendar, Manager) broadcast events when state changes occur. Currently, no UI layer listens to these events. UIEventSubscriber bridges this gap by creating a per-player subscriber that attaches to the relevant domain objects and routes received events to the EventProjection system for rendering.

Expected Behavior

When a player connects, a UIEventSubscriber is instantiated for them. It subscribes to Wisper events from:

  • The Player object (stats, inventory, skill changes)
  • The current Room (entities entering/leaving, speech, items)
  • The current Area (weather, time, area-wide announcements)
  • The active CombatInstance (if in combat — turns, damage, end)
  • The Calendar (time advancement)
  • The Manager (system messages, server announcements)

Received events are forwarded to the EventProjection system for transformation into RenderOps.

subscriber = UIEventSubscriber.new(player)
subscriber.attach_all
# Player moves to new room → subscriber receives room events
# Player enters combat → subscriber receives combat events

Acceptance Criteria

  • UIEventSubscriber is created per player on connection.
  • Subscribes to Wisper events from: Player, Room, Area, CombatInstance, Calendar, Manager.
  • Events received are routed to the EventProjection system.
  • Subscriber holds references to all active subscriptions for cleanup.
  • #detach_all cleanly removes all subscriptions.
  • Subscriber is destroyed on player disconnect.

Subtasks

Code

  • Create UIEventSubscriber class with #initialize(player).
  • Implement #attach_all subscribing to Player, Room, Area, Calendar, Manager.
  • Implement #attach_combat(combat_instance) for combat subscription.
  • Implement #detach_all cleaning up all subscriptions.
  • Implement event routing: received events are forwarded to EventProjection.
  • Track active subscriptions in an internal registry for lifecycle management.
  • Hook into player connection/disconnection lifecycle.

Quality

  • Docs: Update YARD comments on affected classes and methods. Update relevant Docusaurus documentation pages if applicable.
  • Tests (Cucumber): Add tests/unit/ui_event_subscriber.feature covering subscribing to all domain objects, receiving events from each source, detaching all subscriptions, cleanup on disconnect, event routing to projection system.
  • Tests (Cucumber Integration): Add integration feature in tests/integration/ for UIEventSubscriber attaching to domain objects and routing events.
  • Tests (Profiling): Run bundle exec rake unit_profile and verify no performance regressions.
  • Quality: Verify coverage >=97% via bundle exec rake unit. If coverage is <97% then review the current unit test coverage report at build/tests/unit/coverage/ and use it to write new Cucumber based unit tests to improve coverage. Specifically, write Cucumber/Gherkin style unit tests that are descriptively named and specifically improve coverage on whichever file has the most uncovered lines by writing tests that will target the uncovered lines in the report. Once that is done rerun bundle exec rake unit to verify all tests pass and coverage is above >=97%. Only mark this as complete once coverage is >=97%, if not repeat this task as many times as is needed until coverage reaches >=97%.
  • Quality: Run bundle exec rake (default task: unit tests with coverage) and bundle exec rake integration, fix any errors if needed ensuring both pass across entire code base, do not ignore any failure even if it seems unrelated to this commit, fix it.

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
## Metadata | Key | Value | |-----|-------| | **Branch** | `feature/m2-ui-event-subscriber` | | **Commit Message** | `feat: implement UIEventSubscriber with per-player Wisper attachment` | | **Parent Epic** | #298 — UI Event Subscription System | ## Background and Context Aethyr uses the Wisper gem for pub/sub eventing within the game engine. Domain objects (Player, Room, Area, CombatInstance, Calendar, Manager) broadcast events when state changes occur. Currently, no UI layer listens to these events. `UIEventSubscriber` bridges this gap by creating a per-player subscriber that attaches to the relevant domain objects and routes received events to the EventProjection system for rendering. ## Expected Behavior When a player connects, a `UIEventSubscriber` is instantiated for them. It subscribes to Wisper events from: - The **Player** object (stats, inventory, skill changes) - The current **Room** (entities entering/leaving, speech, items) - The current **Area** (weather, time, area-wide announcements) - The active **CombatInstance** (if in combat — turns, damage, end) - The **Calendar** (time advancement) - The **Manager** (system messages, server announcements) Received events are forwarded to the `EventProjection` system for transformation into `RenderOp`s. ```ruby subscriber = UIEventSubscriber.new(player) subscriber.attach_all # Player moves to new room → subscriber receives room events # Player enters combat → subscriber receives combat events ``` ## Acceptance Criteria - [ ] `UIEventSubscriber` is created per player on connection. - [ ] Subscribes to Wisper events from: Player, Room, Area, CombatInstance, Calendar, Manager. - [ ] Events received are routed to the EventProjection system. - [ ] Subscriber holds references to all active subscriptions for cleanup. - [ ] `#detach_all` cleanly removes all subscriptions. - [ ] Subscriber is destroyed on player disconnect. ## Subtasks ### Code - [ ] Create `UIEventSubscriber` class with `#initialize(player)`. - [ ] Implement `#attach_all` subscribing to Player, Room, Area, Calendar, Manager. - [ ] Implement `#attach_combat(combat_instance)` for combat subscription. - [ ] Implement `#detach_all` cleaning up all subscriptions. - [ ] Implement event routing: received events are forwarded to `EventProjection`. - [ ] Track active subscriptions in an internal registry for lifecycle management. - [ ] Hook into player connection/disconnection lifecycle. ### Quality - [ ] Docs: Update YARD comments on affected classes and methods. Update relevant Docusaurus documentation pages if applicable. - [ ] Tests (Cucumber): Add `tests/unit/ui_event_subscriber.feature` covering subscribing to all domain objects, receiving events from each source, detaching all subscriptions, cleanup on disconnect, event routing to projection system. - [ ] Tests (Cucumber Integration): Add integration feature in `tests/integration/` for UIEventSubscriber attaching to domain objects and routing events. - [ ] Tests (Profiling): Run `bundle exec rake unit_profile` and verify no performance regressions. - [ ] Quality: Verify coverage >=97% via `bundle exec rake unit`. If coverage is <97% then review the current unit test coverage report at `build/tests/unit/coverage/` and use it to write new Cucumber based unit tests to improve coverage. Specifically, write Cucumber/Gherkin style unit tests that are descriptively named and specifically improve coverage on whichever file has the most uncovered lines by writing tests that will target the uncovered lines in the report. Once that is done rerun `bundle exec rake unit` to verify all tests pass and coverage is above >=97%. Only mark this as complete once coverage is >=97%, if not repeat this task as many times as is needed until coverage reaches >=97%. - [ ] Quality: Run `bundle exec rake` (default task: unit tests with coverage) and `bundle exec rake integration`, fix any errors if needed ensuring both pass across **entire** code base, do not ignore any failure even if it seems unrelated to this commit, fix it. ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done.
freemo added this to the v1.1.0 milestone 2026-03-16 01:59:24 +00:00
freemo self-assigned this 2026-03-16 01:59:24 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference: aethyr/Aethyr#299
No description provided.