Esempio n. 1
0
        /// <summary>
        /// Calculates the distance between START and DESTINATION if the travel must be conducted
        /// over a surface (i.e., instead of flying).  This is most helpful in tunnels where a mob
        /// can be within X feet of you, but above or below you.  For such mobs, the direct distance
        /// is X feet, but the path you must take through the tunnels may be much much longer.
        /// </summary>
        /// <param name="start"></param>
        /// <param name="destination"></param>
        /// <returns></returns>
        /// <remarks>17Apr2011-12:16UTC chinajade</remarks>
        public static float SurfacePathDistance(this WoWPoint start, WoWPoint destination)
        {
            float pathDistance;

            if (SurfacePathDistanceCache.TryGet(start, destination, out pathDistance))
            {
                return(pathDistance);
            }

            var groundPath = new WoWPoint[] { };

            bool canFullyNavigate;

            // Note: Use the Navigate.GeneratePath that outs a 'isPartial' boolean once it's available.
            var meshNavigator = Navigator.NavigationProvider as MeshNavigator;

            if (meshNavigator != null)
            {
                var pathResult = meshNavigator.Nav.FindPath(start, destination);
                canFullyNavigate = pathResult.Succeeded && !pathResult.IsPartialPath;

                if (canFullyNavigate)
                {
                    groundPath = pathResult.Points.Select(v => (WoWPoint)v).ToArray();
                }
            }
            else
            {
                groundPath       = Navigator.GeneratePath(start, destination) ?? new WoWPoint[0];
                canFullyNavigate = groundPath.Length > 0;
            }

            if (!canFullyNavigate || groundPath.Length <= 0)
            {
                SurfacePathDistanceCache.Add(start, destination, float.NaN);
                return(float.NaN);
            }


            // Include distance it takes us to get from start point to first point in path...
            pathDistance = start.Distance(groundPath[0]);

            // Include distance it takes us to get from last point in path to destination...
            pathDistance += groundPath[groundPath.Length - 1].Distance(destination);

            // Include distance for each point in path...
            for (int i = 0; i < (groundPath.Length - 1); ++i)
            {
                pathDistance += groundPath[i].Distance(groundPath[i + 1]);
            }

            // Sanity check...
            Contract.Provides(
                pathDistance >= start.Distance(destination),
                context => "Surface path distance must be equal to or greater than straight-line distance.");

            SurfacePathDistanceCache.Add(start, destination, pathDistance);
            return(pathDistance);
        }
Esempio n. 2
0
            /// <summary>
            /// Tries to find a cached surface path distance between the start/destination pair and returns <c>true</c> if successful
            /// </summary>
            /// <param name="start">The start.</param>
            /// <param name="destination">The destination.</param>
            /// <param name="distance">The surface path distance, zero if no cache found or NaN if no path could be fully generated</param>
            /// <returns><c>true</c> if a cache was found, <c>false</c> otherwise.</returns>
            internal static bool TryGet(WoWPoint start, WoWPoint destination, out float distance)
            {
                SurfacePathDistanceCache match = null;
                var now = DateTime.Now;

                // do we need to cleanup old caches?
                var doCleanup = now - s_lastCleanupTime > s_maxCacheTimeSpan;

                // iterate the path cache in revere so we can remove entries safely
                for (int idx = s_pathDistanceCache.Count - 1; idx >= 0; idx--)
                {
                    var entry = s_pathDistanceCache[idx];
                    // check if we need the entry
                    if (doCleanup && now - entry.TimeStamp > s_maxCacheTimeSpan)
                    {
                        s_pathDistanceCache.RemoveAt(idx);
                        continue;
                    }
                    // check if we have a match
                    if (match == null && Navigator.AtLocation(start, entry.Start) && Navigator.AtLocation(destination, entry.Destination))
                    {
                        match = entry;
                        // exit for loop now if not doing a cleanup pass
                        if (!doCleanup)
                        {
                            break;
                        }
                    }
                }


                if (doCleanup)
                {
                    s_lastCleanupTime = now;
                }

                if (match == null)
                {
                    distance = 0;
                    return(false);
                }

                distance = match.Distance;
                return(true);
            }