Search Unity

  1. Are you interested in providing feedback directly to Unity teams? Sign up to become a member of Unity Pulse, our new product feedback and research community.
    Dismiss Notice

Help Wanted Photon RPC Buffer Execution Delay

Discussion in 'Multiplayer' started by Wichael, Oct 13, 2020.

  1. Wichael

    Wichael

    Joined:
    Apr 7, 2018
    Posts:
    6
    Hi guys,

    So basically I'm working on a turn-based game that uses Photon RPC messages for all game functions.

    What I'm currently doing is when both clients connect they both open the scene with their own Game Managers. Basically nothing is network instantiated or synced.

    When Player A moves, the move is sent via RPC using RpcTarget.AllBufferedViaServer.

    So far everything works perfectly fine, but the reason I've used Buffer is because I want a player that reconnected to then receive ALL moves made again on reconnect so that his/her client ends up back where the game left off. It kind of works since some moves are executed when I connect back into the room but I believe that buffer sends them all as a bundle which could explain why although some moves are made, it's not doing it in the correct sequence. I thought ViaServer would send it in order but maybe it's just sending everything too fast...

    Question 1
    So my question is, would there be a way to see how many messages are in the queue by *disabling the RPC queue at the start and enabling it when everything is loaded, and then execute them one by one, disabling and re-enabling the queue in-between each call?

    So when Player B reconnects, x moves are waiting to be sent in the queue, move 1 is sent and the queue is disabled until that RPC has been sent through, then RPC number 2 executes and repeat until all are through.

    *PhotonNetwork.IsMessageQueueRunning = false;

    Question 2
    I've noticed that if a move is made and one client isn't responding - the RPC call doesn't get received. So far I haven't been able to test my "fix" for this as none of my clients have failed to respond yet... (Usually good but when I need it to freeze it won't. >.>)

    So what I've done is:
    a) Add PhotonNetwork.SendAllOutgoingCommands(); after every RPC call.
    b) Used OnApplicationPause to disable and re-enable the RPC queue so that RPC messages are queued while the client isn't responding.

    The question is, will OnApplicationPause execute before the application stops responding? Is there a better built-in method to use that will work better? I know it's a tricky one because if the application fails to respond then it's probably not going to be executing anything since it's an unplanned situation...

    Thank you in advance,
    Michael.
     
  2. Wichael

    Wichael

    Joined:
    Apr 7, 2018
    Posts:
    6
    Okay so I've come up with a better solution for question 1.

    Basically, Buffer doesn't send each RPC in order (at least it doesn't appear to). I debugged each RPC and on rejoin I found that only 3 RPC events were called even though 7 moves were made. Also, only one side's pieces moved.

    So instead I made a new class that stored each type of moves details. Every RPC move will add the details of the move to a list on all clients. So if any client disconnects, when they reconnect they do the following:

    1. Setup to the usual start game state.
    2. Ask the master if their list is > 0. If true the master will send an RPC directed only to .Other telling the other player which player they are, and who needs to move next.
    3. Master will foreach loop through each move in the list and send the appropriate RPC that was originally made to .Other instead of .All.
    4. If the last item in the loop is the last item in the list, Master will send .Other an RPC to let it know that it is now up to date.

    So far this works perfectly, and if any player disconnects and rejoins they will get an updated list of what happened from the current master.

    I decided what RPC to send based on an enum in the class. Example:

    Player Moves:

    Moves move = new Moves;
    move.MoveType = Moves.MoveType.Move;
    move.heroLocationX = heroX;
    move.heroLocationY = hero.Y;
    move.destinationX = destinationX;
    move.destonationY = destinationY;
    moves.Add(move);

    I add all the variables from any other types of moves into the class aswell, and in the foreach loop I check if the current looped item is of type Move or Kill.

    if Move, send an "Move" RPC.Other with the appropriate move specific variables.
    If Kill, send an "Kill" RPC.Other with the appropriate kill variables.

    Long story short, to resync a game using only RPC calls, just make a list of a custom class with the variables needed from each RPC call and send them in a loop back to the player when they rejoin.

    Still need to see if my solution for question 2 worked...
     
  3. seenuvasan0708

    seenuvasan0708

    Joined:
    Jun 18, 2019
    Posts:
    1
    what if both clients disconnect and joined back? Who is going to send the previous RPC list? How can they resume the game?
     
  4. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,674
    The RPC buffer is in the server and will be sent from there.
    If all clients drop out, the EmptyRoomTTL defines how long the room will stay available (even for rejoins).
     
unityunity