The problem I needed to solve
When audio, interface and logging all react to gameplay, directly attaching them to every rule creates many dependencies. I needed a simple event boundary.
Implementation in this snapshot
GameEventBus exposes typed CardPlayed, RoundStarted, RoundEnded, GameStarted and GameEnded events. Its Publish methods pass their data to current subscribers.
The design decision and its cost
Typed events give consumers a specific contract. The tradeoff is that this is not a distributed messaging system; subscribers run within the same execution path.
Current boundaries
The bus does not isolate each subscriber’s exceptions. Subscription lifetime also belongs to the consumer. An event keyword alone does not prevent leaks or remove every dependency.
Is a card event a result or a request?
Suppose a player touches an illegal card and the interface wants to start its sound and movement. Publishing CardPlayed before validation would make listeners treat an unaccepted action as real. GameEventBus.PublishCardPlayed checks neither ownership, suit nor turn; it only forwards eventData. Its timing contract therefore matters: the game flow must establish validity and the intended state change before announcing the event. The bus cannot enforce the order of outside calls.
CardPlayedEvent carries the player, card instance, table-card count and play order. A listener can identify the card without interpreting button text. Read-only properties do not mean RuntimePlayer was copied, however. A listener consulting that reference later may see updated state. Historical logging needs an explicit distinction between values captured at publication and live references. The word Event does not settle that distinction.
Publish methods invoke delegates directly; they create no queue, separate scheduling or background processing. Heavy listeners extend the publication path, and the bus has no protected loop to continue through other listeners after an exception. This argues for small reactions and deliberate subscription lifetimes. Unity components can accumulate duplicate subscriptions across activation cycles. Consumers must pair registration with removal rather than assume that the bus manages their lifetime.
What this stage taught me
For me, events describe something that happened. Rules should establish a valid action first, and presentation and sound should react afterward; publishing does not replace gameplay validation.




