Search Unity

Third Party [PUN2] Late joining players don't see any changes made in the scene

Discussion in 'Multiplayer' started by Rajkumar-Darbar, Nov 19, 2022.

  1. Rajkumar-Darbar

    Rajkumar-Darbar

    Joined:
    Mar 1, 2015
    Posts:
    8
    I am trying to build a simple FPS multiplayer game using Photon PUN 2. In my game, there are some targets, and players can raycast at them to change their color. I am using RPC with RpcTarget.AllBuffered. Everything gets synchronized well if players join in the room first and then start shooting at targets. Unfortunately, late joining players in the room don't see any changes made so far by other players.

    In my code, I used:
    PhotonNetwork.AutomaticallySyncScene = true;
    PhotonNetwork.LoadLevel(1);

    Any help to fix this issue would be much appreciated. Thanks in advanced.
     
  2. Strafe_m

    Strafe_m

    Joined:
    Oct 24, 2022
    Posts:
    72
    My guess would be that your only changing it for the current players in the room, so people who join late won't receive the RPC
     
  3. Rajkumar-Darbar

    Rajkumar-Darbar

    Joined:
    Mar 1, 2015
    Posts:
    8
    Yeah, you might be right. I was wondering how to send RPC for both current and late joining players? Any sample code ?
     
  4. Homicide

    Homicide

    Joined:
    Oct 11, 2012
    Posts:
    657
    RPC's that arent buffered for all will be lost. Thats all that is happening. You need to ensure they all recieve those packets if it matters.
     
  5. Rajkumar-Darbar

    Rajkumar-Darbar

    Joined:
    Mar 1, 2015
    Posts:
    8
    I am already using RpcTarget.AllBuffered. This is not working for the late joining players. What are other options to make buffered RPC?
     
  6. Strafe_m

    Strafe_m

    Joined:
    Oct 24, 2022
    Posts:
    72
    Maybe try AllBufferedViaServer, not really sure on this one
     
  7. Rajkumar-Darbar

    Rajkumar-Darbar

    Joined:
    Mar 1, 2015
    Posts:
    8
    I tested AllBufferedViaServer too. But not working in my case.
     
  8. Strafe_m

    Strafe_m

    Joined:
    Oct 24, 2022
    Posts:
    72
    Maybe for the players who join late, send the RPC to them when they join?
     
  9. Rajkumar-Darbar

    Rajkumar-Darbar

    Joined:
    Mar 1, 2015
    Posts:
    8
    That might be a way out. I will try to implement that and post update here. Thanks!!
     
  10. Rajkumar-Darbar

    Rajkumar-Darbar

    Joined:
    Mar 1, 2015
    Posts:
    8
    I have solved it using photon custom properties. When I am changing the color of a target using raycasting, I am storing its photonViewId and color value in a Hashtable. Late-joining players use this Hashtable in OnJoinedRoom() callback to synchronize all changes in that room.

    Here is my sample code:

    step 01: while creating a new room, initialize the room's custom properties
    Code (CSharp):
    1. private void CreateNewRoom()
    2. {
    3.     int randomRoomNumber = 100;
    4.     RoomOptions roomOptions =
    5.     new RoomOptions()
    6.     {
    7.         IsVisible = true,
    8.         IsOpen = true,
    9.         MaxPlayers = 5,
    10.     };
    11.  
    12.     Hashtable roomHT = new Hashtable();
    13.     string photonViewid = "0";
    14.     roomHT.Add(photonViewid, new Vector3(0, 0, 0)); // key should be a string
    15.     roomOptions.CustomRoomProperties = roomHT;
    16.  
    17.     PhotonNetwork.CreateRoom("RoomName_" + randomRoomNumber, roomOptions);
    18. }
    step02: store target's photonViewId and color value in the hashtable during rpc
    Code (CSharp):
    1. [PunRPC]
    2. void ShootRPC()
    3. {
    4.     particalSys.Play();
    5.     Ray ray = new Ray(gunTransform.position, gunTransform.forward);
    6.     LayerMask mask = LayerMask.GetMask("targets");
    7.  
    8.     if (Physics.Raycast(ray, out RaycastHit hit, 100f, mask))
    9.     {
    10.         raycastGO = hit.collider.gameObject;
    11.  
    12.         var enemyHealth = gameManager.GetComponent<ScoreBoard>();
    13.         var menuManager = gameManager.GetComponent<MenuManager>();
    14.  
    15.         if (enemyHealth && menuManager)
    16.         {          
    17.  
    18.             if (menuManager.command == "red")
    19.             {
    20.                 raycastGO.GetComponent<MeshRenderer>().material = red;
    21.  
    22.                 int photonViewId = raycastGO.GetComponent<PhotonView>().ViewID;
    23.                 Vector3 color = new Vector3(241, 19, 19);
    24.                 PhotonNetwork.CurrentRoom.SetCustomProperties
    25.                 (new Hashtable() { { photonViewId.ToString(), color } });
    26.             }
    27.  
    28.             if (menuManager.command == "green")
    29.             {
    30.                 raycastGO.GetComponent<MeshRenderer>().material = green;
    31.  
    32.                 int photonViewId = raycastGO.GetComponent<PhotonView>().ViewID;
    33.                 Vector3 color = new Vector3(20, 91, 17);
    34.                 PhotonNetwork.CurrentRoom.SetCustomProperties
    35.                 (new Hashtable() { { photonViewId.ToString(), color } });
    36.             }          
    37.         }
    38.     }
    39. }
    step03: when a new player joins, use that Hashtable in OnJoinedRoom() callback to synchronize all changes
    Code (CSharp):
    1. public override void OnJoinedRoom()
    2. {
    3.     Hashtable customProperties = PhotonNetwork.CurrentRoom.CustomProperties;
    4.  
    5.     foreach (string key in customProperties.Keys)
    6.     {
    7.         if (key.Contains("0") || key.Contains("curScn"))
    8.         {
    9.             //do nothing
    10.         }
    11.         else
    12.         {
    13.             int photonViewID = int.Parse(key);
    14.  
    15.             PhotonView photonView = PhotonView.Find(photonViewID);
    16.  
    17.             GameObject gameObject = null;
    18.             if (photonView != null)
    19.             {
    20.                 gameObject = photonView.gameObject;
    21.             }
    22.  
    23.             var colorInfo = (Vector3)customProperties[key];
    24.             float r = colorInfo.x / 255;
    25.             float g = colorInfo.y / 255;
    26.             float b = colorInfo.z / 255;
    27.  
    28.             if (gameObject != null)
    29.             {
    30.                 gameObject.GetComponent<MeshRenderer>().material.color
    31.                 = new Color(r, g, b);
    32.            
    33.             }
    34.         }
    35.     }
    36. }