Support Forum

Loading Graph at runtime

Hi,
Using this script to load cached graph at runtime, don’t work when i enable via script but works when i do it manualy in the editor.

public class loadNavMeshFromCache : MonoBehaviour
{
public string graphCachePath = “Assets/GraphCaches/GraphCache.bytes”;

void OnEnable()
{
    var graphBytes = File.ReadAllBytes(graphCachePath);

    if (graphBytes != null)
    {
        AstarPath.active.data.DeserializeGraphs(graphBytes);
    }
}

}

Any help?
Currently only work when i destroy and create new pathfinder with path to cache in standart Settings.

Hi

Can you try running this during Start instead. It’s possible that your script is enabled before the pathfinding component has even been loaded by unity.

Still don’t work, i enable script after scene load. Also try to enable it many times after 1-3 sec. wait.
Is this correct scheme?

  1. Keep pathfinding component in main scene marked Don’t Destroy on Load
  2. Load levels as scenes additive
  3. Use script above to update Recast graph

Hi

Yes, that sounds correct.
Your code looks like almost identical to how the cache is loaded, so I’m not sure why it wouldn’t work.
image

Are you sure it is reading the file correctly?

Now it works in editor, when i enable via script(previously works only when enably manualy)
I can copy your example or it will not work?
Show errors for DeserializeGraphs and .bytes

Hi, Any help? Still don’t work.

Hi

Note that your path is relative to the project folder. This will not work in a standalone game, only when running in the Unity Editor. Is that what is not working for you possibly?

Yes, that seems to be the problem, best way to fix it?
So i need to change cached graphs for one pathfinding component, when loading new scene.

Edit2: I just realized you can use your Solution and just replace “public string graphCachePath = “Assets/GraphCaches/GraphCache.bytes”;” with “public string graphCachePath = $“{Application.dataPath}/GraphCaches/GraphCache.bytes”;”

You can load the file via a filestream, I do it like this:

 string _fullpath = $"{Application.dataPath}/mygraph.bytes";

            if (!File.Exists(_fullpath))
                return;

            FileStream stream = File.Open(_fullpath, FileMode.Open);

            if (stream == null)
                return;

            byte[] bytes = null;
            using (BinaryReader _reader = new BinaryReader(stream))
            {
                int count = _reader.ReadInt32();
                bytes = _reader.ReadBytes(count);
            }

          if (bytes != null)
                AstarPath.active.data.DeserializeGraphsAdditive(bytes);

Note: the reader needs to know how many bytes there are so when I serialize the graphs I put an int with the byte count in front.

var settings = new Pathfinding.Serialization.SerializeSettings();
        byte[] bytes = AstarPath.active.data.SerializeGraphs(settings);
     

        string _fullpath = $"{Application.dataPath}/mygraph.bytes";

        using (BinaryWriter _writer = new BinaryWriter(File.Open(_fullpath, FileMode.OpenOrCreate)))
        {            
            _writer.Write(bytes.Length);
            _writer.Write(bytes);
        }

Edit: Application.dataPath refers to the “PROJECTNAME_Data” folder in the build - in the editor its basically just your “Assets” folder.
Unity does not create this automatically when you build your project and you have to put your graph files into the correct folder manually.

Thanks for reply:)
I need to put cache graph files in Streaming Assets folder and download them additionaly from server?

Yes and no, it depends on your workflow.^^ “Application.dataPath” basically means your game’s directory - when you build your project you will have your executable and 2 folders in your directory. One of those is “ProjectName_Data” - this is where “Application.dataPath” refers to.

So if you put your graph file in that folder, you can load it in your script with $"{Application.dataPath}/graph.bytes"

Unity - Scripting API: Application.dataPath

If you setup your StreamingAssets folder, unity will include that in your folder structure, meaning you don’t have to put your assets there manually.
To access that you should use “Application.streamingAssetsPath”.

Unity - Manual: Streaming Assets

In theory you could also put your serialized graphs in an assetbundle as a TextAsset and load them form there, and/or as you mentioned it download it from a server. ^^
Unity - Manual: AssetBundles

I don’t feel confident enough on giving you advice about how you should or should not do it. I was trying to emulate your solution and make it work with as little change as possible, sorry if I caused confusion. ^^’

Your code should work in the editor and the build if you make use of this change:

Although, as mentioned, you have to put your “GraphCaches” folder with the “GraphCache.bytes” file into your games directory after building the game. How you do it, wether by including it from the start for your users or updating it at runtime by downloading it from a server is up to you. ^^

Hi,
Was able to setup it using Unity Adressables:)
Resources\Streaming assets have problem with finding files and etc.

Here is my code:

using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;


public class LoadGraph : MonoBehaviour
{
    public string ToLoad;
    public TextAsset graphData;
    public bool Running = true;
    private AsyncOperationHandle AsHandle;

    void OnEnable()
    {
        graphData = null;

        Addressables.LoadAssetAsync<TextAsset>(ToLoad).Completed += handle =>
        {
            graphData = handle.Result;
            AsHandle = handle;
        };

        StartCoroutine(Spawn());

    }
    IEnumerator Spawn()
    {
        while (Running != false)
        {
            if (graphData != null)
            {
                AstarPath.active.data.DeserializeGraphs(graphData.bytes);
                yield break;
            }
            else
            {
               yield return new WaitForSeconds(0.02f);
            }
        }
    }
}
1 Like