diff --git a/Core/GOAP/GoapAgentState.cs b/Core/GOAP/GoapAgentState.cs index 4f602414..f54c86dd 100644 --- a/Core/GOAP/GoapAgentState.cs +++ b/Core/GOAP/GoapAgentState.cs @@ -11,5 +11,6 @@ public sealed class GoapAgentState public int ConsumableCorpseCount { get; set; } public int LastCombatKillCount { get; set; } public bool Gathering { get; set; } - public LinkedList safeLocations = new LinkedList(); + + public Stack SafeLocations { get; } = new(); } diff --git a/Core/Goals/CombatGoal.cs b/Core/Goals/CombatGoal.cs index 9d7eed60..073f0f26 100644 --- a/Core/Goals/CombatGoal.cs +++ b/Core/Goals/CombatGoal.cs @@ -22,7 +22,6 @@ public sealed class CombatGoal : GoapGoal, IGoapEventListener private readonly CastingHandler castingHandler; private readonly IMountHandler mountHandler; private readonly CombatLog combatLog; - private readonly GoapAgentState goapAgentState; private float lastDirection; private float lastMinDistance; @@ -31,7 +30,7 @@ public sealed class CombatGoal : GoapGoal, IGoapEventListener public CombatGoal(ILogger logger, ConfigurableInput input, Wait wait, PlayerReader playerReader, StopMoving stopMoving, AddonBits bits, ClassConfiguration classConfiguration, ClassConfiguration classConfig, - CastingHandler castingHandler, CombatLog combatLog, GoapAgentState state, + CastingHandler castingHandler, CombatLog combatLog, IMountHandler mountHandler) : base(nameof(CombatGoal)) { @@ -48,8 +47,6 @@ public CombatGoal(ILogger logger, ConfigurableInput input, this.mountHandler = mountHandler; this.classConfig = classConfig; - this.goapAgentState = state; - AddPrecondition(GoapKey.incombat, true); AddPrecondition(GoapKey.hastarget, true); AddPrecondition(GoapKey.targetisalive, true); @@ -168,32 +165,6 @@ public override void Update() } else { - // dont save too close points - logger.LogInformation("Target(s) Dead -- trying saving safe pos " + playerReader.MapPosNoZ.ToString()); - bool foundClosePoint = false; - if (this.goapAgentState.safeLocations == null) - { - return; - } - for (LinkedListNode point = this.goapAgentState.safeLocations.Last; point != null; point = point.Previous) - { - Vector2 p1 = new Vector2(point.Value.X, point.Value.Y); - Vector2 p2 = new Vector2(playerReader.MapPos.X, playerReader.MapPos.Y); - if (Vector2.Distance(p1, p2) <= 0.1) - { - foundClosePoint = true; - break; - } - } - if (!foundClosePoint) - { - Console.WriteLine("Saving safepos: " + playerReader.MapPosNoZ.ToString()); - this.goapAgentState.safeLocations.AddLast(playerReader.MapPosNoZ); - if (this.goapAgentState.safeLocations.Count > 100) - { - this.goapAgentState.safeLocations.RemoveFirst(); - } - } input.PressClearTarget(); } } diff --git a/Core/Goals/FleeGoal.cs b/Core/Goals/FleeGoal.cs index b437792d..06787544 100644 --- a/Core/Goals/FleeGoal.cs +++ b/Core/Goals/FleeGoal.cs @@ -3,145 +3,117 @@ using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; +using System.Buffers; using System.Numerics; namespace Core.Goals; -public sealed class FleeGoal : GoapGoal +public sealed class FleeGoal : GoapGoal, IRouteProvider { - public override float Cost => 4f; + public override float Cost => 3.1f; + private readonly ILogger logger; private readonly ConfigurableInput input; private readonly ClassConfiguration classConfig; private readonly Wait wait; private readonly PlayerReader playerReader; - private readonly Navigation playerNavigation; + private readonly Navigation navigation; private readonly AddonBits bits; - private readonly StopMoving stopMoving; - private readonly CastingHandler castingHandler; - private readonly IMountHandler mountHandler; private readonly CombatLog combatLog; private readonly GoapAgentState goapAgentState; + + private readonly SafeSpotCollector safeSpotCollector; + + private Vector3[] MapPoints = []; + public int MOB_COUNT = 1; - public bool runningAway; public FleeGoal(ILogger logger, ConfigurableInput input, - Wait wait, PlayerReader playerReader, StopMoving stopMoving, AddonBits bits, + Wait wait, PlayerReader playerReader, AddonBits bits, ClassConfiguration classConfiguration, Navigation playerNavigation, GoapAgentState state, - ClassConfiguration classConfig, CastingHandler castingHandler, CombatLog combatLog, - IMountHandler mountHandler) - : base(nameof(CombatGoal)) + ClassConfiguration classConfig, CombatLog combatLog, + SafeSpotCollector safeSpotCollector) + : base(nameof(FleeGoal)) { this.logger = logger; this.input = input; - this.runningAway = false; this.wait = wait; this.playerReader = playerReader; - this.playerNavigation = playerNavigation; + this.navigation = playerNavigation; this.bits = bits; this.combatLog = combatLog; - this.stopMoving = stopMoving; - this.castingHandler = castingHandler; - this.mountHandler = mountHandler; this.classConfig = classConfig; this.goapAgentState = state; AddPrecondition(GoapKey.incombat, true); - //AddPrecondition(GoapKey.hastarget, true); - //AddPrecondition(GoapKey.targetisalive, true); - //AddPrecondition(GoapKey.targethostile, true); - //AddPrecondition(GoapKey.targettargetsus, true); - //AddPrecondition(GoapKey.incombatrange, true); - - //AddEffect(GoapKey.producedcorpse, true); - //AddEffect(GoapKey.targetisalive, false); - //AddEffect(GoapKey.hastarget, false); Keys = classConfiguration.Combat.Sequence; + + // this will ensure that the component is created + this.safeSpotCollector = safeSpotCollector; + } + + #region IRouteProvider + + public DateTime LastActive => navigation.LastActive; + + public Vector3[] MapRoute() => MapPoints; + + public Vector3[] PathingRoute() + { + return navigation.TotalRoute; } - private void ResetCooldowns() + public bool HasNext() { - ReadOnlySpan span = Keys; - for (int i = 0; i < span.Length; i++) - { - KeyAction keyAction = span[i]; - if (keyAction.ResetOnNewTarget) - { - keyAction.ResetCooldown(); - keyAction.ResetCharges(); - } - } + return navigation.HasNext(); + } + + public Vector3 NextMapPoint() + { + return navigation.NextMapPoint(); + } + + #endregion + + public override bool CanRun() + { + return + goapAgentState.SafeLocations.Count > 0 && + combatLog.DamageTakenCount() > MOB_COUNT; } public override void OnEnter() { - if (mountHandler.IsMounted()) - { - mountHandler.Dismount(); - } + // TODO: might have to do some pre processing like + // straightening the path + var count = goapAgentState.SafeLocations.Count; + MapPoints = new Vector3[count]; + + goapAgentState.SafeLocations.CopyTo(MapPoints, 0); - this.runningAway = false; - playerNavigation.Stop(); - playerNavigation.SetWayPoints(stackalloc Vector3[] { }); - playerNavigation.ResetStuckParameters(); + navigation.SetWayPoints(MapPoints.AsSpan(0, count)); + navigation.ResetStuckParameters(); } public override void OnExit() { - if (combatLog.DamageTakenCount() > 0 && !bits.Target()) - { - stopMoving.Stop(); - } - // clearing - this.runningAway = false; - playerNavigation.Stop(); - playerNavigation.SetWayPoints(stackalloc Vector3[] { }); - playerNavigation.ResetStuckParameters(); + goapAgentState.SafeLocations.Clear(); + + navigation.Stop(); + navigation.StopMovement(); } public override void Update() { - wait.Update(); - if (this.goapAgentState.safeLocations.Count >= MOB_COUNT && this.runningAway == false) + if (bits.Target()) { - - bool foundPoint = false; - logger.LogInformation("Flee Goal Activated. Current Pos: " + playerReader.MapPos.ToString() + ",Safe Spots: " + goapAgentState.safeLocations.Count); - if (goapAgentState.safeLocations == null) - { - return; - } - for (LinkedListNode point = goapAgentState.safeLocations.Last; point != null; point = point.Previous) - { - Vector2 p1 = new Vector2(point.Value.X, point.Value.Y); - Vector2 p2 = new Vector2(playerReader.MapPos.X, playerReader.MapPos.Y); - if (Vector2.Distance(p1, p2) >= 2.2) - { - // select the point far enough to lose the current mobs. - input.PressClearTarget(); - playerNavigation.Stop(); - playerNavigation.ResetStuckParameters(); - playerNavigation.SetWayPoints(stackalloc Vector3[] { (Vector3)(point.Value) }); - playerNavigation.Update(); - Console.WriteLine("Found point " + point.Value.ToString()); - foundPoint = true; - this.runningAway = true; - break; - } - } - if (foundPoint) - { - logger.LogInformation("Running away to the last safe point!"); - return; - } - else - { - logger.LogInformation("Cant run away, figting!"); - } + input.PressClearTarget(); } + + wait.Update(); + navigation.Update(); } } diff --git a/Core/GoalsComponent/SafeSpotCollector.cs b/Core/GoalsComponent/SafeSpotCollector.cs new file mode 100644 index 00000000..d5c7cbc5 --- /dev/null +++ b/Core/GoalsComponent/SafeSpotCollector.cs @@ -0,0 +1,44 @@ +using Core.GOAP; + +using System; +using System.Threading; + +namespace Core.Goals; + +public sealed class SafeSpotCollector : IDisposable +{ + private readonly PlayerReader playerReader; + private readonly GoapAgentState state; + private readonly AddonBits bits; + + private readonly Timer timer; + + public SafeSpotCollector( + PlayerReader playerReader, + GoapAgentState state, + AddonBits bits) + { + this.playerReader = playerReader; + this.state = state; + this.bits = bits; + + timer = new(Update, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); + } + + public void Dispose() + { + timer.Dispose(); + } + + public void Update(object? obj) + { + if (bits.Combat()) + return; + + if (state.SafeLocations.TryPeek(out var lastPos) && + lastPos == playerReader.MapPosNoZ) + return; + + state.SafeLocations.Push(playerReader.MapPosNoZ); + } +} diff --git a/Core/GoalsFactory/GoalFactory.cs b/Core/GoalsFactory/GoalFactory.cs index 0ff42a86..fa6fbd1e 100644 --- a/Core/GoalsFactory/GoalFactory.cs +++ b/Core/GoalsFactory/GoalFactory.cs @@ -57,6 +57,7 @@ public static IServiceProvider Create( services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); var playerReader = sp.GetRequiredService(); @@ -137,6 +138,7 @@ public static IServiceProvider Create( services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); if (classConfig.WrongZone.ZoneId > 0)