The way we're synchronising the state on the server and on the client happens via diffs. We're working on the same board state object, but some details don't survive the serialisation (i.e. the lambdas that are everywhere as this is a lisp 😂 )
But as the frontend does not need to do the actual resolving, for most cases, this is fine
In any case, what the server does is to prepare diffs of the board state before and after resolution of an effect / action. As there is hidden information involved, this is done 4 times:
Hidden info from the perspective of the Corp player (e.g. don't see Runner hand)
Hidden info from the perspective of the Runner player (e.g. don't see Corp hand)
Hidden info for the spectators (e.g. don't see either hand)
No hidden info for the replay
The first three sets of diffs are sent to the respective clients for them to apply to their local game state
The fourth is saved on the server to result in the json file that is the replay
When the replay is being played on the client, I'm simply faking incoming server packages by calling the respective websocket handler responsible for applying the diffs. In replay mode, all outgoing messages are suppressed, so that clicking any of the buttons on the frontend doesn't do anything
It has been a while, but I think on loading in a replay I was also preparing snapshots of the board state at the start of each player's turns. That way when jumping back and forward across many turns, you don't have to apply dozens of diffs sequentially but can jump to the nearest snapshot and go from there
Originally posted by @danj3000 in https://github.com/Ashteki/ashteki/issues/1366#issuecomment-2016862815