2 Replies
      Latest reply on Jun 6, 2019 4:17 PM by igorland
      igorland Level 1 Level 1 (0 points)

        Hello. I am using MultipeerConnectivity framework in my SpriteKit game.

         

        I have two scenarios when a peer leaves the game. First, when the peer leaves temporarily: connection is lost but all the nodes for this peer remain in the scene. And second: when the peer decides to leave for good. S/he selects an option "Exit the game" and sends the message to all other players saying that s/he is leaving. When the message is received by others, this peer's nodes should be removed from the scene.

         

        This code is for exiting the game:

         

        @objcfunc exitGame()
            {
                // Show an alert whether the player wants to exit the game
                let alert = UIAlertController(title: "", message: "Do you want to leave the game?", preferredStyle: UIAlertController.Style.alert)
             
                // If the player wants to leave the game
                let acceptAction: UIAlertAction = UIAlertAction(title: "Leave", style: UIAlertAction.Style.default)
                { _ in
                 
                    // Send a message to other players that you are exiting
                    // Create data to send: the current deck is sent to the peers
                    let messageToSend = self.makeMessageExit()  // A message is sent to inform others that I left
                    self.appDelegate.connectionManager.sendData(dictionaryWithData: messageToSend,
                                                                toPeer: self.appDelegate.connectionManager.session.connectedPeers)
                 
                    DispatchQueue.main.async
                        {
                            // Here goes the code to Remove the Menu with the Button Exit
                            if self.btnExitGame != nil && self.blurEffectView != nil && self.viewMenu != nil
                            {
                                self.btnExitGame.removeFromSuperview()
                                self.btnExitGame = nil
                             
                                self.blurEffectView.removeFromSuperview()
                                self.blurEffectView = nil
                             
                                self.viewMenu.removeFromSuperview()
                                self.viewMenu = nil
                            }
                         
                            // This closes the game scene
                            self.closeSceneToFindPlayers()
                         
                            // Deinitialize Connection Manager
                            self.appDelegate.connectionManager = nil
                    }
                }
             
                // If the player declines to leave the game
                let declineAction = UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel)
                { _ in
                    
                }
             
                alert.addAction(acceptAction)
                alert.addAction(declineAction)
             
                OperationQueue.main.addOperation
                { () -> Void in
                        self.view?.window?.rootViewController?.present(alert, animated: true, completion: nil)
                }
            }

        This code is for losing the peer:

         

        func lostPeer(peerID: MCPeerID)
            {
                print("I AM LOSING PEER.............")
        
                // If the peer temporarily left the game, change the status
                for (index, player) in self.appDelegate.players.enumerated()
                {
                    if player.peerID?.displayName == peerID.displayName //&& player.status == "in" TODO: THIS IS REMOVED NEEDED??
                    {
                        self.appDelegate.players[index].status = "out_temp"
                    }
                }
              
                // Display an alert message that the peer left
                let alert = UIAlertController(title: "Player Left",
                                              message: "\(peerID.displayName) left the game.",
                                              preferredStyle: UIAlertController.Style.alert)
              
                // Add an action (button)
                alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
              
                OperationQueue.main.addOperation
                { () -> Void in
                             self.view?.window?.rootViewController?.present(alert, animated: true, completion: nil)
                }
              
                // Then I mark the leaving peer's nodes indicating that s/he left, but the nodes are still in the scene....
                 drawFields()
            }

         

        Here is the method to deal with the peer when s/he left for good when I receive the exit message from him/her:

         

        func updateSceneExit(sender: MCPeerID?)
            {
                print("SCENE EXIT UPDATING............")
        
                // Remove peer from the list of players
                for player in appDelegate.players
                {
                    if player.peerID?.displayName == sender?.displayName
                    {
                        appDelegate.players = appDelegate.players.filter(){$0 != player}
                    }
                }
               
                // Redraw fields
                drawFields()
        
                print("SCENE EXIT UPDATED............",appDelegate.players)
            }

         

        Now. In 80%-90% of cases, everything works fine. However when I have more than 2 players connected, sometimes what happens is that the connection with the peer is lost BEFORE I receive his/her Exit message. This results in the situation when the peer said that s/he had left, but I still have his/her nodes in the scene. Meanwhile, another player would still receive the message in advance resulting in no error.

         

        Can someone please help me resolve the problem? Would be greatly appreciated!!!

        • Re: MPConnectivity: losing peer before receiving exit message
          igorland Level 1 Level 1 (0 points)

          OK. The best I could do it is to implement a protocol where a player wanting to exit sends a message to other peers; then the peers send the message back saying it is OK for the player to leave; once the OK message has been received from all connected peers, the Player disconnects.

          • Re: MPConnectivity: losing peer before receiving exit message
            igorland Level 1 Level 1 (0 points)

            Whereas the approach works with one or two peers connected, when I have three and more (up to 5), I constantly face the problem when the Player to whom other peers connected does not see that some other peers disconnected. I.e.:

             

            Peer A sends a message to other peers that he wants to leave the game;

            All peers send him a message back that it is OK for him to leave;

            Peer A gets OK messages from everyone, exits the game and disconnects;

            Peers B and C see that Peer A lost connection and update their scene. Peer D does not see that Peer A lost connection. It continues to treat as if Peer A is still in the game.

             

            Method in my connection manager:

             

            func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID)
                {
                    for (index, aPeer) in foundPeers.enumerated()
                    {
                        if aPeer.displayName == peerID.displayName
                        {
                            foundPeers.remove(at: index)
                            break
                        }
                    }
                   
                    delegate?.lostPeer(peerID: peerID)
            
                    print("LOST PEERS:>>>>>>>>>>",foundPeers)
                }

             

            Note that in my game, I do not allow connection of peers with the same name.

             

            Could someone please help?

             

            Thanks a lot!