Object state synchronisation
The whole answer can be found below.
Try Our
Documentation
Please check if you can find an answer in our extensive documentation on PUN.
Join Us
on Discord
Meet and talk to our staff and the entire Photon-Community via Discord.
Read More on
Stack Overflow
Find more information on Stack Overflow (for Circle members only).
Object state synchronisation
XRay
2016-11-02 13:31:40
Hi, I just started working with PUN and I'm facing a problem right now that I'm not sure how to solve.
So, I have a lobby scene where players have to step on an object in order to flag it as ready. When all objects are ready, we start the game. The thing is, I don't know how to procede to flag that object as ready for every clients.
I first thought about giving those objects a photonView in order to call RPCs. But those RPCs would need to be buffered and you can step off that object to make it unready again. That would mean a lot a buffered RPCs if players decide to "play" with that.
Then I read about the custom properties and thought about saving every plateform's states in the room properties. But I read that those properties are update every 5 seconds, so if a player joins the lobby after someone has stepped on a plateform, he would have to wait 5 seconds before seeing it as "ready". Plus the fact that he could interact with it within those 5 seconds.
So I'm kinda lost right now, If anyone could explain to me how to deal with those kind of synchronisation (because I feel like it will happen a lot), It would help a lot.
Comments
[Deleted User]
2016-11-03 12:11:18
Hi XRay,
you can use OnPhotonSerializeView(...) for this. A comparable example is in the PUN Basics Tutorial. Make sure, that you only write something to the stream, if the synchronized value is changed in order to avoid message flooding.
For example you can add a trigger to the platform and using OnTriggerEnter(...)
and OnTriggerExit(...)
callbacks from Unity to notify the script to send a new state across the network. You can do this by adding a boolean variable e.g. which allows the stream to send data.
Thanks, and about writing only if the value has changed, is something like that correct ?
if (stream.isWriting)
{
if(state1 != newState1)
stream.SendNext(newState1);
if(state2 != newState2)
stream.SendNext(newState2);
}else{
this.state1 = (bool)stream.ReceiveNext();
this.state2 = (bool)stream.ReceiveNext();
}
It's the part in the else{} that bugs me. We can't check if (state1 != newState1) because the state only change in the owning client but by writing like I did, it expects to receive 2 bool from the stream, I guess it won't work if only one or none are sent.
One more thing, If I send data only when it's changed. Let's say, that client A is on the plateform, so it's flagged as "Ready". Now a new client B connects, but cannot see the plateform as "Ready" because client A hasn't changed the plateform state thus no data has been writen on the stream. How can I force sync the state when a new client connects ?
EDIT:
May I also ask something else, I was wondering if the name given to PunRpc functions, must be something unique. I've seen the Rpc List in the server settings and I don't know if there could be a problem if let's say Player script and Car script have both [PunRpc] void Move();
TreeFortress
2016-11-04 01:26:13
I think the way you wanna do it, is if any of your states change, then send them all over. Or, you always have your first value be an byte, indicating the type of payload to come.
In terms of new players joining, just listen for that event, and force each switch to write its values one more time when it detects a new player.
if(s1Changed || s2Changed || newPlayer){
newPlayer = false;
//write states....
}
Or... just keep it simple, and serialize @ 1fps, whether they changed or not. That's not very much traffic in the scheme of things, especially if it's just a single Bool on 4 switches, and all clients will have the same state within 1 second of it changing.
[Deleted User]
2016-11-07 10:08:13
You can use something like
if (stream.isWriting && someCondition)
{
// Do stuff
return;
}
if (stream.isReading)
{
// Do stuff
}
Another possibility you have is to use the CustomRoomProperties. Therefore the MasterClient needs to setup a hashtable containing all triggers, e.g. Hashtable props = new Hashtable() { { TriggerId_1, false }, { TriggerId_2, false } };
. When someone enters a trigger (OnTriggerEnter is called by Unity) or exits the trigger (OnTriggerExit), the client needs to update the room properties by calling PhotonNetwork.room.SetCustomProperties(updatedProps);
. In the OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged)
callback you only receive which trigger changed so you can search them by ID and change their state as stated in the changed properties.
Aren't the customRoomProperties slow to update ? I mean, I read that it's updated for every clients within 5 seconds after a change. I actually use them to sync global game's properties before starting the game but I'm sure I can use them for something like updating an object state, especially because of that long delay.
[Deleted User]
2016-11-07 13:02:55
No, there isn't such a high delay (except from bad ping) when updating the room properties, so I think you can safely use them for your scenario.
Back to top