Null rerefence oddity with mobile and web player only

Options
Hello,

I keep getting a null reference that goes back and forth between the 2 lines of code marked. It only seems to happen when game is deployed to either mobile or web player only. The players seem to play fine but if I can eliminate it I would like to. I'm running Unity 4.6.4f1.

using UnityEngine;
using System.Collections;

public class NetworkDragon : Photon.MonoBehaviour {

	public static Vector3 realPosition = Vector3.zero;
	Quaternion realRotation = Quaternion.identity;	
	Animator anim;

	private AnimationState animFlight;

	// Use this for initialization
	void Start () {
		anim = GetComponent<Animator>();
		if(anim == null) {
			Debug.LogError ("ZOMG, you forgot to put an Animator component on this character prefab!");
		}
	}
	
	void Update () {
		if( photonView.isMine ) {
			// Do nothing -- the character motor/input/etc... is moving us
		}
		else {
			transform.position = Vector3.Lerp(transform.position, realPosition, 0.1f);
			transform.rotation = Quaternion.Lerp(transform.rotation, realRotation, 0.1f);
		}
	}

	public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
		if(stream.isWriting) {
			// This is OUR player. We need to send our actual position to the network.
			stream.SendNext(transform.position);
			stream.SendNext(transform.rotation);
				
----> stream.SendNext(anim.GetFloat("Speed"));
			stream.SendNext(anim.GetInteger("Flight"));
		}
		else {
			// This is someone else's player. We need to receive their position (as of a few
			// millisecond ago, and update our version of that player.
			realPosition = (Vector3)stream.ReceiveNext();
			realRotation = (Quaternion)stream.ReceiveNext();
			
----> anim.SetFloat("Speed", (float)stream.ReceiveNext());
			anim.SetInteger("Flight", (int)stream.ReceiveNext());
		}
		
	}

}

Sometimes its this line: stream.SendNext(anim.GetFloat("Speed"));

and sometimes this line: anim.SetFloat("Speed", (float)stream.ReceiveNext());

Could this be simply a missed data packet?

Anyone else see this?

Thanks

Comments

  • vadim
    Options
    Hi,

    Did you find out which variable in null reference?
  • FGStud
    Options
    vadim wrote:
    Hi,

    Did you find out which variable in null reference?

    I assume it's "Speed" variable (the only variable as pointed out in original post) but I have found nothing to understand why that could be null at the beginning of 2nd player entering a room. I don't see it when 1 player creates a room. Only when 2nd player enters.

    It hasnt been affecting the game but I just upgraded to Unity 5.0.1 and now it is causing crashes only on mobile (i.e. mobile player versus Unity editor player). I see the error in all build targets but it only crashes on mobile.

    When I build for Standalone player now I see it at the beginning of the 2nd player entering room (other player is running in Unity) but there is no crash. There is no null if only 1 player is in the room.

    It only seems to be at the very beginning of the 2nd players entering room.

    I'm kinda dead in the water until this is fixed.

    Could this be a dropped packet or something?
  • FGStud
    Options
    The full error dump from Unity is below if it helps ...

    Line 37 of NetworkDragon.cs is:

    stream.SendNext(anim.GetFloat("Speed"));


    So obviously when the 2nd player joins "Speed" is not defined for some reason.

    Would some sort of delay before joining help?


    NullReferenceException: Object reference not set to an instance of an object
    NetworkDragon.OnPhotonSerializeView (.PhotonStream stream, .PhotonMessageInfo info) (at Assets/Scripts/NetworkDragon.cs:37)
    System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
    Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
    System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232)
    System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115)
    PhotonView.ExecuteComponentOnSerialize (UnityEngine.Component component, .PhotonStream stream, .PhotonMessageInfo info) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs:530)
    PhotonView.SerializeComponent (UnityEngine.Component component, .PhotonStream stream, .PhotonMessageInfo info) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs:440)
    PhotonView.SerializeView (.PhotonStream stream, .PhotonMessageInfo info) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonView.cs:337)
    NetworkingPeer.OnSerializeWrite (.PhotonView view) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs:3286)
    NetworkingPeer.RunViewUpdate () (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs:3207)
    PhotonHandler.Update () (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs:90)
  • FGStud
    Options
    I changed the observe option from "Unreliable" to "Reliable Delta Compression" and the null went away. Testing a few more times and it started appearing again over and over. I then changed observe option to "Unreliable On Change" and I stopped seeing the null error. But then it started appearing again.

    What in the world is going on here?

    No one has ever seen this behavior before?
  • FGStud
    Options
    So I switched the position of streaming variables and now the first variable is the one with the null ref.

    FROM:
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
    
    		///Debug.Log ("anim.GetFloat(Speed): " + anim.GetFloat("Speed"));
    
    		if(stream.isWriting) {
    			// This is OUR player. We need to send our actual position to the network.
    			stream.SendNext(transform.position);
    			stream.SendNext(transform.rotation);
    			
    	null ref -->stream.SendNext(anim.GetFloat("Speed"));
    			stream.SendNext(anim.GetInteger("Flight"));
    			stream.SendNext(anim.GetInteger("Glide"));
    		}
    		else {
    			// This is someone else's player. We need to receive their position (as of a few
    			// millisecond ago, and update our version of that player.
    			realPosition = (Vector3)stream.ReceiveNext();
    			realRotation = (Quaternion)stream.ReceiveNext();
    			
    			anim.SetFloat("Speed", (float)stream.ReceiveNext());
    			anim.SetInteger("Flight", (int)stream.ReceiveNext());
    			anim.SetInteger("Glide", (int)stream.ReceiveNext());
    
    		}
    		
    	}
    


    TO:
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
    
    		///Debug.Log ("anim.GetFloat(Speed): " + anim.GetFloat("Speed"));
    
    		if(stream.isWriting) {
    			// This is OUR player. We need to send our actual position to the network.
    			stream.SendNext(transform.position);
    			stream.SendNext(transform.rotation);
    
    	null ref -->stream.SendNext(anim.GetInteger("Flight"));
    			stream.SendNext(anim.GetInteger("Glide"));
    			stream.SendNext(anim.GetFloat("Speed"));
    		}
    		else {
    			// This is someone else's player. We need to receive their position (as of a few
    			// millisecond ago, and update our version of that player.
    			realPosition = (Vector3)stream.ReceiveNext();
    			realRotation = (Quaternion)stream.ReceiveNext();
    
    			anim.SetInteger("Flight", (int)stream.ReceiveNext());
    			anim.SetInteger("Glide", (int)stream.ReceiveNext());
    			anim.SetFloat("Speed", (float)stream.ReceiveNext());
    		}
    		
    	}
    

    And now the "Flight" variable is the line I get the null ref but only when 2nd player joins room.

    This is driving me bonkers!! :shock:

    Anyone have any ideas?
  • FGStud
    Options
    I just tried setting the values explicetly on Start ... I can't believe this would not work!
    using UnityEngine;
    using System.Collections;
    
    public class NetworkDragon : Photon.MonoBehaviour {
    	
    	public static Vector3 realPosition = Vector3.zero;
    	Quaternion realRotation = Quaternion.identity;	
    	Animator anim;
    
    	// Use this for initialization
    	void Start () {
    		anim = GetComponent<Animator>();
    		if(anim == null) {
    			Debug.LogError ("Need Animator component on this character prefab");
    		}
    		anim.SetInteger("Flight", 0);
    		anim.SetInteger("Glide", 0);
    		anim.SetFloat("Speed", 0.0f);
    	}
    	
    	void Update () {
    		if( photonView.isMine ) {
    			// Do nothing -- the character motor/input/etc... is moving us
    		}
    		else {
    			transform.position = Vector3.Lerp(transform.position, realPosition, 0.1f);
    			transform.rotation = Quaternion.Lerp(transform.rotation, realRotation, 0.1f);
    		}
    	}
    
    	public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
    
    		if(stream.isWriting) {
    			// This is OUR player. We need to send our actual position to the network.
    			stream.SendNext(transform.position);
    			stream.SendNext(transform.rotation);
    
    null ref here ---> stream.SendNext(anim.GetInteger("Flight"));
    			stream.SendNext(anim.GetInteger("Glide"));
    			stream.SendNext(anim.GetFloat("Speed"));
    		}
    		else {
    			// This is someone else's player. We need to receive their position (as of a few
    			// millisecond ago, and update our version of that player.
    			realPosition = (Vector3)stream.ReceiveNext();
    			realRotation = (Quaternion)stream.ReceiveNext();
    
    			anim.SetInteger("Flight", (int)stream.ReceiveNext());
    			anim.SetInteger("Glide", (int)stream.ReceiveNext());
    			anim.SetFloat("Speed", (float)stream.ReceiveNext());
    		}
    		
    	}
    
    }
    

    and I still get null ref ... Is there some script that is called before this?
  • FGStud
    Options
    Now I get a crash in xcode that seems different from the null ref ... not a good week :cry:

    7236s7.jpg
  • FGStud
    Options
    Fixed it but not a great solution ...
  • Tobias
    Options
    I don't know for sure how this happens but my guess is that the PhotonView (PV) is initialized before the Animator component. Maybe the Animator also needs a frame to get sub-components setup or so. In any case, maybe the Update() loop will call OnPhotonSerializeView() before the GO and animator is fully setup?!
    Does a check for "non null" help in this case??
  • FGStud
    Options
    Hi Tobias,

    Yes a check right before did catch the null ref of the Animator component. This is what I eventually did to get it to work. I'm not sure if this is going to be an issue but I no longer see the null ref.

    if(stream.isWriting && stream != null && anim != null) {
    			// This is OUR player. We need to send our actual position to the network.
    			stream.SendNext(transform.position);
    			stream.SendNext(transform.rotation);
    
    
    			stream.SendNext(anim.GetInteger("Flight"));
    			stream.SendNext(anim.GetInteger("Glide"));
    			stream.SendNext(anim.GetFloat("Speed"));
    		}
    		else {
    			if( stream != null && anim != null)
    			{
    			// This is someone else's player. We need to receive their position (as of a few
    			// millisecond ago, and update our version of that player.
    			realPosition = (Vector3)stream.ReceiveNext();
    			realRotation = (Quaternion)stream.ReceiveNext();
    
    			anim.SetInteger("Flight", (int)stream.ReceiveNext());
    			anim.SetInteger("Glide", (int)stream.ReceiveNext());
    			anim.SetFloat("Speed", (float)stream.ReceiveNext());
    			}
    		}
    
    

    Would checking for null ref each frame cause performance issues down the line? I see none now but as the game gets more complex I worry it might ...

    This is the code that finally caught the null ref exception ...
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
    
    		if(stream == null) {
    			Debug.LogError ("stream is null");
    		}
    if(anim == null) {
    			Debug.LogError ("anim is null");
    		}
    		if(stream.isWriting) {
    			// This is OUR player. We need to send our actual position to the network.
    			stream.SendNext(transform.position);
    			stream.SendNext(transform.rotation);
    
    
    			stream.SendNext(anim.GetInteger("Flight"));
    			stream.SendNext(anim.GetInteger("Glide"));
    			stream.SendNext(anim.GetFloat("Speed"));
    		}
    		else {
    			// This is someone else's player. We need to receive their position (as of a few
    			// millisecond ago, and update our version of that player.
    			realPosition = (Vector3)stream.ReceiveNext();
    			realRotation = (Quaternion)stream.ReceiveNext();
    
    			anim.SetInteger("Flight", (int)stream.ReceiveNext());
    			anim.SetInteger("Glide", (int)stream.ReceiveNext());
    			anim.SetFloat("Speed", (float)stream.ReceiveNext());
    		}
    
    

    The debugs have been removed.