/// <summary> /// Graph update thread. /// Async graph updates will be executed by this method in another thread. /// </summary> void ProcessGraphUpdatesAsync() { #if UNITY_2017_3_OR_NEWER Profiler.BeginThreadProfiling("Pathfinding", "Threaded Graph Updates"); #endif var handles = new [] { graphUpdateAsyncEvent, exitAsyncThread }; while (true) { // Wait for the next batch or exit event var handleIndex = WaitHandle.WaitAny(handles); if (handleIndex == 1) { // Exit even was fired // Abort thread and clear queue while (graphUpdateQueueAsync.Count > 0) { var s = graphUpdateQueueAsync.Dequeue(); s.obj.internalStage = GraphUpdateObject.STAGE_ABORTED; } asyncGraphUpdatesComplete.Set(); #if UNITY_2017_3_OR_NEWER Profiler.EndThreadProfiling(); #endif return; } while (graphUpdateQueueAsync.Count > 0) { #if UNITY_2017_3_OR_NEWER asyncUpdateProfilingSampler.Begin(); #endif // Note that no locking is required here because the main thread // cannot access it until asyncGraphUpdatesComplete is signaled GUOSingle aguo = graphUpdateQueueAsync.Dequeue(); try { if (aguo.order == GraphUpdateOrder.GraphUpdate) { aguo.graph.UpdateArea(aguo.obj); graphUpdateQueuePost.Enqueue(aguo); } else { throw new System.NotSupportedException("" + aguo.order); } } catch (System.Exception e) { Debug.LogError("Exception while updating graphs:\n" + e); } #if UNITY_2017_3_OR_NEWER asyncUpdateProfilingSampler.End(); #endif } // Done asyncGraphUpdatesComplete.Set(); } }
/// <summary>Schedules graph updates internally</summary> void QueueGraphUpdatesInternal() { while (graphUpdateQueue.Count > 0) { GraphUpdateObject ob = graphUpdateQueue.Dequeue(); if (ob.internalStage != GraphUpdateObject.STAGE_PENDING) { Debug.LogError("Expected remaining graph updates to be pending"); continue; } ob.internalStage = 0; foreach (IUpdatableGraph g in astar.data.GetUpdateableGraphs()) { NavGraph gr = g as NavGraph; if (ob.nnConstraint == null || ob.nnConstraint.SuitableGraph(astar.data.GetGraphIndex(gr), gr)) { var guo = new GUOSingle(); guo.order = GraphUpdateOrder.GraphUpdate; guo.obj = ob; guo.graph = g; ob.internalStage += 1; graphUpdateQueueRegular.Enqueue(guo); } } } GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate); anyGraphUpdateInProgress = true; }
/** Graph update thread. * Async graph updates will be executed by this method in another thread. */ void ProcessGraphUpdatesAsync() { var handles = new[] { graphUpdateAsyncEvent, exitAsyncThread }; while (true) { // Wait for the next batch or exit event var handleIndex = WaitHandle.WaitAny(handles); if (handleIndex == 1) { // Exit even was fired // Abort thread and clear queue graphUpdateQueueAsync.Clear(); asyncGraphUpdatesComplete.Set(); return; } while (graphUpdateQueueAsync.Count > 0) { // Note that no locking is required here because the main thread // cannot access it until asyncGraphUpdatesComplete is signaled GUOSingle aguo = graphUpdateQueueAsync.Dequeue(); try { if (aguo.order == GraphUpdateOrder.GraphUpdate) { aguo.graph.UpdateArea(aguo.obj); graphUpdateQueuePost.Enqueue(aguo); } else if (aguo.order == GraphUpdateOrder.FloodFill) { FloodFill(); } else { throw new System.NotSupportedException("" + aguo.order); } } catch (System.Exception e) { Debug.LogError("Exception while updating graphs:\n" + e); } } // Done asyncGraphUpdatesComplete.Set(); } }
void ProcessPostUpdates() { while (graphUpdateQueuePost.Count > 0) { GUOSingle s = graphUpdateQueuePost.Dequeue(); GraphUpdateThreading threading = s.graph.CanUpdateAsync(s.obj); if ((threading & GraphUpdateThreading.UnityPost) != 0) { try { s.graph.UpdateAreaPost(s.obj); } catch (System.Exception e) { Debug.LogError("Error while updating graphs (post step)\n" + e); } } } }
/** Schedules graph updates internally */ void QueueGraphUpdatesInternal() { bool anyRequiresFloodFill = false; while (graphUpdateQueue.Count > 0) { GraphUpdateObject ob = graphUpdateQueue.Dequeue(); if (ob.requiresFloodFill) { anyRequiresFloodFill = true; } foreach (IUpdatableGraph g in astar.data.GetUpdateableGraphs()) { NavGraph gr = g as NavGraph; if (ob.nnConstraint == null || ob.nnConstraint.SuitableGraph(astar.data.GetGraphIndex(gr), gr)) { var guo = new GUOSingle { order = GraphUpdateOrder.GraphUpdate, obj = ob, graph = g }; graphUpdateQueueRegular.Enqueue(guo); } } } if (anyRequiresFloodFill) { var guo = new GUOSingle { order = GraphUpdateOrder.FloodFill }; graphUpdateQueueRegular.Enqueue(guo); } GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate); anyGraphUpdateInProgress = true; }
/// <summary>Schedules graph updates internally</summary> private void QueueGraphUpdatesInternal() { while (graphUpdateQueue.Count > 0) { GraphUpdateObject ob = graphUpdateQueue.Dequeue(); foreach (IUpdatableGraph g in astar.data.GetUpdateableGraphs()) { NavGraph gr = g as NavGraph; if (ob.nnConstraint == null || ob.nnConstraint.SuitableGraph(astar.data.GetGraphIndex(gr), gr)) { var guo = new GUOSingle(); guo.order = GraphUpdateOrder.GraphUpdate; guo.obj = ob; guo.graph = g; graphUpdateQueueRegular.Enqueue(guo); } } } GraphModifier.TriggerEvent(GraphModifier.EventType.PreUpdate); anyGraphUpdateInProgress = true; }
/// <summary>Schedules graph updates internally</summary> void QueueGraphUpdatesInternal(IWorkItemContext context) { while (graphUpdateQueue.Count > 0) { GraphUpdateObject ob = graphUpdateQueue.Dequeue(); foreach (IUpdatableGraph g in astar.data.GetUpdateableGraphs()) { NavGraph gr = g as NavGraph; if (ob.nnConstraint == null || ob.nnConstraint.SuitableGraph(astar.data.GetGraphIndex(gr), gr)) { var guo = new GUOSingle(); guo.order = GraphUpdateOrder.GraphUpdate; guo.obj = ob; guo.graph = g; graphUpdateQueueRegular.Enqueue(guo); context.SetGraphDirty(gr); } } } context.PreUpdate(); anyGraphUpdateInProgress = true; }
private void QueueGraphUpdatesInternal () { isRegisteredForUpdate = false; bool anyRequiresFloodFill = false; while (graphUpdateQueue.Count > 0) { GraphUpdateObject ob = graphUpdateQueue.Dequeue (); if (ob.requiresFloodFill) anyRequiresFloodFill = true; foreach (IUpdatableGraph g in astarData.GetUpdateableGraphs ()) { NavGraph gr = g as NavGraph; if (ob.nnConstraint == null || ob.nnConstraint.SuitableGraph (active.astarData.GetGraphIndex (gr),gr)) { GUOSingle aguo = new GUOSingle (); aguo.order = GraphUpdateOrder.GraphUpdate; aguo.obj = ob; aguo.graph = g; graphUpdateQueueRegular.Enqueue (aguo); } } } if (anyRequiresFloodFill) { GUOSingle guo = new GUOSingle(); guo.order = GraphUpdateOrder.FloodFill; graphUpdateQueueRegular.Enqueue (guo); } //Nodes might have been invalidated and then the debugPathData could lead to nodes being used which have been invalidated //This could in the long run lead to exceptions debugPath = null; GraphModifier.TriggerEvent (GraphModifier.EventType.PreUpdate); }
/** Schedules graph updates internally */ void QueueGraphUpdatesInternal () { bool anyRequiresFloodFill = false; while (graphUpdateQueue.Count > 0) { GraphUpdateObject ob = graphUpdateQueue.Dequeue (); if (ob.requiresFloodFill) anyRequiresFloodFill = true; foreach (IUpdatableGraph g in astar.astarData.GetUpdateableGraphs ()) { NavGraph gr = g as NavGraph; if (ob.nnConstraint == null || ob.nnConstraint.SuitableGraph (astar.astarData.GetGraphIndex (gr),gr)) { var guo = new GUOSingle (); guo.order = GraphUpdateOrder.GraphUpdate; guo.obj = ob; guo.graph = g; graphUpdateQueueRegular.Enqueue (guo); } } } if (anyRequiresFloodFill) { var guo = new GUOSingle(); guo.order = GraphUpdateOrder.FloodFill; graphUpdateQueueRegular.Enqueue (guo); } GraphModifier.TriggerEvent (GraphModifier.EventType.PreUpdate); }
private bool ProcessRegularUpdates(bool force) { while (graphUpdateQueueRegular.Count > 0) { GUOSingle s = graphUpdateQueueRegular.Peek(); GraphUpdateThreading threading = s.graph.CanUpdateAsync(s.obj); #if UNITY_WEBGL // Never use multithreading in WebGL threading &= ~GraphUpdateThreading.SeparateThread; #else // When not playing or when not using a graph update thread (or if it has crashed), everything runs in the Unity thread if (force || !Application.isPlaying || graphUpdateThread == null || !graphUpdateThread.IsAlive) { // Remove the SeparateThread flag threading &= ~GraphUpdateThreading.SeparateThread; } #endif if ((threading & GraphUpdateThreading.UnityInit) != 0) { // Process async graph updates first. // Next call to this function will process this object so it is not dequeued now if (StartAsyncUpdatesIfQueued()) { return(false); } s.graph.UpdateAreaInit(s.obj); } if ((threading & GraphUpdateThreading.SeparateThread) != 0) { // Move GUO to async queue to be updated by another thread graphUpdateQueueRegular.Dequeue(); graphUpdateQueueAsync.Enqueue(s); // Don't start any more async graph updates because this update // requires a Unity thread function to run after it has been completed // but before the next update is started if ((threading & GraphUpdateThreading.UnityPost) != 0) { if (StartAsyncUpdatesIfQueued()) { return(false); } } } else { // Unity Thread if (StartAsyncUpdatesIfQueued()) { return(false); } graphUpdateQueueRegular.Dequeue(); try { s.graph.UpdateArea(s.obj); } catch (System.Exception e) { Debug.LogError("Error while updating graphs\n" + e); } if ((threading & GraphUpdateThreading.UnityPost) != 0) { s.graph.UpdateAreaPost(s.obj); } } } if (StartAsyncUpdatesIfQueued()) { return(false); } return(true); }
/** Updates graphs. * Will do some graph updates, possibly signal another thread to do them. * Will only process graph updates added by QueueGraphUpdatesInternal * * \param force If true, all graph updates will be processed before this function returns. The return value * will be True. * * \returns True if all graph updates have been done and pathfinding (or other tasks) may resume. * False if there are still graph updates being done or waiting in the queue. * * */ bool ProcessGraphUpdates(bool force) { if (force) { asyncGraphUpdatesComplete.WaitOne(); } else { #if !UNITY_WEBGL if (!asyncGraphUpdatesComplete.WaitOne(0)) { return(false); } #endif } if (graphUpdateQueueAsync.Count != 0) { throw new System.Exception("Queue should be empty at this stage"); } while (graphUpdateQueueRegular.Count > 0) { GUOSingle s = graphUpdateQueueRegular.Peek(); GraphUpdateThreading threading = s.order == GraphUpdateOrder.FloodFill ? GraphUpdateThreading.SeparateThread : s.graph.CanUpdateAsync(s.obj); #if !UNITY_WEBGL bool forceUnityThread = force; // When not playing or when not using a graph update thread (or if it has crashed), everything runs in the Unity thread if (!Application.isPlaying || graphUpdateThread == null || !graphUpdateThread.IsAlive) { forceUnityThread = true; } if (!forceUnityThread && (threading == GraphUpdateThreading.SeparateAndUnityInit)) { if (graphUpdateQueueAsync.Count > 0) { //Process async graph updates first. //Next call to this function will process this object so it is not dequeued now asyncGraphUpdatesComplete.Reset(); graphUpdateAsyncEvent.Set(); return(false); } s.graph.UpdateAreaInit(s.obj); //Move GUO to async queue to be updated by another thread graphUpdateQueueRegular.Dequeue(); graphUpdateQueueAsync.Enqueue(s); //Next call to this function will process this object so it is not dequeued now asyncGraphUpdatesComplete.Reset(); graphUpdateAsyncEvent.Set(); return(false); } else if (!forceUnityThread && (threading == GraphUpdateThreading.SeparateThread)) { //Move GUO to async queue to be updated by another thread graphUpdateQueueRegular.Dequeue(); graphUpdateQueueAsync.Enqueue(s); } else { #endif //Everything should be done in the unity thread if (graphUpdateQueueAsync.Count > 0) { //Process async graph updates first. if (force) { throw new System.Exception("This should not happen"); } //Next call to this function will process this object so it is not dequeued now asyncGraphUpdatesComplete.Reset(); graphUpdateAsyncEvent.Set(); return(false); } graphUpdateQueueRegular.Dequeue(); if (s.order == GraphUpdateOrder.FloodFill) { FloodFill(); } else { if (threading == GraphUpdateThreading.SeparateAndUnityInit) { try { s.graph.UpdateAreaInit(s.obj); } catch (System.Exception e) { Debug.LogError("Error while initializing GraphUpdates\n" + e); } } try { s.graph.UpdateArea(s.obj); } catch (System.Exception e) { Debug.LogError("Error while updating graphs\n" + e); } } #if !UNITY_WEBGL } #endif } #if !UNITY_WEBGL if (graphUpdateQueueAsync.Count > 0) { //Next call to this function will process this object so it is not dequeued now asyncGraphUpdatesComplete.Reset(); graphUpdateAsyncEvent.Set(); return(false); } #endif GraphModifier.TriggerEvent(GraphModifier.EventType.PostUpdate); if (OnGraphsUpdated != null) { OnGraphsUpdated(); } return(true); }