Null reference exception after moving the RestoreState() to our mover.cs

So after I refactored everything (compared my files with the github commits etc etc) as per Sam’s instructions I ran into an error when going from one scene to the next and back again. Upon re-entering the Scene I originally spawned in I get:
NullReferenceException: Object reference not set to an instance of an object
Scripts.Movement.Mover.RestoreState (System.Object state) (at Assets/Scripts/Movement/Mover.cs:74)

Which refers to:

 public void RestoreState(object state)
            var serializableVector3 = (SerializableVector3)state;
            _myNavMeshAgent.Warp(serializableVector3.ToVector3()); // This line

I tried disabling Navmeshagent instead and using player.transform but the result is the same.
If I swap places of the Navmesh line and the ActionSched. line the error occurs on the ActionSched. line so it is clearly behaving as if we do not have an Object attached to the component.

If I shuffle around where I call Load() in my Portal.cs I can get it to work (kind of):

IEnumerator Transition()
            Fader fader = FindObjectOfType<Fader>();
            SavingWrapper wrapper = FindObjectOfType<SavingWrapper>();
            yield return fader.FadeOut(fadeOutTime);
            yield return SceneManager.LoadSceneAsync(sceneToLoad);
            wrapper.Load(); // Doesn't work here
            Portal otherPortal = GetOtherPortal();
            // Doesn't work here either.
            yield return new WaitForSecondsRealtime(loadSceneTime);
            // Works here (well as it, it does not give me the same error, it still bugs out due to the fading glitching out etc)
            yield return fader.FadeIn(fadeInTime);
            // Works here (but the player starts teleporting back and forth, obviously not a great place to have it, but again, I am not getting the error)

So, to me, it certainly seems like it is saying something like “Hey the Guid referred to an Object that no longer has this particular Mover.cs component from within which you are trying to do stuff”. Does this have to do with the fact that we carry two different GUID’s for our Player Object in our two scenes so that when we go back and forth it is trying to access the component of the Object that is no longer loaded? But if so, why does it work when i change scene the first time but not the second time?

My brain hurts…

(it was all working as expected before we refactored most of it into Mover.cs)

Help, please…

My first guess is that you’re caching your references to the Navmesh Agent and Action Scheduler in Start()…
Now that we’re using the Saving system, these sorts of references need to be in Awake() if they’re going to be referenced in RestoreState() or CaptureState().
The reason for this is that all of the activity that happens in Fader when we transition between scenes happens between Awake() and Start().

Spot on, thanks as per usual Brian.

It does seem as if I celebrated a bit prematurely… It is working, as in I am no longer getting the null reference exception, however I am being faced with this after teleportation to a new scene:

Failed to create agent because it is not close enough to the NavMesh
Scripts.Movement.Mover:RestoreState(Object) (at Assets/Scripts/Movement/Mover.cs:74)

Which again points to:

Any ideas? is it trying to access the Navmesh of the previous scene? I should probably tell you that we are now using a persistent player GUID across scenes which probably is what is causing this issue. The NavMeshAgent is trying to warp to previously CapturedState which was captured in the previous scene. Should we really Load the players state when crossing scenes?

We haven’t worried too much about this as it is a warning, not a redbug. It tends to come up with most students projects (including my own when I took the course!) when changing scenes.

Unfortunately, I’m at work right now and can’t test this, but it occurs to me that if we disable the NavMeshAgents in the SCENE and then re-enable them in the Start() method, it might get around this issue, but I won’t be able to test it till I get home.

That is fine, I just needed to know that I had not messed something up and what you said is enough for me to not worry about it for now. And as you say, it sounds like it would not be to difficult to refactor away.

Thanks for the help Brian.

EDIT: interesting tidbit: It only happens when going from Sandbox.scene (the “original Scene” in my case) to the SandboxLoop.scene (the smaller runway scene), not the other way around. Go figure :thinking:

The issue is with he Save and Load order in Portal.Transition()

            yield return SceneManager.LoadSceneAsync(sceneToLoad);
            wrapper.Load(); // here we attempt to restore the players position from the save state in the previous scene.
            Portal otherPortal = GetOtherPortal();
           // this would be the optimal placement of the Wrapper.Load(), the issue is with the updated player position. And all the issues that would arise from not Loading the new Scene state before Wrapper.Save()

Wouldn’t the optimal solution be to not update the players position at all when (specifically) Portal.cs is calling Wrapper.Load? Like maybe have another Wrapper.LoadWithoutUpdatingPlayerPos() method for cases like these where the calling method is also locally updating the players position to the desired location.

EDIT3: Since you have taken the same course, do you know the reason for not including the rotation of the objects we want to restore the state for? I find it jarring that the player is facing the same way as he did before loading a new save point within a scene.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.