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);
}