Game Center GKMatch GKSendDataReliable packet lost
Asked Answered
D

2

11

I have been using GKMatch for quite a while successfully in an app. I have been chasing down and issue with the game occasionally stopping and have tracked it down to packets being sent but not received. This happens only occasionally but I can't seem to track down why it happens.

All messages are sent using GKSendDataReliable.

Logging has shown that the packet is being sent from one device successfully, but it is never received at the target device.

//Code sample of sending method....
//self.model.match is a GKMatch instance    
-(BOOL) sendDataToAllPlayers:(NSData *)data error:(NSError **)error {
        [self.model.debugger addToLog:@"GKManager - sending data"];
        return [self.model.match sendDataToAllPlayers:data withDataMode:GKSendDataReliable error:error];
    }

...

//Code sample of receiving method....
// The match received data sent from the player.
-(void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
    [self.model.debugger addToLog:@"GKManager - received data"];
    [super didReceiveData:data fromPlayer:playerID];
}

What I see happen is that periodically (maybe 1 in 100 messages) is sent without error from the 'sendDataToAllPlayers' method, but the receiving device never hits the 'didReceiveData' method. My understanding is that using GKSendDataReliable should send messages and then won't send another until it receives an acknowledgement. Messages aren't received but new messages are sent from the same device.

The sending method returns 'YES' and error is nil, but the didReceiveData is never hit...!

Has anyone ever seen this? Does anyone have any ideas what this could be? I don't know what else I could do to debug this.

Distinction answered 7/6, 2013 at 15:35 Comment(7)
My users also complain that some data may be accidentally lost during the game. But I am still unable to reproduce this bug myself. Do you have an example project where this bug is consistently reproducible? If yes, could you please share it (may be on github)? Thanks.Pruett
My project is very large (active app in the store currently) but I will try and put together a smaller version of it to see if it is consistently reproducible.Distinction
I'm having the same problem, especially when internet connectivity on one of the devices is weak. Is it true that GKSendDataReliable stops sending messages until it receives an acknowledgment?Monachism
Have you filed a bug report for this? This seems like fundamentally broken functionality that should be affecting any developers using realtime matches.Cayuse
I've confirmed this too. Really very surprising from Apple (not to mention disappointing). The whole point of the reliable mode is that the connection should buffer and delay until it can send, not just drop messages.Create
If there is a bug report I would like to dupe it, do you have a number? I find this bug outrageous actually. Building a transport layer in the app on top of the Game Kit which is already sitting on top of reliable transport layer, is frankly embarrassing for them. Someone somewhere should be slapped around the face several times.Create
I've been having this problem since day 1 of Game Center. Wrote up several bugs to Apple about it, but 4 years later nothing has been done to address it.Totalizator
P
8

I confirm the bug. I made an example project consistently reproducing the issue: https://github.com/rabovik/GKMatchPacketLostExample. I tested it on a weak internet connection (iPad 3 with Wi-Fi and iPhone 4S with EDGE; both on iOS 6.1.3), and some packets regularly get lost without any error from Game Center API. Moreover sometimes device stops receiving any data, while another still sends and receives messages successfully.

So if we are sure the bug exists, the only possible workaround is to add an extra transport layer for truly reliable delivery.

I wrote a simple lib for this purpose: https://github.com/rabovik/RoUTP. It saves all sent messages until acknowledgement for each received, resends lost and buffers received messages in case of broken sequence. In my tests combination "RoUTP + GKMatchSendDataUnreliable" works even beter than "RoUTP + GKMatchSendDataReliable" (and of course better than pure GKMatchSendDataReliable which is not really reliable).

Pruett answered 6/7, 2013 at 13:13 Comment(1)
RoUTP seems to be broken now with iOS 9. If I sent data using it not all devices will receive the data. Doesn't matter if I use reliable or unreliable transport. If I disable RoUTP everything works fine.Codding
C
1

[Edit: RoUTP no longer seems to work properly in iOS9]

I did some testing yesterday at the edge of my wifi's range where packet loss was occuring. What happens is that when packets are lost using GKMatchSendDataReliable the player is abruptly disconnected from the GKMatch session. match:player:didChangeState is called with GKPlayerStateDisconnected and the player's ID is removed from the playerIDs dictionary. This happens with only slight packet loss. I can still browse the internet from this connection for instance.

Now, if I switch to sending packets unreliably, then match:player:didChangeState never fires and the match keeps going without a problem (except losing the occasional packet which might be important). It will only disconnect if the packet loss becomes substantial. Now this is where Yan's RoUTP library is handy, since we can keep track of and retry these important messages without having our players disconnected when they encounter slight packet loss.

Also, data sending using GKMatchSendDataReliable will only return YES if the message has been successfully queued for delivery. It does not tell you whether or not the message was successfully delivered. How could it? It returns right away.

Codding answered 10/11, 2014 at 15:16 Comment(5)
Hey i've been working on a pretty complex rts game and i've noticed exactly the problem you are describing. Do you recommend I try RoUTP library?Aladdin
It definately works, but it's very basic. For instance all packets have to be sent through RoUTP once you start using it. And it will keep trying to deliver packets forever. This can cause a burst of delayed packets to come through all at once. I may consider going full client server instead of peer to peer and ditching RoUTP. If clients have packet loss and get disconnected then that may just be a desired consequence to keep the game normal for the other clients, rather than having a player popping around the scene killing other players before anybody can react because of packets surging in.Codding
It also doesn't say who send what packet as that info is dropped. So you have to encode the playerID into the message using a char array. All players receive all messages, so if you go client server then it's not ideal. That is, you can't send messages to specific players. Only to all players and then have players ignore messages not intended for them.Codding
Hey thanks for responding. So I was originally sending packets reliable but due to the way Game Center handles disconnects with reliable packets, I needed to try something else because even the smallest timeout would disconnect a user. So what I ended up doing was writing my own layer over the send message unreliable and managing the reliable queue myself. This allows me to prioritize certain messages over others and manually drop packets if they are no longer needed (I.e. If it took too long). I have had success so far with this approach. And no disconnects are occurring.Aladdin
For years I have been experiencing both the loss of "reliable" packets, and the spontaneous -didChangeState disconnections. I never thought that reliable packet loss would trigger a disconnect, so I did a quick test by changing all of my data to unreliable. No change. I still get the -didChangeState disconnections on a 3 or 4 player game. Doesn't seem to happen in 2 player games, however.Totalizator

© 2022 - 2024 — McMap. All rights reserved.