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

Game development with Board Game Arena Studio
User avatar
robinzig
Posts: 461
Joined: 11 February 2021, 18:23

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

Post by robinzig »

Hi everyone,

Apologies if there is already an established answer to this somewhere - there likely is, since the functionality I am after already exists on several games I regularly play on BGA. (Eg Russian Railroads, the currently-alpha Castles of Burgundy, and probably lots more). But I'm new to the BGA framework and am yet to see anything that looks like it will answer this.

I'm trying to implement Deus (in the *very* early stages - haven't even started the UI view yet!), which I picked in part because it's not a particularly complex game in the sense of having lots of rules and moving parts. But there are potentially complex chains of decisions that players will take on their turn, which typically will involve:
- playing a card
- choosing how to pay for it (since you can always substitute money for other resources)
- choosing where to put the corresponding building
- activating the effects of previously-played cards, many of which will involve decisions (eg moving pieces, or whether to pay resources for VP...)

I have a fairly good outline in my head of how I could do this by simply implementing different actions and having each one send a request to the server, have it update the game state via the database and return the notification to the client. But this would obviously mean that the player couldn't "undo" any steps of their turn, and also that all other players would see the "progress" of every player's turn in the logs. I think it would be a better user experience to do it like the above-mentioned games do, where while only the active player is making decisions, they should do everything client-side and with the option to "wind their turn back" (unseen by the other players) at any point, then finally "lock this in" by submitting the move to the server and triggering all the notifications of what happened on their turn.

I have looked at (although not yet understood in depth) the part of the cookbook on "client state" - and that certainly seems like it could be useful for updating the UI while the player plays, without yet submitting anything to the server. But what I'm really unclear on is how to record the entire sequence of choices and submit that as an "action" in one go.

I can see how it might work for simple cases like the one discussed in the link above, ie. where you choose a worker then choose where it goes, because then you have essentially 2 discrete pieces of information to send to the server. But in Deus (and I assume in lots of other similar games) there are essentially (not really of course) an "infinite" number of things that can happen, and I can't think how to handle this. (Other than by simply having the client calculate all the needed changes in the game-state and send that to the server - but that's obviously no good even though it would probably seem to work for most players, because there's nothing to stop a cheater making a request that says "I now have 100 more coins and 50 more VP" and have the server believe that.)

What I really think I'm looking for is a way to "save" on the client side a bunch of server requests, without actually submitting them, then basically submit them all one after the other, so that the server can check legality of the entire sequence and update the database as it goes along (and presumably roll back if any of the actions are illegal - not sure if the database transaction model will make that work automatically or not) and then send all the relevant notifications back to all players at the end. But I'm not sure how to achieve this in the BGA framework.

Thanks for reading, I hope you've understood my question - but if not please feel free to ask for clarifications. (Although not code snippets, I haven't started to code any of this yet, or even the state machine - I'm just trying to get an outline in my head of what to do before starting any code!) I look forward to some good answers! :)
Last edited by robinzig on 06 May 2021, 12:46, edited 1 time in total.
User avatar
Tisaac
Posts: 2743
Joined: 26 August 2014, 21:28

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

Post by Tisaac »

I disagree with your base axiom : I would do everything through backend.
To sum up pro/cons :
Backend pros :
- you avoid duplicating the logic in front and back
- the user can refresh mid turn without loosing everything
- taking action are way easier because they are atomic
Backend cons :
- you need to code the undo feature : you can either use the one from the framework that works if no-one else do an action during a turn, or if no random event is triggered

Frontend pros :
- action are immediate, even with slow internet connections
- easy to undo since nothing is stored during the turn
Frontend cons :
- sending the whole bunch of actions to treat them is harder (the exact issue your are facing)
- refreshing the page means loose everything
- You need to duplicate the logic

As for the fact that other players sees what a player is doing during its turn, it's neither a pro or cons, it depends what the rulebook says.
If the actions are public, then that's another pros for backend because you really want to see what someone is doing during its turn instead of just wondering if he is actually playing or not.
On the other hand, if some actions are private, then that's a pro for frontend.
User avatar
robinzig
Posts: 461
Joined: 11 February 2021, 18:23

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

Post by robinzig »

Thank you for the reply - I agree with a lot of your points, particularly that there's not a huge downside to other players seeing actions "live". Although I'm still curious how games like Russian Railroads handle exactly this, where clearly things are done on the front end - no notifications until the turn is confirmed. If it needs code/logic to be duplicated between backend and frontend as you say then I'm definitely less keen, but hoped there would be a "smarter" way to handle it!

But the major reason I didn't want to do it all in the backend is exactly the one "Backend con" you raised:

- you need to code the undo feature : you can either use the one from the framework that works if no-one else do an action during a turn, or if no random event is triggered

My problem that I didn't know how to handle this, and didn't even really think it was possible without a lot of tedious code (as you'd have to rewind database updates somehow). Is the "one from the framework" documented somewhere, because I must have missed it? Thanks again!
User avatar
fafa-fr
Posts: 383
Joined: 22 December 2013, 21:58

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

Post by fafa-fr »

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.
User avatar
Tisaac
Posts: 2743
Joined: 26 August 2014, 21:28

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

Post by Tisaac »

robinzig wrote: 06 May 2021, 12:45 Thank you for the reply - I agree with a lot of your points, particularly that there's not a huge downside to other players seeing actions "live". Although I'm still curious how games like Russian Railroads handle exactly this, where clearly things are done on the front end - no notifications until the turn is confirmed. If it needs code/logic to be duplicated between backend and frontend as you say then I'm definitely less keen, but hoped there would be a "smarter" way to handle it!

But the major reason I didn't want to do it all in the backend is exactly the one "Backend con" you raised:

- you need to code the undo feature : you can either use the one from the framework that works if no-one else do an action during a turn, or if no random event is triggered

My problem that I didn't know how to handle this, and didn't even really think it was possible without a lot of tedious code (as you'd have to rewind database updates somehow). Is the "one from the framework" documented somewhere, because I must have missed it? Thanks again!
That's right here :
https://en.doc.boardgamearena.com/Main_ ... e.game.php
"Undo moves"

And doing one yourself is really not that hard, just create a Log module that will keep track of enough info to revert actions, for instance "a card was moved from here to there". I can provide you examples of that if you need it. IMO that's way easier to code than handle a complex flow in front end and the interface between front and back.

As for seeing actions, that's again more a upside to see actions live in most cases than a downside. That does not means that every click must call an action and notify everyone, I also use some small client state flows when it's coherent to use it, but still basic case is "you do someting => you store it, notify about it and change state".
User avatar
robinzig
Posts: 461
Joined: 11 February 2021, 18:23

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

Post by robinzig »

Thank you! I've read through that page quite a few times so I'm not sure how I never managed to notice that whole section :oops:

I'd still be interested to hear from others about "the other way". I totally appreciate what you say about "IMO that's way easier to code than handle a complex flow in front end and the interface between front and back." - that's why I was wondering if anything existed in the framework to handle that flow, since I've seen it (or what seems like it) in several games that are live on BGA. But I guess I can go with your suggestion of sending everything to the server, and adding the undo functionality you linked to, for my first implementation if that's so much easier :)
User avatar
Tisaac
Posts: 2743
Joined: 26 August 2014, 21:28

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

Post by Tisaac »

robinzig wrote: 06 May 2021, 13:56 Thank you! I've read through that page quite a few times so I'm not sure how I never managed to notice that whole section :oops:

I'd still be interested to hear from others about "the other way". I totally appreciate what you say about "IMO that's way easier to code than handle a complex flow in front end and the interface between front and back." - that's why I was wondering if anything existed in the framework to handle that flow, since I've seen it (or what seems like it) in several games that are live on BGA. But I guess I can go with your suggestion of sending everything to the server, and adding the undo functionality you linked to, for my first implementation if that's so much easier :)
I don't think there is anything in the framework to handle this in client side.
If I were to do this, I would "simply" store all actions into a queue and send that as JSON object (JSON.stringify on front end, and 'self::getArg('actionArgs', AT_json, true)' on the action side), and then resolve them in order.
You would still need a way to clear your UI of the last choices made, maybe using this.gamedatas as a reference if you are not modifying them during your client state flow.
User avatar
Lunalol
Posts: 584
Joined: 09 October 2016, 23:21

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

Post by Lunalol »

In USE (Unconditional Surrender! World War 2 in Europe), I use framework undo system (so on server side) and tune it to have multi-depth undo.
So you can go back one action at once or with an undo all go back to last not 'undoable' action.
I use a system based on a stack. This feature is still being tested (on alpha and selected table on beta).

It was near impossible to do that on client side for this game.
User avatar
BaronFraser
Posts: 39
Joined: 10 June 2020, 10:27

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

Post by BaronFraser »

+1 for server-side

The "how" depends on your game, but you just need to model the actions so that you can either reverse the steps or revert to a snapshot with each step.

In Automobiles, actions are 100% about cube movements, so I have a table that keeps a log of every cube that is moved during a player's turn and which action that movement belongs to. When a player undoes a move, I just reverse the cube movements until the that move has been undone - other games will vary.
User avatar
Tisaac
Posts: 2743
Joined: 26 August 2014, 21:28

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

Post by Tisaac »

BaronFraser wrote: 06 May 2021, 15:22 +1 for server-side

The "how" depends on your game, but you just need to model the actions so that you can either reverse the steps or revert to a snapshot with each step.

In Automobiles, actions are 100% about cube movements, so I have a table that keeps a log of every cube that is moved during a player's turn and which action that movement belongs to. When a player undoes a move, I just reverse the cube movements until the that move has been undone - other games will vary.
+1 for that way of logging, that's the easiest way to implement the undo afterwise IMO
Post Reply

Return to “Developers”