/// <summary> /// Finds the path. /// </summary> /// <param name="from">From.</param> /// <param name="to">To.</param> /// <param name="continentNameMpq">The continent name MPQ.</param> /// <param name="resultSuccess">if set to <c>true</c> [result success].</param> /// <param name="addFromAndStart">if set to <c>true</c> [add from and start].</param> /// <param name="loadAllTile"></param> /// <returns></returns> private static List <Point> FindPath(Point from, Point to, string continentNameMpq, out bool resultSuccess, bool addFromAndStart, bool loadAllTile, bool ShortPath, bool hideMe = false) { // Prevent Z modified with "GetZ" to be passed as reference to original points/lists. from = new Point(from); to = new Point(to); if (!hideMe) { // should be run only from the function that allow pathfinder patchwerk, nowhere else Logging.WriteError("FindPath: Error, accessed from unknown location."); } if (from.DistanceTo(to) <= 1f) { resultSuccess = true; return(new List <Point> { from, to }); } if (from.Type.ToLower() == "swimming") { if (TraceLine.TraceLineGo(new Point(to.X, to.Y, to.Z + 1000), to, Enums.CGWorldFrameHitFlags.HitTestLiquid)) { // The destination is in water if (!TraceLine.TraceLineGo(from, to)) { Logging.WriteNavigator("Swimmming right to the destination"); resultSuccess = true; return(new List <Point> { from, to }); } Logging.WriteNavigator("Swimming to the destination using the PathFinder"); } else { from.Z = GetZPosition(from); // get to the bottom of the ocean to avoid infinite 0 count path Logging.WriteNavigator("Using the PathFinder to destination out of water"); } } if (from.Type.ToLower() == "flying") { from.Z = GetZPosition(from); Logging.WriteNavigator("Using the PathFinder while flying"); } List <Point> locList = new List <Point>(); resultSuccess = true; try { if (!UsePatherFind || continentNameMpq == "None") { locList.Add(from); locList.Add(to); return(locList); } if (_pather == null) { _pather = new Pather(continentNameMpq); } if (_pather.Continent != continentNameMpq) { _pather.Dispose(); _pather = new Pather(continentNameMpq); } if (addFromAndStart) { locList.Add(from); } if (loadAllTile) { _pather.LoadAllTiles(); } bool failedPolyref; locList = ShortPath ? _pather.FindPathSimple(from, to, out resultSuccess, out failedPolyref, true) : _pather.FindPath(from, to, out resultSuccess, out failedPolyref); if (addFromAndStart && resultSuccess) { locList.Add(to); } if (!resultSuccess && failedPolyref) { /*Logging.WriteDebug("Reloading PathFinder..."); * _pather.Dispose(); * _pather = new Pather(continentNameMpq); * locList = ShortPath ? _pather.FindPathSimple(from, to, out resultSuccess, out failedPolyref, true) : _pather.FindPath(from, to, out resultSuccess, out failedPolyref); * if (addFromAndStart && resultSuccess) * locList.Add(to);*/ } // Clean list: for (int i = 0; i <= locList.Count - 2; i++) { if (locList[i].DistanceTo(locList[i + 1]) < 0.5 || !locList[i + 1].IsValid) { locList.RemoveAt(i + 1); i--; } } // Offset all points except origin and end to pass around obstacles by some distance. // We stop at 2.0 before each point in MovementManager and the meshes are done for a player of 0.6 in diameter. // So 2.0-0.6=1.4 is the strick minimum offset needed. Since 'click to point' has a precision of 0.5, // 1.4+0.5=1.9 is a pretty good value here. for (int i = locList.Count - 2; i > 0; i--) { Point offset = Helpful.Math.GetPositionOffsetBy3DDistance(locList[i - 1], locList[i], 1.9f); locList[i] = offset; } Logging.WriteNavigator("Path Count: " + locList.Count() + (resultSuccess ? "" : " but incomplete")); return(locList); } catch (Exception e) { Logging.WriteError("ToRecast(this Point v): PATH FIND ERROR: " + e); Console.WriteLine("Path find ERROR."); resultSuccess = false; locList = new List <Point>(); if (addFromAndStart) { if (from != null) { if (from.X != 0 || from.Y != 0 || from.Z != 0) { locList.Add(from); } } if (to != null) { if (to.X != 0 || to.Y != 0 || to.Z != 0) { locList.Add(to); } } } return(locList); } }