Skip to content

Make GameLog transient — clients build from forwarded events#9802

Merged
tool4ever merged 4 commits intoCard-Forge:masterfrom
MostCromulent:gamelog
Feb 19, 2026
Merged

Make GameLog transient — clients build from forwarded events#9802
tool4ever merged 4 commits intoCard-Forge:masterfrom
MostCromulent:gamelog

Conversation

@MostCromulent
Copy link
Copy Markdown
Contributor

Summary

Follow-up to #9760, as requested by @tool4ever in his approval review:

as follow-up please attempt turning TrackableProperty.GameLog transient-like (no longer sent over network) -> because each remote client would now be able to just send the events to its own GameLogFormatter?

Now that game events are forwarded to remote clients (#9760), each client can build its own GameLog locally by feeding forwarded events to GameLogFormatter. This removes GameLog from network serialization entirely.

Changes

  • GameView: gameLog is now a transient field (no longer sent over network). Removed updateGameLog() which was only reachable from dead code
  • TrackableProperty: Removed GameLog entry (was typed as StringType but stored a GameLog object — a type mismatch)
  • Game: Removed dead method updateGameLogForView() (no callers)
  • GameLog: Narrowed getEventVisitor() return type to GameLogFormatter (was IGameEventVisitor<?>) and removed the now-unused import
  • AbstractGuiGame: In handleGameEvent(), feeds forwarded events to the local GameLogFormatter so remote clients populate their own game log. The host is unaffected — it populates via its EventBus subscription

Testing

Manually tested with a two-player network game (host + remote client). Added temporary System.out.println logging in handleGameEvent() to verify client-side GameLog population. Confirmed:

  • GameLog entries are created on the remote client for all expected event types: mulligans, turn/phase transitions, land plays, spell casts, combat assignments, blockers, damage
  • Entries begin appearing after openView (when the client creates its local Game/GameView with a real GameLog). Events before openView are setup events (zone changes, stats) that don't produce log entries on the host either
  • No double-population on the host — handleGameEvent() is only called on the remote client via the network protocol; the host uses its EventBus subscription

GameLog was a TrackableProperty on GameView that was never actually
delta-synced (flagAsChanged was dead code). Now that game events are
forwarded to remote clients, each client can run its own GameLogFormatter
on the forwarded events to build the game log locally.

- Move GameLog from TrackableProperty to transient field on GameView
- Remove TrackableProperty.GameLog enum entry
- Remove dead code: Game.updateGameLogForView(), GameView.updateGameLog()
- Wire AbstractGuiGame.handleGameEvent() to feed events to local GameLog
- Narrow GameLog.getEventVisitor() return type to GameLogFormatter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tool4ever
Copy link
Copy Markdown
Contributor

works almost as expected :)
the only problem is I neglected to consider that in some places GameLog.add(final GameLogEntryType type, final String message) gets used to write directly to it
so in those cases the client doesn't receive them now

I'd suggest we just wrap them in a new lightweight GameEventAddLog to pass them along instead. Unless our dear AI can think of an even simpler approach...

…ents

GameLog was made transient so clients build logs from forwarded events,
but 25 call sites used GameLog.add() directly, bypassing the event
system. Introduces GameEventAddLog to wrap these calls so they propagate
to remote clients.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MostCromulent
Copy link
Copy Markdown
Contributor Author

See latest commit.

I considered a few alternatives:

  1. Reuse GameEventRandomLog — already exists, but it hardcodes STACK_RESOLVE. The 25 call sites use 9 different entry types (ANTE, ZONE_CHANGE, COMBAT, MANA, DISCARD, etc.), so we'd lose log filtering. Not viable.
  2. Add a callback to GameLog.add() so it fires events automatically — avoids changing 25 call sites, but adds architectural complexity (circular dependency between GameLog and Game, callback initialization ordering, split internal/external add paths). More clever but harder to reason about.
  3. GameEventAddLog (tool4ever's suggestion) — one new record, visitor plumbing (3 lines across 2 files), one formatter handler, and 25 mechanical call-site changes from game.getGameLog().add(X, Y) → game.fireEvent(newGameEventAddLog(X, Y)).

I agree with tool4ever — GameEventAddLog is the simplest. Each call-site change is trivial, follows existing patterns, and the result is consistent: all log entries flow through the event system, so both host and client build identical logs.

@tool4ever tool4ever merged commit 4e62b88 into Card-Forge:master Feb 19, 2026
2 checks passed
@MostCromulent MostCromulent deleted the gamelog branch February 23, 2026 20:39
clairchiara pushed a commit to clairchiara/forge that referenced this pull request Feb 28, 2026
…rge#9802)

GameLog was made transient so clients build logs from forwarded events,
but 25 call sites used GameLog.add() directly, bypassing the event
system. Introduces GameEventAddLog to wrap these calls so they propagate
to remote clients.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: tool4EvEr <tool4EvEr@>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants