Synchronization

Hello all
I have somewhat difficult question for you :)
I have two players in a same room.
They are both trying to execute some form of combo button press (lets say players can do this in about a second)
I have to inform both players of who finished (sent an event) this first.

If player one sends this event and by the time it reaches player two, player two still haven't send his own finish event, then it is clear that player one wins.
But..if player two have just sent his own finish event and then receive finish event from player one how do I know with one finished first?

Local clocks are not synchronized. I don't know the lag for neither players. Is there a way to do this right?

Answers

  • Okay so many ways you can go about doing this.

    Lets take your case here:
    -1 master client
    -2 players in the room
    -We need to detect when each user sends an input
    -Once inputs are received, produce a win result for the first input received
    -Reset for a new use case

    With that rule set in line, we can move on to logic.

    We want to have 1 object in the scene to receive the player inputs and register the feedback back to the players. We will name this "GameController" and will give it a PhotonView component and have it observe itself. We will add a string to the script called "firstPlayer" and this will be our indicator for who acted first. We will also add a "bool" called "allowInput" and this will be our flag to stop inputs being sent in.

    Inside of GameController script we will add a PunRPC method called "ReceiveInput" with a parameter type of "string" named "actorId", this will set the firstPlayer var.

    From here, on each client you will look in the Update method for input, on input true we will get the GameController, get its photonView and send it an RPC with our local PhotonPlayer id.

    Inside of the Receive input RPC we will first create an if statement that checks for allowInput false and return out of that, then set allowInput to false and firstPlayer to the actorId parameter.

    From here we can now see that the first player that sends an input gets logged to the firstPlayer var and inputs are paused, preventing the secondary player from bugging out the system with a late call, etc case.

    Finally, we can create another RPC if needed to then reset the firstPlayer string to null and the allowInput bool to true and fire this method from the GameController itself when youre ready to move to the next round or case.

    Hopefully this helps, again this is just 1 way of going about this, i can think of 4 different ways off the top my head for photon, it really just depends on how you want to go about doing it and what is the most efficient for you, youre game and the rooms data IO.
  • JohnTubeJohnTube mod
    edited October 14
    Hi @GLucas,

    Thank you for your contribution on the forum, much appreciated.

    I won't discuss your suggested approach in general or in details, however, I have one question:
    with a parameter type of "string" named "actorId"
    why "string"? PUN registers the Player class as custom type and you can send it in as RPC parameter and under the hood, only the ActorNumber which is an integer is exchanged. I think it's more efficient and intuitive to use ActorNumber and integer instead of string and UserId.
  • @JohnTube Ah, yes i agree i just tested and that would work out easier and would be more legible as far as a cohesive workflow goes.
  • @denmla1000,

    Since this is very time sensitive you could send the network timestamp (PhotonNetwork.Time) from each player and then compare.
    The thing is who should decide.
    The best case is to have an authoritative server logic.
    Otherwise, you could go for the lightweight pseudo authoritative master client.
    In any case, always send via server.
    Meaning even if the master client sends to himself, forward to the server first to give some time for the other player's event to arrive then compare.
  • Thank you @GLucas for the answer and @JohnTube for followup.
    So far I used only RaiseEvent in my code. I red that in low level Photon do only this call, but I maybe I am wrong. I tough to make this sync with this calls but I guess the PhotonView + RPC is already setup system for this sync lock-unlock logic.
    My only concern is that the latency will be big. I tested master to other player:
    RaiseEvent -> OnEvetnt RaiseEvent -> OnEvent and it has 0.12 - 0.2 seconds latency.
    Is that normal/expected or it can be optimized somehow?
  • Hi @denmla1000,

    Yes, correct.
    All PUN features are using RaiseEvent under the hood.
    RaiseEvent can be used in this case.

    Is that normal/expected or it can be optimized somehow?
    If you need a faster decision, I would recommend going for custom server plugins which would allow deciding on the server which has 2 benefits: half the time + authoritative logic. The plugins require self-hosting or enterprise cloud.
  • Tnx. We are yet to come there :)
    For now MVP of the game is all we need, and later custom solutions will be a must.
    Tnx for the answers
Sign In or Register to comment.