Making sure PhotonNetwork.RaiseEvent reaches temporarily disconnected players
Options
Hi!
I'm using
Some of the receiving players are temporarily disconnected at the time of my broadcasts (let's say due to a bad internet connection). I need to make sure that after those clients reconnect, they will receive all the events that were broadcasted while those clients were in disconnected state.
Is this possible to implement with Photon?
I don't know where to start from. I don't really understand how RaiseEvent works under the hood and what happens when I reliably RaiseEvent while some players are disconnected. How can I find out who was disconnected at the time and also which events he missed?
Thank you!
I'm using
PhotonNetwork.RaiseEvent
to broadcast events to all players passing sendReliable = true
as a parameter.Some of the receiving players are temporarily disconnected at the time of my broadcasts (let's say due to a bad internet connection). I need to make sure that after those clients reconnect, they will receive all the events that were broadcasted while those clients were in disconnected state.
Is this possible to implement with Photon?
I don't know where to start from. I don't really understand how RaiseEvent works under the hood and what happens when I reliably RaiseEvent while some players are disconnected. How can I find out who was disconnected at the time and also which events he missed?
Thank you!
0
Best Answers
-
Hi @1_Mad_Developer,
You're welcome and don't worry.But there is a problem. Now when a player disconnects and then reconnects during the game, he receives all the events from the beginning of the match, including the events that he already received before.
This should not be a problem and the behavior is expected and by design.
What you should do, since you have 2 players only:
if an event is received successfully by the other player delete it from cache so it won't be sent again as it is already "processed and consumed". It is the best option as other ways to avoid receiving duplicate or old events may be too complex for your game.
In any case, receiving an event more than once is better than not receiving it at all! So you can just ignore those events by checking actor number.
Regarding the heart beat coroutine to check internet connection, let's discuss that on the other forum thread.
1 -
Hey @1_Mad_Developer,
I think you just need to fix the data filter by changing:broadcastData.Add("eid", new Hashtable() { { "eid", 999 } }); // mark my cached event with 999
tobroadcastData.Add("eid", 999); // mark my cached event with 999
2 -
Hi @1_Mad_Developer,
I see the issue, theOnPlayerDisconnected
callback is not being triggered when a player leaves temporarily.
Until we release a fix in an upcoming version which could take a while, here is how to fix this manually by changing the code yourself:
In "NetworkingPeer.cs" insideHandleEventLeave
please replace:if (player.isInactive && !_isAlreadyInactive) { return; }
withif (player.isInactive && !_isAlreadyInactive) { SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerDisconnected, player); return; }
In theOnPlayerDisconnected(PhotonPlayer player)
you can check if the player is coming back usingplayer.isInactive
.2
Answers
-
1
-
Thanks @JohnTube and sorry for the late responce!
As you suggested I've enabled event caching for my room. But there is a problem. Now when a player disconnects and then reconnects during the game, he receives all the events from the beginning of the match, including the events that he already received before. I only want to process the new events (those that we raised while the player was disconnected). Can this be done with Photon?
Also I'm not sure if it's relevant but I'm doing something unusual when a player disconnects. Maybe it influences room cache somehow. I have a corutine that in short intervals checks if internet can be reached. And as soon as internet is unavailable I callPhotonNetwork.Disconnect()
. This way I don't need to wait fordisconnectTimeout
and it allows me to immediately callPhotonNetwork.ReconnectAndRejoin()
as soon as the internet becomes available again.
For your reference, here is how I'm creating a new room:RoomOptions roomOptions = new RoomOptions(); roomOptions.IsOpen = true; roomOptions.IsVisible = true; roomOptions.MaxPlayers = 2; roomOptions.CleanupCacheOnLeave = false; roomOptions.EmptyRoomTtl = 120000; roomOptions.PlayerTtl = 120000; PhotonNetwork.CreateRoom(null, roomOptions, TypedLobby.Default);
I look forward for hearing your answer!
Thank you very much!0 -
Hi @1_Mad_Developer,
You're welcome and don't worry.But there is a problem. Now when a player disconnects and then reconnects during the game, he receives all the events from the beginning of the match, including the events that he already received before.
This should not be a problem and the behavior is expected and by design.
What you should do, since you have 2 players only:
if an event is received successfully by the other player delete it from cache so it won't be sent again as it is already "processed and consumed". It is the best option as other ways to avoid receiving duplicate or old events may be too complex for your game.
In any case, receiving an event more than once is better than not receiving it at all! So you can just ignore those events by checking actor number.
Regarding the heart beat coroutine to check internet connection, let's discuss that on the other forum thread.
1 -
Thanks for the advice @JohnTube !
I'm having troubles deleting the cached events though. I'm not sure how to do it correctly and the documentation doesn't give any code examples.
Right now my process of caching and deletion of events is as follows:
1) Our player raises some event:RaiseEventOptions eventOptions = RaiseEventOptions.Default; eventOptions.CachingOption = EventCaching.AddToRoomCache; Hashtable broadcastData = new Hashtable(); broadcastData.Add(0, "actual event content for my game"); broadcastData.Add("eid", new Hashtable() { { "eid", 999 } }); // mark my cached event with 999 PhotonNetwork.RaiseEvent(myEventCode, broadcastData, true, eventOptions);
2) When enemy player receives the event, he raises another event which whole purpose is to delete the first event from room's cache:PhotonNetwork.RaiseEvent(myEventCode, new Hashtable() { { "eid", 999 } }, true, new RaiseEventOptions { CachingOption = EventCaching.RemoveFromRoomCache });
And then the first event is still in room's cache and I still receive them all a second time after a reconnect. I've triedCachingOption = EventCaching.AddToRoomCacheGlobal
but the result is the same.In any case, receiving an event more than once is better than not receiving it at all! So you can just ignore those events by checking actor number.
Could you please explain how do I do that? I'm still new to Photon and this stuff is a little complicated for me.
Also thank you for all your help so far! At least I'm digging in the right direction now.0 -
Hey @1_Mad_Developer,
I think you just need to fix the data filter by changing:broadcastData.Add("eid", new Hashtable() { { "eid", 999 } }); // mark my cached event with 999
tobroadcastData.Add("eid", 999); // mark my cached event with 999
2 -
Omg, you are ofcourse right!
Such a stupid mistake from my side. Why would I put a Hashtable inside another Hashtable? I guess I just worked too much yesterday.
Anyway now everything works fine and I finally can proceed with developing my game!
Thank you very much for your help @JohnTube !0 -
Hi @JohnTube ,
I'm having one more issue regarding player disconnects. As you suggested I'm using cached events to make sure that raised events can reach temporarily disconnected players.
I had to setroomOptions.PlayerTtl = 120 000
to make sure that disconnected players can rejoin within 2 mins. This leads to another problem. When 1st player is in game and 2nd player disconnects, the 1st player only receives OnPhotonPlayerDisconnected after 2 mins (after PlayerTtl timeout). I need to immediately know when the 2nd player disconnects and for this I had to setroomOptions.PlayerTtl = 1000
but now the players can't reconnect to the abandoned room at all. I guess this is because the room is not storing the actorID anymore.
I did setroomOptions.EmptyRoomTtl = 120 000
but it doesn't solve the issue.
Could please point me to the right direction here? How can I resolve this?
Thank you!0 -
Hi @1_Mad_Developer,
I see the issue, theOnPlayerDisconnected
callback is not being triggered when a player leaves temporarily.
Until we release a fix in an upcoming version which could take a while, here is how to fix this manually by changing the code yourself:
In "NetworkingPeer.cs" insideHandleEventLeave
please replace:if (player.isInactive && !_isAlreadyInactive) { return; }
withif (player.isInactive && !_isAlreadyInactive) { SendMonoMessage(PhotonNetworkingMessage.OnPhotonPlayerDisconnected, player); return; }
In theOnPlayerDisconnected(PhotonPlayer player)
you can check if the player is coming back usingplayer.isInactive
.2 -
-1
-
Hi, i'm new user
sorry for my bad english, i've the same problem the difference is that mu game is a card game with 5 players, when a player disconnect and rejoin room events from the beginning of the match, including the events that he already received before. I only want to process the new events (those that we raised while the player was disconnected). How i do ?0 -
Hi @Mario1972,
Thank you for choosing Photon!
Well, you need to keep track of what events are received by client manually:
1- locally cache "the progress" of the player on the client. when events arrive process only new ones.
2- when a cached event is no longer needed delete it from cache.0 -
Thank you.
There is a index in photon or i must create my own index for discard event received.0 -
It depends on your game so yes you must create your own "index".
You may have something like an event "counter" per game or per player.
Ideally, you should remove events from the cache when you no longer need them.0 -
Hi, i've new problem,
when player raisevent when lose connection temporarily, other player don't receve event.
How to test if player is connect before send event?0 -
Hi my question is when player raise event ad he is disconect, how check befor post pessage0
-
Hi @Mario1972,
I already posted here the approach I suggest if you want to make sure an event is successfully transmitted to its destination(s).
Some ideas:
Broadcast (because RaiseEvent does not have Operation Response by default).
Add "event round-trip" timeout.
ACK event reception also using events.
Cache event locally on the client before sending.
Add an event ACK timeout.
Retry in case of failure or timeout or disconnect, etc.
Add max. retry count.
Sender adds events to room cache first when raised.
Sender deletes events from room cache when ACKed.1 -
Hi, i wont clear all cache event, how i do?0
-
Hi @Mario1972,
Next time, start a new forum question as this one is not related to the original post.
I'll answer here this time:
There is this method:PhotonNetwork.networkingPeer.OpRemoveCompleteCache();
If it does not work well for you (didn't test it myself), you can try the following:public void CleanUpEventsCache() { Dictionary<byte, object> parameters = new Dictionary<byte, object>(); parameters.Add(ParameterCode.Cache, EventCaching.RemoveFromRoomCache); PhotonNetwork.networkingPeer.OpCustom(OperationCode.RaiseEvent, parameters, true); }
0