Page 2 of 2

Re: How to handle complex multi-step turns client side with undo?

Posted: 06 May 2021, 16:57
by robinzig
fafa-fr wrote: 06 May 2021, 13:09 Hi,
I'm sorry I don't have time right now to read your whole post and to answer, but I just wanted to let you know that I'll take some time to read it and to explain what I did for Castles of Burgundy, and what are the pros and cons of this approach.
Thank you fafa-fr. Even if (as seems likely) I don't end up going with the client-side approach I would be *very* interested in hearing not only what you did for CoB, but your insight as the developer into what the pros and cons were. No rush but I am definitely very keen to see this.

PS you did a great job with the implementation ! :D

EDIT: went on my control panel and I appear to have access (read-only, of course) to the CoB source code! I don't remember requesting access but perhaps I did - thank you if you spontaneously gave it to me, I'll definitely study it when I get the chance! :D

Re: How to handle complex multi-step turns client side with undo?

Posted: 06 May 2021, 19:11
by RavingWanderer
I implemented a server-side undo stack in Hand and Foot. The moves a player makes are (for the most part) also kept secret from the other players by selective modification of the data given out by getAllDatas, based on the stack content and the requesting player. When the moves are exposed to the other players (generally the end of the player's turn or other key action), the notifications associated with those actions are replayed for the other players. The stack is cleared when the moves are no longer reversible.

This struck me as being much simpler than managing reasonably complex content changes in the client, and means that (as nothers have noted) that refreshing the active player does not lose in-progress moves.

Re: How to handle complex multi-step turns client side with undo?

Posted: 07 May 2021, 01:19
by fafa-fr
robinzig wrote: 06 May 2021, 16:57 EDIT: went on my control panel and I appear to have access (read-only, of course) to the CoB source code! I don't remember requesting access but perhaps I did - thank you if you spontaneously gave it to me
I didn't do it myself, you may have asked it some time ago.

Here are a few things about CoB implementation:

- I didn't implement Undo on client side, it would have been a nightmare, and very risky regarding potential bugs (well at least if you want to display possible / legal moves, and tell players that a move is forbidden when they do it, and not later when they confirm their whole turn, which would be a terrible user experience). I wanted to allow players to undo a whole turn, and that can be a lot of actions, each of them having a lot of consequences on what's possible or not for subsequent actions.
I only used client states for a few simple cases. The least simple case is when choosing a tile to place, because it involves some server-side computing of possible moves (and number of workers needed for each move) for each die / tile couple, that will be passed to the client so that it can display proper informations upon die / tile player selection. But I wouldn't have used this approach for a more complex sequence of actions.

- I don't use BGA's undo feature because I don't want to reload the whole page on each Undo. So I have backup (snapshot) tables that record almost everything at the beginning of a turn, and for the UI undo, a `moved_pieces` table to keep track of the pieces that have moved during the turn (not of the moves themselves, upon Undo I just move them back to the place recorded in the backup table). There are a few tricky things, like for the turn order discs. Each game will have different tricky things to undo, and if it gets too complicated, the page reload of BGA's built-in Undo feature may be a good choice.

- But I thought that it would be confusing for players (especially new players) to see game tiles moving all over the board when a turn with several actions is cancelled. (They may not notice that these moves are caused by an "undo turn"). So I don't send notifications to other players and spectators when the moves are done, I store them in a DB table, then send them when the turn is confirmed (maybe not the best choice, see later). This is possible thanks to the new "Ignoring notifications" feature (see "Game interface logic" Studio doc page), that allows the player that just confirmed their turn to ignore these end-of-turn notifications, to avoid duplicate log messages. But at the moment there's a problem: these duplicate log messages are not ignored on the "game review" page, in the list of moves (hence the "maybe not the best choice", but maybe this could be fixed).

- Regarding the choice to show moves to opponents / spectators in real-time or only when they are confirmed, I think the feeling can be very different for different games (risk of confusion or not, pace of the game, ...). But even for a given game, the feeling can be different for different players: some castles of burgundy players would prefer to see the moves during their opponent's turn, but I'm pretty sure that some players play a lot with the undo feature, and that seeing all these moves and cancelations could be confusing or just plain annoying for a lot of other players. The ideal thing for me would be to have a user preference for this, but I'm not sure that with the framework as it is today it would be possible / doable without a lot of efforts and potential bugs (we don't have much control on log messages, even if the idea to strike cancelled move messages is good). But I really think that it would be great to improve the framework regarding undoing and notification management.

Re: How to handle complex multi-step turns client side with undo?

Posted: 07 May 2021, 07:08
by Tisaac
fafa-fr wrote: 07 May 2021, 01:19 - Regarding the choice to show moves to opponents / spectators in real-time or only when they are confirmed, I think the feeling can be very different for different games (risk of confusion or not, pace of the game, ...). But even for a given game, the feeling can be different for different players: some castles of burgundy players would prefer to see the moves during their opponent's turn, but I'm pretty sure that some players play a lot with the undo feature, and that seeing all these moves and cancelations could be confusing or just plain annoying for a lot of other players. The ideal thing for me would be to have a user preference for this, but I'm not sure that with the framework as it is today it would be possible / doable without a lot of efforts and potential bugs (we don't have much control on log messages, even if the idea to strike cancelled move messages is good). But I really think that it would be great to improve the framework regarding undoing and notification management.
In order to avoid confusion, you can do what I've done in several games : "dash cancelled notifications"
Image

That's a lot more work through, and I agree that in some games it might not be appropriated depending on the complexity/pace of the game.

Re: How to handle complex multi-step turns client side with undo?

Posted: 07 May 2021, 10:11
by fafa-fr
Tisaac wrote: 07 May 2021, 07:08 In order to avoid confusion, you can do what I've done in several games : "dash cancelled notifications"
yes, that's what I meant with:
fafa-fr wrote: 07 May 2021, 01:19 even if the idea to strike cancelled move messages is good
The only thing that restrains me is that it's not an "official" feature, and I'm not sure it works well in all cases (replays, etc...) and that it will continue to work with framework evolutions, and I didn't take time to check about this.
But when I said that
fafa-fr wrote: 07 May 2021, 01:19 I really think that it would be great to improve the framework regarding undoing and notification management.
this is the kind of things I was thinking about.

Re: How to handle complex multi-step turns client side with undo?

Posted: 07 May 2021, 10:46
by robinzig
fafa-fr wrote: 07 May 2021, 01:19 Here are a few things about CoB implementation:

- I didn't implement Undo on client side, it would have been a nightmare, and very risky regarding potential bugs (well at least if you want to display possible / legal moves, and tell players that a move is forbidden when they do it, and not later when they confirm their whole turn, which would be a terrible user experience). I wanted to allow players to undo a whole turn, and that can be a lot of actions, each of them having a lot of consequences on what's possible or not for subsequent actions.
I only used client states for a few simple cases. The least simple case is when choosing a tile to place, because it involves some server-side computing of possible moves (and number of workers needed for each move) for each die / tile couple, that will be passed to the client so that it can display proper informations upon die / tile player selection. But I wouldn't have used this approach for a more complex sequence of actions.

- I don't use BGA's undo feature because I don't want to reload the whole page on each Undo. So I have backup (snapshot) tables that record almost everything at the beginning of a turn, and for the UI undo, a `moved_pieces` table to keep track of the pieces that have moved during the turn (not of the moves themselves, upon Undo I just move them back to the place recorded in the backup table). There are a few tricky things, like for the turn order discs. Each game will have different tricky things to undo, and if it gets too complicated, the page reload of BGA's built-in Undo feature may be a good choice.

- But I thought that it would be confusing for players (especially new players) to see game tiles moving all over the board when a turn with several actions is cancelled. (They may not notice that these moves are caused by an "undo turn"). So I don't send notifications to other players and spectators when the moves are done, I store them in a DB table, then send them when the turn is confirmed (maybe not the best choice, see later). This is possible thanks to the new "Ignoring notifications" feature (see "Game interface logic" Studio doc page), that allows the player that just confirmed their turn to ignore these end-of-turn notifications, to avoid duplicate log messages. But at the moment there's a problem: these duplicate log messages are not ignored on the "game review" page, in the list of moves (hence the "maybe not the best choice", but maybe this could be fixed).

- Regarding the choice to show moves to opponents / spectators in real-time or only when they are confirmed, I think the feeling can be very different for different games (risk of confusion or not, pace of the game, ...). But even for a given game, the feeling can be different for different players: some castles of burgundy players would prefer to see the moves during their opponent's turn, but I'm pretty sure that some players play a lot with the undo feature, and that seeing all these moves and cancelations could be confusing or just plain annoying for a lot of other players. The ideal thing for me would be to have a user preference for this, but I'm not sure that with the framework as it is today it would be possible / doable without a lot of efforts and potential bugs (we don't have much control on log messages, even if the idea to strike cancelled move messages is good). But I really think that it would be great to improve the framework regarding undoing and notification management.
Thank you very much for this. I'll certainly be taking time to digest it before making the decision as to how to handle this in my own project.

(Although I realised this morning that some card resolutions involving drawing more cards, after which undo certainly isn't possible or desired - so I'm now thinking I might just not have any undo functionality at all. Which would certainly make development simpler! :D )

Re: How to handle complex multi-step turns client side with undo?

Posted: 07 May 2021, 14:12
by Victoria_La
I just have to throw my 2c ;) And maybe I will update wiki on state machines after with all the great points here.
Tissaac did a good summary on pros and cons, but here are my notes:
* I am proponent of client side moves which I did in all games except my first. In the first game I did not know about client state and up with close to 100 states and stack state machine (where state goes on stack and there is like "return" command). That was so bad (complecxity wise) I never want to do it again.
* The sending data at once to server is not a cons of client side - its pretty easy - you just store all data in js and send at the end (not sure where "hard" comes from?)
* The cons is what you mention in original post - if choices get out of control with every client step, there are few mitigations
** Client does same calculation as server (it sounds bad - but if you have data driver rule engine - its not actually more work)
** Server send data with choices (that cannot be unlimited but in most games few levels down is more than enough)
** Client does not enforce choices - server enforces it after the move sent
* The second problem - which is hardest so far I faced - part of sequence that is trully random or reveal data which cannot be undone (that is same issue for undo moved though)
** In this case data must be send to server, it will reply and clent will resume where it left. But its hard to manage from states perspective.

Re: How to handle complex multi-step turns client side with undo?

Posted: 07 May 2021, 18:06
by robinzig
Victoria_La wrote: 07 May 2021, 14:12 I just have to throw my 2c ;) And maybe I will update wiki on state machines after with all the great points here.
Tissaac did a good summary on pros and cons, but here are my notes:
* I am proponent of client side moves which I did in all games except my first. In the first game I did not know about client state and up with close to 100 states and stack state machine (where state goes on stack and there is like "return" command). That was so bad (complecxity wise) I never want to do it again.
* The sending data at once to server is not a cons of client side - its pretty easy - you just store all data in js and send at the end (not sure where "hard" comes from?)
* The cons is what you mention in original post - if choices get out of control with every client step, there are few mitigations
** Client does same calculation as server (it sounds bad - but if you have data driver rule engine - its not actually more work)
** Server send data with choices (that cannot be unlimited but in most games few levels down is more than enough)
** Client does not enforce choices - server enforces it after the move sent
* The second problem - which is hardest so far I faced - part of sequence that is trully random or reveal data which cannot be undone (that is same issue for undo moved though)
** In this case data must be send to server, it will reply and clent will resume where it left. But its hard to manage from states perspective.
Thank you. It's been great to hear from so many experienced BGA devs on this :)