public void MoveTowards(Vector3 vMoveToTarget) { if (FunkyGame.Hero.Class == null) { Logger.DBLog.InfoFormat("Bot did not properly initilize, stopping bot!"); BotMain.Stop(false, "Bot Init Failure"); return; } #region LogStucks // The below code is to help profile/routine makers avoid waypoints with a long distance between them. // Long-distances between waypoints is bad - it increases stucks, and forces the DB nav-server to be called. //if (vLastMoveTo==Vector3.Zero) vLastMoveTo=vMoveToTarget; if (vMoveToTarget != vLastMoveTo) { vLastMoveTo = vMoveToTarget; if (FunkyBaseExtension.Settings.Debugging.LogStuckLocations) { vLastMoveTo = vMoveToTarget; bLastWaypointWasTown = false; float fDistance = Vector3.Distance(vMoveToTarget, vLastMoveTo); // Logger.DBLog.InfoFormat if not in town, last waypoint wasn't FROM town, and the distance is >200 but <2000 (cos 2000+ probably means we changed map zones!) if (!ZetaDia.IsInTown && !bLastWaypointWasTown && fDistance >= 200 & fDistance <= 2000) { if (!hashDoneThisVector.Contains(vMoveToTarget)) { // Logger.DBLog.InfoFormat it string outputPath = FolderPaths.LoggingFolderPath + @"\Stucks.log"; FileStream LogStream = File.Open(outputPath, FileMode.Append, FileAccess.Write, FileShare.Read); using (StreamWriter LogWriter = new StreamWriter(LogStream)) { LogWriter.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture) + ":"); LogWriter.WriteLine("Profile Name=" + ProfileManager.CurrentProfile.Name); LogWriter.WriteLine("'From' Waypoint=" + vLastMoveTo + ". 'To' Waypoint=" + vMoveToTarget + ". Distance=" + fDistance.ToString(CultureInfo.InvariantCulture)); } //LogStream.Close(); hashDoneThisVector.Add(vMoveToTarget); } } } if (ZetaDia.IsInTown) { bLastWaypointWasTown = true; } } #endregion // Make sure GilesTrinity doesn't want us to avoid routine-movement if (FunkyGame.Targeting.Cache.DontMove) { return; } // Store player current position Vector3 vMyCurrentPosition = ZetaDia.Me.Position; //Check GPC entry (backtracking cache) -- only when not in town! if (BackTrackCache.EnableBacktrackGPRcache && !ZetaDia.IsInTown) { if (DateTime.Now.Subtract(LastCombatPointChecked).TotalMilliseconds > 1250) { if (BackTrackCache.cacheMovementGPRs.Count == 0) { BackTrackCache.StartNewGPR(vMyCurrentPosition); } else { //Add new point only if distance is 25f difference if (BackTrackCache.cacheMovementGPRs.Count == 1) { if (BackTrackCache.cacheMovementGPRs[0].CreationVector.Distance(vMyCurrentPosition) >= BackTrackCache.MinimumRangeBetweenMovementGPRs) { BackTrackCache.StartNewGPR(vMyCurrentPosition); } } else { //Only if no GPCs currently are less than 20f from us.. if (!BackTrackCache.cacheMovementGPRs.Any(GPC => GPC.CreationVector.Distance(vMyCurrentPosition) < BackTrackCache.MinimumRangeBetweenMovementGPRs)) { BackTrackCache.StartNewGPR(vMyCurrentPosition); } } } //Reset Timer LastCombatPointChecked = DateTime.Now; } } //Special cache for skipping locations visited. //if (FunkyBaseExtension.Settings.Debugging.SkipAhead) //{ // SkipAheadCache.RecordSkipAheadCachePoint(); // //Check if our current profile behavior is ExploreDungeon tag. // if (FunkyGame.Profile.CurrentProfileBehaviorType == Profile.ProfileBehaviorTypes.ExploreDungeon) //&& !SkipAheadCache.LevelAreaIDsIgnoreSkipping.Contains(FunkyGame.Hero.iCurrentLevelID)) // { // //Check if DungeonExplorer and Current Node are valid. (only when there is more than one node in current route) // if (Navigation.CurrentDungeonExplorer != null && Navigation.DungeonExplorerCurrentNode != null && Navigation.CurrentDungeonExplorer.CurrentRoute.Count > 1) // { // if (Navigation.NP.CurrentPath != null && Navigation.NP.CurrentPath.Count > 0) // { // var destination = Navigation.NP.CurrentPath.Last(); // float distance = destination.Distance2D(Navigation.DungeonExplorerCurrentNode.NavigableCenter); // //Logger.DBLog.InfoFormat("[Funky] Distance from CurrentNode Center == {0}", distance); // if (distance <= 5f) // { // //Check if our target position is within skip ahead cache. // if (SkipAheadCache.CheckPositionForSkipping(destination)) // { // Logger.DBLog.Info("[Funky] Marking Node as Visited! (PlayerMover)"); // Logger.DBLog.DebugFormat("[Funky] {0}", Navigation.PrintDungeonExplorerNode(Navigation.DungeonExplorerCurrentNode)); // Navigation.DungeonExplorerCurrentNode.Visited = true; // } // } // } // } // } //} // Store distance to current moveto target float fDistanceFromTarget; #region Unstucker // Do unstuckery things if (FunkyBaseExtension.Settings.Debugging.EnableUnstucker) { // Store the "real" (not anti-stuck) destination vOldMoveToTarget = vMoveToTarget; // See if we can reset the 10-limit unstuck counter, if >120 seconds since we last generated an unstuck location if (iTotalAntiStuckAttempts > 1 && DateTime.Now.Subtract(timeStartedUnstuckMeasure).TotalSeconds >= 120) { iTotalAntiStuckAttempts = 1; iTimesReachedStuckPoint = 0; vSafeMovementLocation = Vector3.Zero; } // See if we need to, and can, generate unstuck actions if (DateTime.Now.Subtract(timeCancelledUnstuckerFor).TotalSeconds > iCancelUnstuckerForSeconds && UnstuckChecker(vMyCurrentPosition)) { // Record the time we last apparently couldn't move for a brief period of time timeLastReportedAnyStuck = DateTime.Now; // See if there's any stuck position to try and navigate to generated by random mover vSafeMovementLocation = UnstuckHandler(vMyCurrentPosition, vOldMoveToTarget); if (vSafeMovementLocation == Vector3.Zero) { return; } } // See if we can clear the total unstuckattempts if we haven't been stuck in over 6 minutes. if (DateTime.Now.Subtract(timeLastReportedAnyStuck).TotalSeconds >= 360) { iTimesReachedMaxUnstucks = 0; } // Did we have a safe point already generated (eg from last loop through), if so use it as our current location instead if (vSafeMovementLocation != Vector3.Zero) { // Set our current movement target to the safe point we generated last cycle vMoveToTarget = vSafeMovementLocation; } // Get distance to current destination fDistanceFromTarget = Vector3.Distance(vMyCurrentPosition, vMoveToTarget); // Remove the stuck position if it's been reached, this bit of code also creates multiple stuck-patterns in an ever increasing amount if (vSafeMovementLocation != Vector3.Zero && fDistanceFromTarget <= 3f) { vSafeMovementLocation = Vector3.Zero; iTimesReachedStuckPoint++; // Do we want to immediately generate a 2nd waypoint to "chain" anti-stucks in an ever-increasing path-length? if (iTimesReachedStuckPoint <= iTotalAntiStuckAttempts) { FunkyGame.Navigation.AttemptFindSafeSpot(out vSafeMovementLocation, Vector3.Zero, FunkyBaseExtension.Settings.Plugin.AvoidanceFlags); vMoveToTarget = vSafeMovementLocation; } else { Logger.DBLog.DebugFormat("[Funky] Clearing old route and trying new path find to: " + vOldMoveToTarget.ToString()); // Reset the path and allow a whole "New" unstuck generation next cycle iTimesReachedStuckPoint = 0; // And cancel unstucking for 9 seconds so DB can try to navigate iCancelUnstuckerForSeconds = (9 * iTotalAntiStuckAttempts); if (iCancelUnstuckerForSeconds < 20) { iCancelUnstuckerForSeconds = 20; } timeCancelledUnstuckerFor = DateTime.Now; Navigator.Clear(); Navigator.MoveTo(vOldMoveToTarget, "original destination", false); return; } } } #endregion //Prioritize "blocking" objects. if (!FunkyGame.Hero.bIsInTown) { FunkyGame.Navigation.ObstaclePrioritizeCheck(); } #region MovementAbilities // See if we can use abilities like leap etc. for movement out of combat, but not in town and only if we can raycast. if (FunkyBaseExtension.Settings.General.OutOfCombatMovement && !ZetaDia.IsInTown && !FunkyGame.IsInNonCombatBehavior) { Skill MovementPower; Vector3 MovementVector = FunkyGame.Hero.Class.FindOutOfCombatMovementPower(out MovementPower, vMoveToTarget); if (MovementVector != Vector3.Zero) { ZetaDia.Me.UsePower(MovementPower.Power, MovementVector, FunkyGame.Hero.CurrentWorldDynamicID); MovementPower.OnSuccessfullyUsed(); return; } } // Allowed to use movement powers to move out-of-combat? #endregion //Send Movement Command! if (vMyCurrentPosition.Distance2D(vMoveToTarget) > 1f) { ZetaDia.Me.UsePower(SNOPower.Walk, vMoveToTarget, FunkyGame.Hero.CurrentWorldDynamicID); } }