Saving and Loading Graphs
How to precalculate graphs and store that data.
All graphs can be saved and loaded from files. The is actually what the editor does all the time, barely any Unity serialization is used, instead all graph settings are serialized and stored in a byte array. However, not only settings can be saved, once calculated, a graph can save all nodes to a compact byte array representation, which can then be saved to a file and loaded somewhere else.
In the A* inspector, under the Save & Load tab, there are two buttons named "Save to file" and "Load from file", these can be used to save and load graph files.
Caching Graph Calculation
Recalculating the graphs at startup is usually what you want, but sometimes - especially if you are using the RecastGraph or developing for mobile - the lag at the start can get very annoying. It might also be the case that you cannot calculate the graph at startup for some reason.
In that case graph caching is great. It enables you to scan the graph in the editor and save it to an external file which will be loaded at startup. It is a lot faster than scanning the graphs in most cases and you know exactly how the graph will look.
To create a cache, open the Save & Load tab in the A* inspector and click Generate Cache. It will also ask you if you want to rescan the graph before saving. Now the graph you saved will be loaded with all node info intact at startup, no calculation time necessary.
Saving Graphs to File and Loading them
You might also want to save the graphs to a file which you can load later. You can even load it during runtime from a server for example.
If you want to save your graphs, open the Save & Load tab, and click the Save to file button. You can either include only the settings, or include settings as well as node data. If you only include settings, then after the graph has been loaded, you will need to recalculate it before any characters can use it for navigation. You can recalculate all graphs using:
AstarPath.active.Scan();
When you want to load the graphs again, simply press the Load from file button and locate the file. Note that this will replace your current graphs.
Loading and Saving using Code
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). byte[] bytes = AstarPath.active.data.SerializeGraphs();
If you want more control, you can add some settings var settings = new Pathfinding.Serialization.SerializeSettings();
To load the saved data you can call:
// Only save settings
settings.nodes = false;
byte[] bytes = AstarPath.active.data.SerializeGraphs(settings);AstarPath.active.data.DeserializeGraphs(bytes);
If you only load settings, you may want to call Scan after you have loaded the settings: AstarPath.active.data.DeserializeGraphs(bytes);
AstarPath.active.Scan();
Additive Loading
Instead of replacing the currently loaded graphs, you can additively load graphs using
AstarPath.active.data.DeserializeGraphsAdditive(bytes);
You can unload graphs using
var data = AstarPath.active.data;
var myGraph = data.gridGraph;
data.RemoveGraph(myGraph);
Including Data in a TextAsset
Graph data can be included in textassets for easier inclusion in the build. When you have saved the data to a file, rename that file to something like "myGraph.bytes" and place it in your Unity Project. This will tell Unity to handle it as binary information. With an extension like .txt the data would get corrupted because Unity would try to read it as text. Some operating systems like to hide the extension, so if Unity doesn't seem to recognize the file with the .bytes extension make sure it really has a .bytes extension, the .zip (or other) extension might just be hidden. Then you can load the graph from a text asset by referencing it in a variable, and accessing the .bytes field. using UnityEngine;
using System.Collections;
using Pathfinding;
[HelpURL("https://arongranberg.com/astar/documentation/beta/class_test_loader.php")]
public class TestLoader : MonoBehaviour {
public TextAsset graphData;
// Load the graph when the game starts
void Start () {
AstarPath.active.data.DeserializeGraphs(graphData.bytes);
}
}
Internal Data Structure
All settings are serialized to JSON. This is a good way to keep it forwards and backwards compatible. All files referred to below are compressed into a single zip file to make the size smaller and make it easier to handle the data. This means you can actually open the zip file up and edit the settings manually.
Note
Many of the files mentioned below are not always included in the zip. If it is determined that a file would not contain any relevant information (such as saving user created connections, but no connections have been created), it is left out.
Meta
A meta.json file is present in all serializations. This file contains information which is not connected to a specific graph, or is needed to load the other graphs.
The meta file contains
Version number for the system
Number of graphs which are saved
GUID values for each graph, to identify them
Type of each graph
Below is an example of a meta.json file: {
"version": "3.0.9.5",
"graphs": 1,
"guids":
[
"0d83c93fc4928934-8362a8662ec4fb9d"
],
"typeNames":
[
"Pathfinding.GridGraph"
]
}
Graph Settings
Settings for each graph is stored as "graph#.json" where # is the graph number. Here is an example of serialized settings for a grid graph (with some settings removed to keep the length down): {
"aspectRatio":1,
"rotation":{
"x":0,
"y":0,
"z":0
},
"center":{
"x":0,
"y":-0.1,
"z":0
},
"unclampedSize":{
"x":100,
"y":100
},
"nodeSize":1,
"maxClimb":0.4,
"maxClimbAxis":1,
"maxSlope":90,
"erodeIterations":0,
"autoLinkGrids":false,
"autoLinkDistLimit":10,
"neighbours":"Eight",
"cutCorners":true,
"penaltyPositionOffset":0,
"penaltyPosition":false,
"penaltyPositionFactor":1,
"penaltyAngle":false,
"penaltyAngleFactor":100,
"open":true,
"infoScreenOpen":false
...
}
Node information (if included in the serialized data) would take too much space to be included as JSON, instead it is written as binary data. Each graph type has its own code for serializing node data. This is handled by the SerializeExtraInfo and DeserializeExtraInfo methods on each graph.
User Created Connections
The NodeLink2 component is also serialized, when this happens it stores an ID for that component and when the graph is deserialized it will try to find the corresponding component. This works well for static maps, but for objects that are created during runtime there isn't really any good way to keep track of the different objects, so it might be better to don't include the links in the saved data (make sure they are disabled), and then enable them after the graphs have been loaded.