I upgraded from 3.5.1 and I can no longer scan my recast graphs.
I have 4 recast graphs with similar settings, with cell/character size increasing incrementally.
When scanning I get the following errors:
`There was an error generating the graphs:
System.NullReferenceException: Object reference not set to an instance of an object
at Pathfinding.RecastGraph.GetVertex (Int32 index) [0x0000b] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Generators\RecastGenerator.cs:379
at Pathfinding.TriangleMeshNode.GetVertex (Int32 i) [0x00000] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Generators\odeClasses\TriangleMeshNode.cs:57
at Pathfinding.RecastGraph.CreateTile (Pathfinding.Voxels.Voxelize vox, VoxelMesh mesh, Int32 x, Int32 z) [0x0028f] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Generators\RecastGenerator.cs:1574
at Pathfinding.RecastGraph.BuildTileMesh (Pathfinding.Voxels.Voxelize vox, Int32 x, Int32 z) [0x00266] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Generators\RecastGenerator.cs:1477
at Pathfinding.RecastGraph.ScanAllTiles (.OnScanStatus statusCallback) [0x002ea] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Generators\RecastGenerator.cs:1293
at Pathfinding.RecastGraph.ScanTiledNavmesh (.OnScanStatus statusCallback) [0x00000] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Generators\RecastGenerator.cs:1202
at Pathfinding.RecastGraph.ScanInternal (.OnScanStatus statusCallback) [0x00016] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Generators\RecastGenerator.cs:1192
at AstarPath.ScanLoop (.OnScanStatus statusCallback) [0x00326] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Core\AstarPath.cs:1827
at AstarPathEditor.MenuScan () [0x000c1] in D:\PROJECTS\Dustwind\Assets\AstarPathfindingProject\Editor\AstarPathEditor.cs:2429
If you think this is a bug, please contact me on arongranberg.com (post a comment)
UnityEngine.Debug:LogError(Object)
AstarPathEditor:MenuScan() (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:2432)
AstarPathEditor:OnInspectorGUI() (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:452)
UnityEditor.DockArea:OnGUI()
`
NullReferenceException: Object reference not set to an instance of an object Pathfinding.RecastGraph.GetVertex (Int32 index) (at Assets/AstarPathfindingProject/Generators/RecastGenerator.cs:379) Pathfinding.TriangleMeshNode.GetVertex (Int32 i) (at Assets/AstarPathfindingProject/Generators/NodeClasses/TriangleMeshNode.cs:57) Pathfinding.RecastGraph.CreateTile (Pathfinding.Voxels.Voxelize vox, VoxelMesh mesh, Int32 x, Int32 z) (at Assets/AstarPathfindingProject/Generators/RecastGenerator.cs:1574) Pathfinding.RecastGraph.BuildTileMesh (Pathfinding.Voxels.Voxelize vox, Int32 x, Int32 z) (at Assets/AstarPathfindingProject/Generators/RecastGenerator.cs:1477) Pathfinding.RecastGraph.ScanAllTiles (.OnScanStatus statusCallback) (at Assets/AstarPathfindingProject/Generators/RecastGenerator.cs:1293) Pathfinding.RecastGraph.ScanTiledNavmesh (.OnScanStatus statusCallback) (at Assets/AstarPathfindingProject/Generators/RecastGenerator.cs:1202) Pathfinding.RecastGraph.ScanInternal (.OnScanStatus statusCallback) (at Assets/AstarPathfindingProject/Generators/RecastGenerator.cs:1192) AstarPath.ScanLoop (.OnScanStatus statusCallback) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:1827) AstarPathEditor.MenuScan () (at Assets/AstarPathfindingProject/Editor/AstarPathEditor.cs:2429) UnityEditor.DockArea:OnGUI()
Also, with scan broken I cannot verify in 3.5.2, but in 3.5.1 NavMeshCut only cut the first graph, it should cut all of them.
Something is weird, even after reverting the code, the error persisted. Had to redo my graphs to get it to work. Maybe the new version would also work after recreating the graph settings, I’ll try that.
I found the source of the error, after upgrading the optimization ASTAR_MORE_AREAS is turned back on. I have disabled it as I need more graphs, and now it works. A graph number check and a popup could be usefull on scan.
The NavmeshCut still only cuts the first graph, how can I make it cut every graph?
Hi
@Keckske85
Yeah, that’s because the optimizations are stored in the scripts themselves as commented or uncommented #define statements, so if the scripts are upgraded, they will be reset to the default value.
I made the optimizations tab before the Player Settings -> Scripting Define Symbols field existed, if you want them to be preserved, you should add “ASTAR_MORE_AREAS” to that field instead.
That is only cuts a single graph is a limitation of the TileHandlerHelper script, it only grabs the first recast graph that it finds. If you want to support multiple graphs, you need to do something like this:
public void Start () { foreach (RecastGraph g in AstarPath.active.astarData.FindGraphsOfType(typeof(RecastGraph))) { var helper = gameObject.AddComponent<TileHandlerHelper>(); var handler = new TileHandler(g); handler.CreateTileTypesFromGraph(); helper.UseSpecifiedHandler (handler); } }
Ideally I would make the TileHandlerHelper support multiple graphs.
Any chance you can squeeze that in the next update? I could wait for a few months for the official feature.
For the time being I made this:
`using UnityEngine;
using System.Collections;
using Pathfinding;
using Pathfinding.Util;
using System.Collections.Generic;
public class MultiTileHandlerHelper : MonoBehaviour
{
protected new List handlers;
/** How often to check if an update needs to be done (real seconds between checks).
* For very large worlds with lots of NavmeshCut objects, it might be a performance penalty to do this check every frame.
* If you think this is a performance penalty, increase this number to check less often.
*
* For almost all games, this can be kept at 0.
*
* If negative, no updates will be done. They must be manually triggered using #ForceUpdate
*/
public float updateInterval = 0;
float lastUpdateTime = -999;
List<Bounds> forcedReloadBounds = new List<Bounds>();
void OnEnable()
{
NavmeshCut.OnDestroyCallback += HandleOnDestroyCallback;
}
void OnDisable()
{
NavmeshCut.OnDestroyCallback -= HandleOnDestroyCallback;
}
public void DiscardPending()
{
List<NavmeshCut> cuts = NavmeshCut.GetAll();
for (int i = 0; i < cuts.Count; i++)
{
if (cuts[i].RequiresUpdate())
{
cuts[i].NotifyUpdated();
}
}
}
void Start()
{
if (FindObjectsOfType(typeof(TileHandlerHelper)).Length > 1)
{
Debug.LogError("There should only be one TileHandlerHelper per scene. Destroying.");
Destroy(this);
return;
}
if (FindObjectsOfType(typeof(MultiTileHandlerHelper)).Length > 1)
{
Debug.LogError("There should only be one TileHandlerHelper per scene. Destroying.");
Destroy(this);
return;
}
handlers = new List<TileHandler>();
foreach (RecastGraph g in AstarPath.active.astarData.FindGraphsOfType(typeof(RecastGraph)))
{
var handler = new TileHandler(g);
handler.CreateTileTypesFromGraph();
handlers.Add(handler);
}
if (handlers.Count == 0)
{
if (AstarPath.active == null || AstarPath.active.astarData.recastGraph == null)
{
Debug.LogWarning("No AstarPath object in the scene or no RecastGraph on that AstarPath object");
}
}
}
/** Called when a NavmeshCut is destroyed */
void HandleOnDestroyCallback(NavmeshCut obj)
{
forcedReloadBounds.Add(obj.LastBounds);
lastUpdateTime = -999;
}
/** Update is called once per frame */
void Update()
{
if (updateInterval == -1 || Time.realtimeSinceStartup - lastUpdateTime < updateInterval || handlers == null || handlers.Count == 0)
{
return;
}
ForceUpdate();
}
/** Checks all NavmeshCut instances and updates graphs if needed */
public void ForceUpdate()
{
if (handlers == null || handlers.Count == 0)
{
throw new System.Exception("Cannot update graphs. No TileHandler. Do not call this method in Awake.");
}
lastUpdateTime = Time.realtimeSinceStartup;
List<NavmeshCut> cuts = NavmeshCut.GetAll();
if (forcedReloadBounds.Count == 0)
{
int any = 0;
for (int i = 0; i < cuts.Count; i++)
{
if (cuts[i].RequiresUpdate())
{
any++;
break;
}
}
// Nothing needs to be done for now
if (any == 0) return;
}
foreach (TileHandler handler in handlers)
{
bool end = handler.StartBatchLoad();
//Debug.Log ("Updating...");
for (int i = 0; i < forcedReloadBounds.Count; i++)
{
handler.ReloadInBounds(forcedReloadBounds[i]);
}
forcedReloadBounds.Clear();
for (int i = 0; i < cuts.Count; i++)
{
if (cuts[i].enabled)
{
if (cuts[i].RequiresUpdate())
{
handler.ReloadInBounds(cuts[i].LastBounds);
handler.ReloadInBounds(cuts[i].GetBounds());
}
}
else if (cuts[i].RequiresUpdate())
{
handler.ReloadInBounds(cuts[i].LastBounds);
}
}
if (end) handler.EndBatchLoad();
}
for (int i = 0; i < cuts.Count; i++)
{
if (cuts[i].RequiresUpdate())
{
cuts[i].NotifyUpdated();
}
}
}
}
`