Keeping an Async game going reliably

onealexleft
edited July 2016 in DotNet
Hi!

It looks like I've got an issue regarding asynchronous support for Photon. Without custom server-side code it seems that keeping an asynchronous game going reliably after player disconnects is not very likely. I'm ready to accept that for this project, but figure I'd ask in case I'm missing something:

In a turn-based game scenario if the current player disconnects mid-turn (permanently, either explicitly or via timeout) and was the only active player in the server, I don't see a reliable way to take a few values from their CustomProperties and move it to another player who is still in the game but may be inactive and update the RoomProperties to reflect the change so others see the change reliably in their clients without joining the server. This leaves the game in a state where the current avatar is orphaned (no controlling player) and none of the inactives could be notified, since all CustomProperty manipulation originates from clients.

One potential approach I've considered is flagging games on the Leave Game Hook where the player is removed permanently, and trying to notify the lowest ActorNumber to hopefully bring in the masterclient into a server and attempt to reconcile the state, but that seems potentially clunky?


Comments

  • JohnTube
    JohnTube ✭✭✭✭✭
    edited July 2016
    Hi @onealexleft,

    What you're asking is interesting.

    You are pointing to the fact that Photon webhooks do not provide a way to modify room state in any way and in particular when last active player is removed from actor list.

    We are thinking of adding a way to do this in the future, events can be sent and properties can be changed based on return object of a webhook. But this is not for tomorrow.

    I can't understand 100% the workaround you're suggesting. If it's the last actor leaving how do you plan to "notify lowest ActorNumber"? how do you plan to change master client? and what do you mean by "reconcile the state"?

    The master client switch could be a Photon issue not directly related to webhooks. If a master client goes through a client timeout disconnect this is an issue that should be handled separately using a polling ping for instance or by reducing client timeout value.

    I want to understand exactly what you want to achieve as we may have 3 solutions we may offer here.
    Do you confirm the following:
    You want to move some or all custom actor properties of last active actor permanently leaving the room to another inactive actor still in the room and notify all inactive actors (broadcast this by adding a custom room property or even a cached event so that other actors get notified as soon as they rejoin). Is that it?

    What web server do you use? what technology/programming language?

  • onealexleft
    edited July 2016
    Hi @JohnTube,
    JohnTube said:




    You want to move some or all custom actor properties of last active actor permanently leaving the room to another inactive actor still in the room and notify all inactive actors (broadcast this by adding a custom room property or even a cached event so that other actors get notified as soon as they rejoin). Is that it?

    Yes, there's a hashtable in the leaving actor that I'd like to move/merge with a remaining actor as well as update some custom properties in the room (I have some properties there denoting who's turn it is, etc). As for boardcasting the change, that seems outside the scope of Photon for players who aren't in the game actively. Ideally it'd be a webhook so I could do my own broadcasting (either via push notifications, or emails, etc).

    Just to clarify the situation to help explain it better:
    - Our game has 4 avatars.
    - The game supports 1-4 players
    - players can control 1-n avatars, such that each avatar has exactly 1 player controlling them
    - each avatar takes a turn in succession (turn based)
    - for example, a 2 player game, each player controls 2 avatars, in a 3 player game 1 player controls 2 avatars and the rest control only 1, etc.

    In the real-time version of our game, if a player permanently drops then the masterclient re-assigns the orphaned avatar to another player still in the game. This is all managed via CustomProperties on Player objects in Photon. So a small hashtable for each player denoting which avatars they control is saved to their customProperties. On leaving, those tables are updated on a remaining player via the masterclient.

    In the asynchronous version, I could do the same scenario above, but in the case where there are no longer any active players, the game is left potentially in a state where it is an avatar's turn, but no one has been re-assigned to that avatar. Therefore, the game sits indefinitely with no one really knowing or being notified it is their turn.


    My ideas for workarounds have been to try determine if a player is the first and only active player on join and do the re-assignment at that point via that client. That idea seems easier said than done, unless changes to player customProperties are atomic or can't get into a conflicting state if 2 players that join at the same time determine they are "first" from their perspective. If Photon guarantees that PlayerCount and Inactive states are propagated in such a way that each client could determine reliably who connected first then this approach could work?

    My alternative approach was to mark a game as "needing attention" when a permanent leave is detected via webhooks. This would be mostly a custom solution outside of photon. Via webhooks, actorNums are typically sent with most web hook calls. So I could query to find the lowest actorNum that is left in a game. Then during my 'GetGameList' webrpc call, tag a game for the currently lowest actorNum (the masterclient according to the docs) to have them reconnect and go through the 're-assignment' procedure as described in the real-time portion above.

    The technology I'm using is python+Django for storing asynchronous games. The clients are Unity, using the turnbased SDK via C#. And yes, you are correct that this all kind of points to the limitation of not being able to modify game state via web hooks, which would be the cleanest way to handle these scenarios IMO.


  • JohnTube
    JohnTube ✭✭✭✭✭
    edited July 2016
    unless changes to player customProperties are atomic or can't get into a conflicting state if 2 players that join at the same time determine they are "first" from their perspective.

    You can use Check-and-Swap feature.

    From my personal experience, as a game developer using Photon, after discovering the webhooks limitations I used this rule of thumb:
    if a game data needs to be accessed when not joined to that room:
    - read only: you can save that data as lobby properties. otherwise, it needs to be saved outside the room state.
    - write: it needs to be saved outside the room state.

    I'd go with your second approach: handling this "outside of Photon". Flag the game from web server side in GameLeave, IsInactive=false, poll game data from all users using HTTP, first player to rejoin makes the necessary changes asap and removes the flag. You can even cache this event. Also, no need to explicitly join just to execute the avatar switch logic.

    Other solutions that involves change of state from webhooks are being discussed internally and will be available in the next webhooks version. We asked about what web server you were using because there was a workaround that we think works better/only with C#. If you want to join the discussion and make suggestions, please send me a message.
  • Thanks for the help and clarification!