NullReferenceException on RoomObject RPC

Options

Versions:

Pun: 2.41 Photon lib: 4.1.6.17

Unity 2021.3.15f1

Android build running on Android 12


Hi, I'm having trouble with Null reference exception on Android build when calling RPC from different client on Room object. Steps I'm making to reproduce this issue:

(client A is Unity Editor, client B is Android build running on device, all RPCs are called with RpcTarget.AllViaServer parameter, we are using multi scene setup and all PhotonNetwork instantiated objects are flagged as DontDestroyOnLoad, GM is implemented as singleton, its PhotonView ownership is set as Fixed, sync set to Reliable delta compressed)

  1. Client A is Master client, creates room, instantiates object GM as room object (PhotonNetwork.InstantiateRoomObject), instantiates player object P1 (PhotonNetwork.Instantiate), waits for second player
  2. Client B joins open room, instantiates player object P2
  3. Clients load their own custom data from PlayFab, sync them via RPC on player objects P1 and P2 respectively
  4. Client A calls RPC on room object GM to load next level, we are using custom scene loading (PhotonNetwork.AutomaticallySyncScene set to false) because of additive scene loading
  5. Clients start async scene load from SceneManager
  6. Clients wait for their scene load to finish, then each sets their LevelLoaded "flag" as local player custom property (PhotonNetwork.LocalPlayer.SetCustomProperties (props))
  7. GM waits for both players to finish scene loading via OnPlayerPropertiesUpdate callback - on each call checks if all network players set required property to true
  8. SceneManager finishes some scene preparation, activates new scene and starts game initialization in GM
  9. In GM init Client A generates two variables (bool and string - Guid)[snippet 2.], syncs them via RPC on GM (this is the problematic RPC called "SyncGameStartVariables" [snippet 1.])
  10. Clients wait for RPC to be received on their instance of GM [snippet 2.], then resume game initialization, everything after that is irrelevant


Code snippet 1:

[PunRPC]
public void SyncGameStartVariables (bool firstPlayerIsMaster, string matchGuid)
{
   if (firstPlayerIsMaster)
      firstPlayer = p1Controller.netPlayer.player.IsMasterClient ? PlayerNum.FIRST : PlayerNum.SECOND;
   else
      firstPlayer = p2Controller.netPlayer.player.IsMasterClient ? PlayerNum.SECOND : PlayerNum.FIRST;

   this.matchGuid = matchGuid;

   _playerReceivedGameStartData = true;
}

Code snippet 2:

if (PhotonNetwork.LocalPlayer.IsMasterClient)
{
   var masterStarts = Random.value > 0.5f;
   var newMatchGuid = (gameMode == GameMode.MODE2) ? matchGuid :
      X.i.isMultiplayer                            ? Guid.NewGuid ().ToString () : "";
   RPC ("SyncGameStartVariables", masterStarts, newMatchGuid);
}

var gameStartDataTask = Task.Run (() =>
{
   while (!_playerReceivedGameStartData)
      Task.Yield ();
});

...

await Task.WhenAll (p1InitTask, p2InitTask, gameStartDataTask);

RPC is public method in GM

public void RPC (string rpc, params object[] parameters)
{
   photonView.RPC (rpc, RpcTarget.AllViaServer, parameters);
}


Issue:

After Client A calls "SyncGameStartVariables" RPC, same client will successfully receive and run said RPC, Client B also receives it (logged thanks to PUN Logging - Full setting), however then throws exception:

NullReferenceException: Object reference not set to an instance of an object.
GameManager.SyncGameStartVariables (System.Boolean firstPlayerIsMaster, System.String matchGuid) (at <00000000000000000000000000000000>:0)
System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <00000000000000000000000000000000>:0)
Photon.Pun.PhotonNetwork.ExecuteRpc (ExitGames.Client.Photon.Hashtable rpcData, Photon.Realtime.Player sender) (at <00000000000000000000000000000000>:0)
Photon.Pun.PhotonNetwork.OnEvent (ExitGames.Client.Photon.EventData photonEvent) (at <00000000000000000000000000000000>:0)
Photon.Realtime.LoadBalancingClient.OnEvent (ExitGames.Client.Photon.EventData photonEvent) (at <00000000000000000000000000000000>:0)
ExitGames.Client.Photon.PeerBase.DeserializeMessageAndCallback (ExitGames.Client.Photon.StreamBuffer stream) (at <00000000000000000000000000000000>:0)
ExitGames.Client.Photon.EnetPeer.DispatchIncomingCommands () (at <00000000000000000000000000000000>:0)
ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands () (at <00000000000000000000000000000000>:0)
Photon.Pun.PhotonHandler.Dispatch () (at <00000000000000000000000000000000>:0)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.RuntimeMethodInfo.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <00000000000000000000000000000000>:0)
Photon.Pun.PhotonNetwork.ExecuteRpc (ExitGames.Client.Photon.Hashtable rpcData, Photon.Realtime.Player sender) (at <00000000000000000000000000000000>:0)
Photon.Pun.PhotonNetwork.OnEvent (ExitGames.Client.Photon.EventData photonEvent) (at <00000000000000000000000000000000>:0)
Photon.Realtime.LoadBalancingClient.OnEvent (ExitGames.Client.Photon.EventData photonEvent) (at <00000000000000000000000000000000>:0)
ExitGames.Client.Photon.PeerBase.DeserializeMessageAndCallback (ExitGames.Client.Photon.StreamBuffer stream) (at <00000000000000000000000000000000>:0)
ExitGames.Client.Photon.EnetPeer.DispatchIncomingCommands () (at <00000000000000000000000000000000>:0)
ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands () (at <00000000000000000000000000000000>:0)
Photon.Pun.PhotonHandler.Dispatch () (at <00000000000000000000000000000000>:0)
Rethrow as AggregateException: Caught 1 exception(s) in methods called by DispatchIncomingCommands(). Rethrowing first only (see above). (Exception has been thrown by the target of an invocation.)
Photon.Pun.PhotonHandler.Dispatch () (at <00000000000000000000000000000000>:0)


Important thing: this only happens if the Client A (master client) is Unity Editor and Client B is device. If I swap these two, so the master client is Android device, everything works correctly.


What I've tried:

  1. GM, P1 and P2 as children of game object flagged as DontDestroyOnLoad and as root objects flagged alone
  2. multiple rearrangements of first steps, however steps 7 to 10 must stay the same
  3. logged incoming params in internal ExecuteRpc method
  4. refactored multiple of our methods to eliminate every possible problem
  5. logged status of all scenes after step 6 to check if they are loaded and valid (all 4 were always correct)
  6. logged status of GM singleton object, if is always accessible, everything is okay
  7. in step 8 introduced long artificial delay after scene activation and before calling GM initialization so I could be sure everything was getting set up correctly (delays between changing something big and then working with it are standard throughout our codebase, mainly when changing activation states of objects / scenes, we almost always introduce at least 1 frame delay so Unity can do its things)


From what I've read, this may be symptom of receiving RPC during scene transition, I tried to eliminate that possibility as much as I can, however it's harder to debug this on Android device and every change takes time to implement because our project is pretty big - work I try to do here is just change of multiplayer logic in working game.


So, does anyone have any idea why could be this happening, or if it was really problem of receiving RPC during some scene load / activation shenanigans, is there any way to debug this more in depth?


Thank you for any input.

Answers

  • FTechnologygames
    edited February 2023
    Options

    Yep, we got similar error but in the different condition - it's happened because we got different regions for release build on android ( I guess - all regions ) and dev build - which was fixed and only one, so It's why other android and dev PC build were not able find each other.