Something went terribly wrong

I just spent the last few days watching through the full saving system section, not doing anything in the project as I used the saving asset section. As far as I remember, everything was working before then. I went back into my project and went through a portal. It loaded the scene, but the fader is faded out and not fading back in. From the scene view I can see the player is way up in the air (happens from either scene to the other so it’s not that it isn’t changing position, though it’s different heights in either) and right to the side of the fader, probably a coincidence but not sure considering it happens in both cases, going into either scene. The only error is in Mover on this line: transform.eulerAngles = data.rotation.ToVector(); NullReferenceException. Not sure when or what I messed up.

Also, can hit s to save, but pressing l to load doesn’t do anything but give errors same one on mover plus additional ones about an active agent which I checked player still has navmesh agent component.

Hi kotf,
First, I’m sorry for missing this question. I’m not sure how it slipped through the cracks.

The warning about the NavMeshAgent is normal, and generally nothing to worry about if you see it once. If you see it 999+ then that’s another issue.

Let’s start with your Mover.cs, paste it in along with a screenshot of the extended error message (click on the message and the stack trace will appear at the bottom of the console.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using RPG.Core;
using RPG.Saving;

namespace RPG.Movement
{
    public class Mover : MonoBehaviour, IAction, ISaveable
    {
         [SerializeField] float maxSpeed = 6f;
         NavMeshAgent navMeshAgent;
         Health health;
     
    void Awake()
    {
        navMeshAgent = GetComponent<NavMeshAgent>();
        health = GetComponent<Health>();
    }

    void Update()
    {
        UpdateAnimator();
    }

    public void StartMoveAction(Vector3 destination, float speedFraction)
    {
        GetComponent<ActionScheduler>().StartAction(this);
        MoveTo(destination, speedFraction);
    }

    public void MoveTo (Vector3 destination, float speedFraction)
    {
        navMeshAgent.SetDestination(destination);
        navMeshAgent.speed = maxSpeed * Mathf.Clamp01(speedFraction);
        navMeshAgent.isStopped = false;
    }

    public void Cancel()
    {
        navMeshAgent.isStopped = true;
    }
 
    void UpdateAnimator()
    {
        Vector3 velocity = navMeshAgent.velocity;
        Vector3 localVelocity = transform.InverseTransformDirection(velocity);
        float speed = localVelocity.z;
        GetComponent<Animator>().SetFloat("forwardSpeed", speed);
    }

    [System.Serializable]
    struct MoverSaveData
    {
        public SerializableVector3 position;
        public SerializableVector3 rotation;
    }

    public object CaptureState()
    {
        MoverSaveData data = new MoverSaveData();
        data.position = new SerializableVector3(transform.position);
        data.position = new SerializableVector3(transform.eulerAngles);
        return data;
    }

    public void RestoreState(object state)
    {
        MoverSaveData data = (MoverSaveData)state;
        GetComponent<NavMeshAgent>().enabled = false;
        transform.position = data.position.ToVector();
        transform.eulerAngles = data.rotation.ToVector();
        GetComponent<NavMeshAgent>().enabled = true;
    }
    }

}

Let’s narrow down the possibilites (though nothing here should be null at this point) and approach the conversion from a different approach.

public void RestoreState(object state)
{
    if(state==null) 
    {
         Debug.LogError($"{name}'s mover is trying to restore a null state}");
         return;
    }
    NavMeshAgent agent = GetComponent<NavMeshAgent>();
     if(agent==null)
     {
         Debug.LogError($"{name} does not appear to have a NavMeshAgent");
         return;
     }
    if(state is MoverSaveData data)
    {
         agent.enabled=false;
         transform.position = data.position.ToVector();
         transform.rotation = data.rotation.ToVector();
         agent.enabled=true;
    }
    else //state is not a MoverSaveData
    {   
         Debug.LogError($"{name} -State is not a MoverSaveData");
    }
}

I removed the } at the end of state from “Debug.LogError($”{name}'s mover is trying to restore a null state}")"
and changed from transform.rotation to eulerAngles because it couldn’t convert between Vector and Quaternion. Two additional errors pop up.

Ok, I’m officially confused… With the checks in place, there is nothing to be null that is not checked, but you’re still getting a null reference error.

It does show one thing… the default starting location of the Player in the scene is not on a NavMesh. It’s ok to get the message once, but if you’re getting it 545 times and counting, then there is an issue and the agent can’t lock in.

Make sure the player in the scene is on teh NavMesh, and that the spawnpoints on your portals are also on the navmesh.

If you’re still getting the same error log after that, zip up your project (remove the Library folder) and upload it to https://gdev.tv/projectupload.

Uploaded

Ok, I should have spotted this much sooner, but these things can hide from you till you can actually run the code in person…

    public object CaptureState()
    {
        MoverSaveData data = new MoverSaveData();
        data.position = new SerializableVector3(transform.position);
        data.position = new SerializableVector3(transform.eulerAngles); //<-------
        return data;
    }

What’s effectively happening is that you’re filling position, and then replacing position with the eulerAngles, meaning that data.rotation is still actually null.
Change that second line to data.rotation and all should work fine. (Delete the existing save file first, it’s broken).

That did it. Don’t know how I managed to miss that either. Anyway, thanks

It’s easy to miss… Glad we’ve got that sorted!

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

Privacy & Terms