Update graph in partial

Hi
In the runtime how to update graph partial when I place a cube on the ground.

Hi there,

You have a number of options here depending on your needs and current set-up. Check out this section of the documentation for more information. If you need help choosing between these implementations or adding them to your project, let us know :slight_smile:

Hi
Thank you for your suggest, but this can‘t deal problem, i afraid.
As fact, i use GridGraph.GridGraphUpdatePromise and set param rect to achieve this function.
But a bug has appeared when simultaneously execute GridGraphUpdatePromise and GridGraphMovePromise.
Look at the picture, one cube doesn’t scan successful.
PS: i use ProceduralGraphMover to update graph when role moving, player are placed cube while running.

Hi

You must not execute those two promises concurrently. They must be executed sequentially.
Keep in mind that these are pretty low level primitives. Usually you use the much higher level primitives which take care of this for you.

Hi
Thank you. According to your proposal for modification, but there is still this bug present.
This is my code, can you help me find error?

public class GridNavGraphUpdater : SerializedMonoBehaviour
	{
		#region MoverUpdate
		
		public float updateDistance = 10;
		public Transform target;
		public LayerGridGraph layerGridGraph;		// Land
		public GridGraph gridGraph;					// SeaBed

		void Update () 
		{
			if (layerGridGraph != null)
			{
				var graphCenterInGraphSpace = layerGridGraph.transform.InverseTransform(layerGridGraph.center);
				var targetPositionInGraphSpace = layerGridGraph.transform.InverseTransform(target.position);
				
				var dis = VectorMath.SqrDistanceXZ(graphCenterInGraphSpace, targetPositionInGraphSpace);
				if (dis > updateDistance * updateDistance && GraphUpdating == false)
				{
					UpdateGridGraph(layerGridGraph, true);
				}
			}
			
			if (gridGraph != null)
			{
				var graphCenterInGraphSpace = gridGraph.transform.InverseTransform(gridGraph.center);
				var targetPositionInGraphSpace = gridGraph.transform.InverseTransform(target.position);

				var dis = VectorMath.SqrDistanceXZ(graphCenterInGraphSpace, targetPositionInGraphSpace);
				if (dis > updateDistance * updateDistance && GraphUpdating == false)
				{
					UpdateGridGraph(gridGraph, true);
				}
			}
		}
		
		void UpdateGridGraph (GridGraph graph, bool async) {
			// Start a work item for updating the graph
			// This will pause the pathfinding threads
			// so that it is safe to update the graph
			// and then do it over several frames
			// to avoid too large FPS drops

			GraphUpdating = true;
			List<(IGraphUpdatePromise, IEnumerator<JobHandle>)> promises = new List<(IGraphUpdatePromise, IEnumerator<JobHandle>)>();
			AstarPath.active.AddWorkItem(new AstarWorkItem(
				ctx => {
					// Find the direction that we want to move the graph in.
					// Calculate this in graph space (where a distance of one is the size of one node)
					Vector3 dir = graph.transform.InverseTransformVector(target.position - graph.center);

					// Snap to a whole number of nodes to offset in each direction
					int dx = Mathf.RoundToInt(dir.x);
					int dz = Mathf.RoundToInt(dir.z);

					if (dx != 0 || dz != 0) {
						var promise = graph.TranslateInDirection(dx, dz);
						promises.Add((promise, promise.Prepare()));
					}
				},
				(ctx, force) => {
					if (GraphUpdateProcessor.ProcessGraphUpdatePromises(promises, ctx, force)) {
						GraphUpdating = false;
						return true;
					}
					return false;
				}
			));
			if (!async) AstarPath.active.FlushWorkItems();
		}
		
		#endregion

		#region PartialUpdate
		
		private struct PartialUpdateInfo
		{
			public int xmin;
			public int xmax;
			public int zmin;
			public int zmax;
		}
		private List<PartialUpdateInfo> infoList = new List<PartialUpdateInfo>();
		public static bool GraphUpdating { get; private set; }

		public void LateUpdate()
		{
			if (GraphUpdating == false && infoList.Count > 0)
			{
				var info = infoList[0];
				UpdateGraphPartial(info.xmin, info.xmax, info.zmin, info.zmax);
				infoList.RemoveAt(0);
			}
		}

		public void UpdateAreaRect(Vector3 min, Vector3 max)
        {
	        if(layerGridGraph == null)
		        return;
            var gmin = layerGridGraph.transform.InverseTransform(min);
            var gmax = layerGridGraph.transform.InverseTransform(max);
            var xmin = Mathf.Clamp(Mathf.CeilToInt(gmin.x), 0, layerGridGraph.width - 1);
            var xmax = Mathf.Clamp(Mathf.CeilToInt(gmax.x), 0, layerGridGraph.width - 1);
            var zmin = Mathf.Clamp(Mathf.CeilToInt(gmin.z), 0, layerGridGraph.depth - 1);
            var zmax = Mathf.Clamp(Mathf.CeilToInt(gmax.z), 0, layerGridGraph.depth - 1);
            infoList.Add(new PartialUpdateInfo()
            {
	            xmax = xmax,
	            xmin = xmin,
	            zmax = zmax,
	            zmin = zmin,
            });
        }

        public void UpdateAreaAll()
        {
	        infoList.Add(new PartialUpdateInfo()
	        {
		        xmax = layerGridGraph.width,
		        xmin = 0,
		        zmax = layerGridGraph.depth,
		        zmin = 0,
	        });
        }

        public void UpdateGraphPartial(int xmin, int xmax, int zmin, int zmax)
        {
	        if (layerGridGraph.nodes == null || layerGridGraph.nodes.Length != layerGridGraph.width * layerGridGraph.depth * layerGridGraph.LayerCount)
				return;
	        GraphUpdating = true;
			List<(IGraphUpdatePromise, IEnumerator<JobHandle>)> promises = new List<(IGraphUpdatePromise, IEnumerator<JobHandle>)>();
			AstarPath.active.AddWorkItem(new AstarWorkItem(
				ctx =>
				{
					var nodes = new GridGraph.GridGraphUpdatePromise.NodesHolder { nodes = layerGridGraph.nodes };
					var dependencyTracker = ObjectPool<Pathfinding.Jobs.JobDependencyTracker>.Claim();
					var recalculationMode = GridGraph.RecalculationMode.RecalculateMinimal;
					var promise = new GridGraph.GridGraphUpdatePromise(
						graph: layerGridGraph,
						transform: layerGridGraph.transform,
						nodes: nodes,
						nodeArrayBounds: new int3(layerGridGraph.width, layerGridGraph.LayerCount, layerGridGraph.depth),
						rect: new IntRect(xmin, zmin, xmax, zmax),
						dependencyTracker: dependencyTracker,
						nodesDependsOn: default,
						allocationMethod: Allocator.Persistent,
						recalculationMode: recalculationMode,
						graphUpdateObject: null,
						ownsJobDependencyTracker: true
					);
					promises.Add((promise, promise.Prepare()));
				},
				(context, force) =>
				{
					if (GraphUpdateProcessor.ProcessGraphUpdatePromises(promises, context, force)) {
						GraphUpdating = false;
						return true;
					}
					return false;
				}));
        }
        #endregion
	}

Not quite sure, but I do know your code can be greatly simplified. Your partial graph update code can basically be simplified to:

var gridGraph = AstarPath.active.data.gridGraph;
AstarPath.active.UpdateGraphs(gridGraph.GetBoundsFromRect(...rect));

Oh Thank you !
I didn’t actually notice this func.