I’m currently using three graphs:
- A navgraph that allows entities to walk on walls and ceilings
- A point graph in 3D space for flying units
- A second navmesh graph that has normals recalculated for entities that cannot walk on walls or ceilings
I am dynamically generating the point graph based on the navgraph’s bounding box. All of this is working correctly, however I’ve run into an issue where the point graph generation takes a very long time on larger maps. I would like to save only the point graph to a file, since the data for other graphs already reside in the mesh I’m using.
Looking at saving and loading graphs, I can use AstarPath.active.data.SerializeGraphs()
to save all three of my graphs, but I really only need to save my one point graph. Is there a way to serialize/deserialize a single graph, or am I stuck with serializing/deserializing all three at the same time?
Had the same issue.
public byte[] SerializeGraph(NavGraph[] graph)
{
return SerializeGraph(graph, Pathfinding.Serialization.SerializeSettings.Settings);
}
public byte[] SerializeGraph(NavGraph[] graph, Pathfinding.Serialization.SerializeSettings settings)
{
uint checksum;
return SerializeGraph(graph, settings, out checksum);
}
public byte[] SerializeGraph (NavGraph[] graph, Pathfinding.Serialization.SerializeSettings settings, out uint checksum)
{
var graphLock = AssertSafe();
var sr = new Pathfinding.Serialization.AstarSerializer(this, settings);
sr.OpenSerialize();
sr.SerializeGraphs(graph);
sr.SerializeExtraInfo();
byte[] bytes = sr.CloseSerialize();
checksum = sr.GetChecksum();
#if ASTARDEBUG
Debug.Log("Got a whole bunch of data, "+bytes.Length+" bytes");
#endif
graphLock.Release();
return bytes;
}
I adjusted the SerializeGraphs and made it work but you have to specify in the settings that the nodes should be saved. Did you do something like this or do you have a better solution? Hope you can share it.
No, I never ended up figuring out how to do a single graph. I was thinking that I could remove all the graphs, serialize just the one I wanted, then re-add my other two graphs, but that would require some time-consuming refactoring in other parts of my game.
In the end I just accepted that my build size is going to be ~50MB bigger than it needs to be, storing all of my level meshes across multiple cached graph files. It also saves me the hassle of not needing to worry about additive loading - I know that all the graph data I need is in the file so I can load it and be done.
This is the code that I used:
// Take all of the graphs and save them to an array of bytes, including all the nodes
byte[] bytes = AstarPath.active.data.SerializeGraphs(new SerializeSettings { nodes = true });
// Write that array of bytes with all the nodes and stuff to an actual file. This saves the bytes file to the name of the scene. Make sure that the directory exists.
Pathfinding.Serialization.AstarSerializer.SaveToFile(Application.dataPath + "/Other/Pathfinding/" + SceneManager.GetActiveScene().name + ".bytes", bytes);
// Then later on you can load the file. You'd either need to use Resources.Load() or drag the bytes file in Unity's inspector.
public TextAsset graphData;
AstarPath.active.data.DeserializeGraphs(graphData.bytes);
By the way @aron_granberg, the tutorial Saving and loading graphs talks about saving graphs to a file using code, but it never mentions how to actually do it.
If you want to load or save graphs during runtime, you cannot use the editor interface for obvious reasons.
There is an easy to use API for saving and loading files.
This will serialize graph settings to a byte array. By default node info is included (assuming the graphs have been scanned first).
It explains how to serialize the graphs, but it doesn’t make any mention whatsoever around how to actually write it to a file. I had to dive into the inner workings of the script code, figure out what the ‘save to file’ button did, then use that code (which is how I got the code in the above reply).
Thanks for the code. In my prototype I have to update and serialize individual graphs and add deserialize them additively.
This is the code I used
public Dictionary<string, GridGraph> graphDict = new Dictionary<string, GridGraph>();
GridGraph graph = graphDict[scene];
byte[] serializedGraph = AstarPath.active.data.SerializeGraph(new NavGraph[] { graph }, new Pathfinding.Serialization.SerializeSettings { nodes = true});
When I load in the graphs, I store a reference in a dictionary and pull them up later when serializing. A bit cumbersome but this is how I serialized mine individually using SerializeGraph(which I posted before).