/// <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;
        }
Пример #3
0
        /** 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();
            }
        }
Пример #4
0
 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);
             }
         }
     }
 }
Пример #5
0
        /** 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;
        }
Пример #8
0
	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);
        }