Turn based card game, I can't get my multiplayer right, advices and insight needed

Options
Hello,

I've implemented multiplayer in my mobile card game using PUN. After many iterations I can't get it stable enough, everything I test pass but once in production many player will encounter issues that will block the game and ruin the experience.

I know it's a long call but I'm open to any advice that would help me to improve the situation and make the game stable.

I'll try to describe my current implementation in a simple way:
It is p2p, and turn based, meaning that will often wait for the action of a specific player to continue the workflow.

At the start of the game, the master client sync the card deck and a few specific game settings with all clients (who is dealing the cards, this kind of thing)

Now here is how the game will play:
  1. First player select a card to play
  2. The card is sent to every client (including him) via server
  3. Once received by client, the card is visually played
  4. Once the card is visually played the client notify every other client (including him) , via server, that they have properly received and played the card
  5. Once the master received all the notification that the card was played on every client, it proceed to the next player
I thought that having this king of double check would make the game more stable, now it is slowing everything as players have to wait for confirmation from all clients after every action, and stability is still not there.

Is this a good way to ensure data are still synced between clients, do you recommand any better way to do?

Now the most frequent issues rise when a player disconnect, I handle and have tested all the possible case I can imagine, but still it will continue to block the game from time to time with real players. At a point where I really doubt my implementation.

Is this kind of p2p multiplayer implementation that hard to do properly or am I missing the whole point?

Comments

  • Hi @XenoBits,

    I guess you are using RPCs to send this kind of data, don't you? If so I think you can skip the part where each client confirms that he has received the card because RPCs are being sent reliable to make sure they are delivered. Removing the confirmation part also reduces the amount of messages you send, which is good. This will also remove the slowdown you are currently experiencing.

    Maybe this also solves the problem with disconnecting players you have mentioned.
  • XenoBits
    Options
    Thanks for your answer! indeed I'm using RPCs, I've read that they were reliable but some weird issues made me doubt it.

    I think my main issue come from the fact that not all actions are processed immediately,they may will require some visual feedback (play a card animation for example) and things can start to get mixed up if an animation is not completed on one client while the other one already proceeded to the next step.

    Do you have a recommendation on how I could separate the visual part from logic and rpc?
    Should I implement some kind of RPC queuing?
  • I think my main issue come from the fact that not all actions are processed immediately [...]


    Is this part of the game or is this from the 'confirmation delay'? I'm asking because you told that you are using the *ViaServer option for each action a client can do. Have you already tried using an option that is not *ViaServer? For example if you use the option All, the local client will execute the RPC immediately after notifying other clients. This means that the sender's logic and view will be updated immediately so he won't have any delay. The view and logic for the other clients will be updated as soon as they receive the RPC, minimal delay unless the connection is very bad.

    Or does this mean a player can do multiple 'hidden' turns that get executed consecutively on remote clients after the local player has finished his turn? Still not sure, if I understood this correctly.
  • XenoBits
    Options
    It is not part of the game rules but it is needed to improve user experience
    1. A player tap a card to play it
    2. Card is sent to all via server
    3. Once client receive card it will animate it on screen to notify user that it is being played
    4. At the end of the animation the client notify everyone that animation is now completed and it can proceed to the next step
    The potential delay due to getting info back from server is not my current issue.
    Visual feedbacks and animations introduce delay locally and in the end the clients may not be in the same state and synchronized anymore due to this, some new informations could arrive from RPC while the client is not ready to receive it.

    Here is a timeline that maybe will make my issue more understandable.
    • T:0 - Master - User Select a card1
    • T:0 - Master - Card1 is sent to all via server
    • T:1 - Master - Received card1 from server and start card animation
    • T:2 - Client1 - Received card1 from server and start card animation
    • T:2 - Master - Animation completed
    • T:3 - Client1 - Animation Completed
    • T:4 - Client1 - User Select a card2
    • T:5 - Client2 - Received card1 from server and start card animation
    • T:5 - Master - Received card2 from server and start card animation
    • T:5 - Client1 - Received card2 from server and start card animation
    • T:5 - Client2 - Received card2 from server and start card animation but it is already animating the first card
    Note that all actions are "turn based", meaning there can't be multiple actions executed at the same time by different clients (except for chat but it is independant from the game logic)
    And all actions are processed in order (player 1 play a card, then player 2, then 3, then back to player 1 etc)

    If I'm taking all those precautions, like sending allviaserver, is that I'm afraid to receive RPC in the middle of an unpropriate state which will result in potential game breaking.
    And it does not seems realistic to try to figure out all potential case and states where RPC could be received.
    In my mind I must have miss something and there is some multiplayer specific rules or best practices to apply that I'm not aware of.

    As for delay, it is a mobile game, and wireless network connection being what it is in some locations, it may takes sometimes seconds to reach client. That's why I'm always trying to figure the worst case scenario.



  • So I'm seeing two possible solutions for now:

    1.

    At the end of the animation the client notify everyone that animation is now completed and it can proceed to the next step


    You can wait until the last client confirms, that the animation of the card has finished before proceeding to the next turn. This has at least one major disadvantage: If any client disconnects before confirmation, the game either gets stuck or - if you implement a workaround for this - clients might have long waiting times before they can do anything.

    2.

    T:5 - Client2 - Received card2 from server and start card animation but it is already animating the first card


    Whenever you have this situation you can abort or skip (based on the timing) the currently playing animation and start the next one. The disadvantage here seems to be a little minor but this would affect visual representation of the game.
  • XenoBits
    Options
    Thanks again for your input,

    my current implementation is the first one, and when a player is disconnected I ask the master to confirm on his behalf to all other clients.
    But indeed I end up having some special cases I cannot reproduce where the game will get stuck.

    I may try getting rid of the whole thing and switch to the second option, I'm just afraid to have some difficulty to handle all special cases where animations could be interrupted.