using BardFrontline.Core; using System.Numerics; using System.Text.Json; static class OptimizationTests { static Actor Self(params uint[] states) => new(1, "self", 60000, 60000, 0, false, true, false, 0, [.. states]); static Actor Enemy(ulong id, uint hp = 30000) => new(id, $"enemy{id}", hp, 60000, 20, true, true, false, 0, []); static CombatSnapshot Snap(params Actor[] enemies) => new(Self(), 10000, 10000, true, false, 10, false, enemies, [], 0); static ActionDecision? Decide(CombatSnapshot s, Settings c, params Skill[] ready) => new Rotation().Decide(s, c, new Fake(ready)); static void SkillIs(Skill skill, ActionDecision? d) => Suite.Equal(skill, d!.Skill); public static void Run(Suite suite) { suite.Run("Optimization defaults preserve automatic HP player-first finisher and backstep preferences", () => { var c = JsonSerializer.Deserialize("{\"EagleFinisherHp\":9000,\"HelpParty\":true}")!; c.Normalize(); Suite.True(c.AutoAttack && c.AttackObjectives && !c.IgnoreEnemyGuard && c.HelpParty); Suite.True(!c.StableTargets && !c.DetectManualControl && !c.ManualRepelling && !c.FocusDefense && !c.PreferAoe); Suite.Equal(BurstStrategy.Normal, c.Burst); Suite.Equal(EagleStrategy.FinisherFirst, c.EagleStrategy); Suite.Equal(TargetOrder.LowestHp, c.TargetOrder); Suite.Equal(9000, c.EagleFinisherHp); Suite.Equal(0, c.DisabledObjectives.Count); }); suite.Run("New strategy settings serialize and malformed values normalize", () => { var c = new Settings { StableTargets = true, DetectManualControl = true, ManualRepelling = true, FocusDefense = true, PreferAoe = true, Burst = BurstStrategy.ManualWindow, DisabledObjectives = [ObjectiveKind.Core] }; var roundTrip = JsonSerializer.Deserialize(JsonSerializer.Serialize(c))!; Suite.True(roundTrip.ManualRepelling && roundTrip.DisabledObjectives.Contains(ObjectiveKind.Core)); c.TargetHoldSeconds = float.NaN; c.ManualControlSeconds = float.PositiveInfinity; c.FocusAttackers = -1; c.BurstCharges = 50; c.AoeMinTargets = 0; c.Burst = (BurstStrategy)99; c.Normalize(); Suite.Equal(.6f, c.TargetHoldSeconds); Suite.Equal(3f, c.ManualControlSeconds); Suite.Equal(2, c.FocusAttackers); Suite.Equal(4, c.BurstCharges); Suite.Equal(2, c.AoeMinTargets); Suite.Equal(BurstStrategy.Normal, c.Burst); }); suite.Run("Stable targeting absorbs small HP jitter but default remains instant", () => { var s = Snap(Enemy(10, 21000), Enemy(11, 20000)) with { CurrentTarget = 10, TargetAge = .2 }; Suite.Equal(11ul, Decide(s, new(), Skill.PowerfulShot)!.TargetId); Suite.Equal(10ul, Decide(s, new() { StableTargets = true }, Skill.PowerfulShot)!.TargetId); Suite.Equal(11ul, Decide(s with { TargetAge = .7 }, new() { StableTargets = true }, Skill.PowerfulShot)!.TargetId); }); suite.Run("Stable targeting yields immediately to major HP advantage or invalid targets", () => { var c = new Settings { StableTargets = true }; var s = Snap(Enemy(10, 30000), Enemy(11, 20000)) with { CurrentTarget = 10, TargetAge = .1 }; Suite.Equal(11ul, Decide(s, c, Skill.PowerfulShot)!.TargetId); foreach (var old in new[] { Enemy(10, 19000) with { Dead = true }, Enemy(10, 19000) with { Status = [Statuses.Guard] }, Enemy(10, 19000) with { Targetable = false } }) Suite.Equal(11ul, Decide(s with { Enemies = [old, Enemy(11, 20000)] }, c, Skill.PowerfulShot)!.TargetId); }); suite.Run("Stability cannot retain an objective over a player or delay an Eagle finisher", () => { var c = new Settings { StableTargets = true }; var s = Snap(Enemy(10, 100) with { IsObjective = true }, Enemy(11, 9000)) with { CurrentTarget = 10, TargetAge = .1 }; Suite.Equal(11ul, Decide(s, c, Skill.PowerfulShot)!.TargetId); SkillIs(Skill.EagleEyeShot, Decide(s with { Player = Self(Statuses.RoleEagle) }, c, Skill.EagleEyeShot, Skill.PowerfulShot)); }); suite.Run("Planned and dispatched stable targets agree", () => { var s = Snap(Enemy(10, 21000), Enemy(11, 20000)) with { CurrentTarget = 10, TargetAge = .1 }; var c = new Settings { StableTargets = true }; var f = new Fake(Skill.PowerfulShot); Suite.Equal(10ul, TargetSelector.PlanTarget(s, c, f, f)!.Id); Suite.Equal(10ul, new Rotation().Decide(s, c, f)!.TargetId); }); suite.Run("Plugin target writes and native requests never trigger automatic takeover", () => { var control = new ManualControl(); var c = new Settings { DetectManualControl = true }; control.Observe(0, 10, 1, false, c); control.OwnTarget(11, .1); control.OwnAction(2); control.Observe(.2, 11, 2, false, c); Suite.True(!control.Active(.2)); control.Observe(.3, 11, 3, true, c); control.Observe(.4, 11, 3, false, c); Suite.True(!control.Active(.4)); }); suite.Run("Manual target and foreign action takeover has bounded expiry", () => { var control = new ManualControl(); var c = new Settings { DetectManualControl = true, ManualControlSeconds = 3 }; control.Observe(0, 10, 65535, false, c); control.Observe(1, 11, 65535, false, c); Suite.True(control.Active(3.9)); Suite.True(!control.Active(4)); control.Observe(5, 11, 0, false, c); Suite.True(control.Active(5)); control.Resume(); Suite.True(!control.Active(5)); }); suite.Run("Forced takeover persists across context resets but explicit resume clears it", () => { var control = new ManualControl { Forced = true }; control.ResetObservations(); Suite.True(control.Active(100)); control.Resume(); Suite.True(!control.Active(100)); control.Observe(0, 10, 1, false, new()); control.Observe(1, 11, 2, false, new()); Suite.True(!control.Active(1)); }); suite.Run("Manual control pauses offense survival and target planning", () => { var s = Snap(Enemy(10, 100)) with { ManualControl = true, Player = Self(Statuses.RoleEagle) with { Hp = 1000 } }; var f = new Fake(Actions.All); Suite.True(new Rotation().Decide(s, new(), f) == null); Suite.True(TargetSelector.PlanTarget(s, new(), f, f) == null); }); suite.Run("Adaptive weave starts at legacy budget and learns observed confirmation latency", () => { var w = new WeaveTiming(); Suite.Equal(.65f, w.Budget); for (var i = 0; i < 3; i++) { w.Submitted(i * 2, false); w.Observe(i * 2 + .1, false, .6f, false, false); w.Observe(i * 2 + .8, true, 0, false, false); } Suite.Equal(3, w.SampleCount); Suite.True(w.Budget > .8f && w.Budget < .9f); Suite.True(!w.Allows(.75f, Skill.SilentNocturne, true)); Suite.True(w.Allows(.75f, Skill.SilentNocturne, false)); Suite.True(w.Allows(.1f, Skill.EncoreOfLight, true)); Suite.True(w.Allows(0, Skill.HarmonicArrow, true)); }); suite.Run("Weave learning ignores casts timeouts and pending queues", () => { var w = new WeaveTiming(); w.Submitted(0, true); w.Observe(1, true, 0, false, false); Suite.Equal(0, w.SampleCount); w.Submitted(2, false); w.Observe(5, false, 0, false, false); Suite.Equal(0, w.SampleCount); w.Submitted(6, false); w.Observe(6.6, true, 0, true, false); Suite.Equal(0, w.SampleCount); w.Observe(6.8, true, 0, false, false); Suite.Equal(1, w.SampleCount); w.Reset(); Suite.Equal(.65f, w.Budget); }); suite.Run("Adaptive sample window is bounded and budget responds to recent samples", () => { var w = new WeaveTiming(); for (var i = 0; i < 30; i++) { w.Submitted(i * 2, false); w.Observe(i * 2 + (i < 5 ? 1.4 : .55), true, 0, false, false); } Suite.Equal(20, w.SampleCount); Suite.True(w.Budget < .65f && w.Budget >= .5f); }); suite.Run("Rival Wings names classify all objective families without localized strings", () => { foreach (var (id, kind) in new[] { (6857u, ObjectiveKind.Core), (6860u, ObjectiveKind.Tower), (6864u, ObjectiveKind.Mech), (6871u, ObjectiveKind.Infantry), (7891u, ObjectiveKind.Mercenary), (7906u, ObjectiveKind.Mercenary), (99999u, ObjectiveKind.Other) }) Suite.Equal(kind, Battlefield.Classify(BattlefieldMode.RivalWings, true, false, id)); Suite.Equal(ObjectiveKind.Mech, Battlefield.Classify(BattlefieldMode.RivalWings, false, true, 0)); Suite.Equal(ObjectiveKind.Other, Battlefield.Classify(BattlefieldMode.Frontline, true, false, 6857)); Suite.Equal(ObjectiveKind.Ice, Battlefield.Classify(BattlefieldMode.Frontline, true, false, 4822)); }); suite.Run("Objective family switches affect attacks but never hide threats", () => { foreach (var kind in Enum.GetValues()) { var s = Snap(Enemy(10) with { IsObjective = true, ThreateningObjective = true, Kind = kind }); var c = new Settings { DisabledObjectives = [kind] }; Suite.True(Decide(s, c, Skill.PowerfulShot) == null); Suite.True(TargetSelector.HasNearbyThreat(s)); SkillIs(Skill.PowerfulShot, Decide(s, new(), Skill.PowerfulShot)); } }); suite.Run("Original Harmonic behavior remains immediate and aligned mode has bounded hold", () => { var s = Snap(Enemy(10)) with { HarmonicCharges = 1 }; SkillIs(Skill.HarmonicArrow, Decide(s, new(), Skill.HarmonicArrow, Skill.PowerfulShot)); var c = new Settings { Burst = BurstStrategy.AlignBuffs }; SkillIs(Skill.PowerfulShot, Decide(s, c, Skill.HarmonicArrow, Skill.PowerfulShot)); SkillIs(Skill.HarmonicArrow, Decide(s with { HarmonicReadySeconds = 4 }, c, Skill.HarmonicArrow)); SkillIs(Skill.HarmonicArrow, Decide(s with { HarmonicCharges = 3 }, c, Skill.HarmonicArrow)); SkillIs(Skill.HarmonicArrow, Decide(s with { Player = Self(Statuses.Bravery) }, c, Skill.HarmonicArrow)); }); suite.Run("Manual burst holds only declared burst skills and releases in window", () => { var s = Snap(Enemy(10)) with { Player = Self(Statuses.RoleBravery), LimitFull = true }; var c = new Settings { Burst = BurstStrategy.ManualWindow }; SkillIs(Skill.PowerfulShot, Decide(s, c, Skill.HarmonicArrow, Skill.Bravery, Skill.FinalFantasia, Skill.PowerfulShot)); SkillIs(Skill.Bravery, Decide(s with { BurstWindow = true }, c, Skill.Bravery, Skill.PowerfulShot)); SkillIs(Skill.EncoreOfLight, Decide(s with { Player = Self(Statuses.EncoreReady) }, c, Skill.EncoreOfLight, Skill.PowerfulShot)); SkillIs(Skill.EagleEyeShot, Decide(s with { Player = Self(Statuses.RoleEagle), Enemies = [Enemy(10, 9000)] }, c, Skill.EagleEyeShot)); }); suite.Run("Aoe circle strategy chooses dense players only when enabled", () => { var s = Snap(Enemy(10, 1000) with { Position = new(0, 0, 20) }, Enemy(11, 40000) with { Position = new(10, 0, 10) }, Enemy(12, 50000) with { Position = new(11, 0, 10) }) with { Player = Self(Statuses.EncoreReady), Shapes = new Dictionary { [Skill.EncoreOfLight] = new(false, 5) } }; Suite.Equal(10ul, Decide(s, new(), Skill.EncoreOfLight)!.TargetId); Suite.Equal(11ul, Decide(s, new() { PreferAoe = true }, Skill.EncoreOfLight)!.TargetId); Suite.Equal(10ul, Decide(s, new() { PreferAoe = true, AoeMinTargets = 4 }, Skill.EncoreOfLight)!.TargetId); }); suite.Run("Aoe line counts width range direction elevation and immunity", () => { var aim = Enemy(10) with { Position = new(0, 0, 10) }; var s = Snap(aim, Enemy(11) with { Position = new(1, 0, 20) }, Enemy(12) with { Position = new(0, 0, -5) }, Enemy(13) with { Position = new(4, 0, 10) }, Enemy(14) with { Position = new(0, 8, 10) }, Enemy(15) with { Position = new(0, 0, 30) }, Enemy(16) with { Position = new(0, 0, 15), Invulnerable = true }); Suite.Equal(2, Strategy.AoeCount(s, new(), Skill.ApexArrow, aim, new(true, 25, 2))); }); suite.Run("Aoe strategy never diverts from players to a denser objective pack", () => { var s = Snap(Enemy(10) with { Position = new(0, 0, 20) }, Enemy(11) with { IsObjective = true }, Enemy(12) with { IsObjective = true }) with { Player = Self(Statuses.EncoreReady), Shapes = new Dictionary { [Skill.EncoreOfLight] = new(false, 5) } }; Suite.Equal(10ul, Decide(s, new() { PreferAoe = true }, Skill.EncoreOfLight)!.TargetId); }); suite.Run("Focus defense uses enemy target and cast signals without double-counting actors", () => { var s = Snap(Enemy(10) with { TargetId = 1, CastTargetId = 1 }, Enemy(11) with { CastTargetId = 1 }, Enemy(12) with { TargetId = 1 }, Enemy(13) with { TargetId = 1, Enemy = false }, Enemy(14) with { TargetId = 1, Dead = true }, Enemy(15) with { TargetId = 1, Distance = 60 }) with { Player = Self() with { Hp = 23000 } }; Suite.Equal(3, Strategy.FocusCount(s)); SkillIs(Skill.Recuperate, Decide(s, new(), Skill.Guard, Skill.Recuperate)); SkillIs(Skill.Guard, Decide(s, new() { FocusDefense = true }, Skill.Guard, Skill.Recuperate)); Suite.True(Decide(s with { AliveSeconds = 4 }, new() { FocusDefense = true }, Skill.Guard, Skill.Recuperate) == null); }); suite.Run("Focus pressure lowers healing threshold but never raises it or removes Guard protection", () => { var s = Snap() with { Player = Self() with { Hp = 53000 }, RecentHpLossRatio = .3 }; Suite.True(Decide(s, new(), Skill.Recuperate) == null); SkillIs(Skill.Recuperate, Decide(s, new() { FocusDefense = true }, Skill.Recuperate)); Suite.Equal(3000, Strategy.HealDeficit(s, new() { FocusDefense = true, RecuperateMissingHp = 3000 })); Suite.True(Decide(s with { Player = Self(Statuses.Guard) with { Hp = 53000 } }, new() { FocusDefense = true }, Skill.Recuperate) == null); }); suite.Run("HP pressure expires after two seconds and ignores healing increments", () => { var p = new HealthPressure(); Suite.Equal(0d, p.Observe(0, 60000, 60000)); Suite.Equal(.25, p.Observe(.5, 45000, 60000)); Suite.Equal(.25, p.Observe(1, 55000, 60000)); Suite.Equal(0d, p.Observe(2.6, 55000, 60000)); p.Reset(); Suite.Equal(0d, p.Observe(3, 1000, 60000)); }); suite.Run("Manual backstep switch leaves the rest of the rotation and skill toggle intact", () => { var s = Snap(Enemy(10) with { Distance = 8 }); SkillIs(Skill.RepellingShot, Decide(s, new(), Skill.RepellingShot, Skill.SilentNocturne)); SkillIs(Skill.SilentNocturne, Decide(s, new() { ManualRepelling = true }, Skill.RepellingShot, Skill.SilentNocturne)); Suite.True(Decide(s, new() { DisabledSkills = [Skill.RepellingShot] }, Skill.RepellingShot) == null); }); suite.Run("Decision audit contains every skill and does not carry stale results to another frame", () => { var s = Snap(Enemy(10)); var c = new Settings(); var selected = Decide(s, c, Skill.PowerfulShot); var rows = DecisionAudit.Evaluate(s, c, selected, "运行", (_, _) => "冷却"); Suite.Equal(Actions.All.Length, rows.Count); Suite.True(rows.Single(r => r.Skill == Skill.PowerfulShot).Result.Contains("本轮选中")); Suite.True(rows.Single(r => r.Skill == Skill.EncoreOfLight).Result.Contains("4312")); var paused = DecisionAudit.Evaluate(null, c, null, "非支持区域", (_, _) => throw new Exception("must not probe")); Suite.True(paused.All(r => r.TargetId == 0 && r.Result == "非支持区域")); }); suite.Run("Decision audit distinguishes toggle policy native failure and higher priority selection", () => { var s = Snap(Enemy(10) with { Distance = 8 }) with { Player = Self(Statuses.EncoreReady) }; var c = new Settings { ManualRepelling = true, DisabledSkills = [Skill.HarmonicArrow] }; var selected = Decide(s, c, Skill.EncoreOfLight); var rows = DecisionAudit.Evaluate(s, c, selected, "运行", (skill, _) => skill == Skill.SilentNocturne ? "原生状态 582" : null); Suite.True(rows.Single(r => r.Skill == Skill.HarmonicArrow).Result.Contains("关闭")); Suite.True(rows.Single(r => r.Skill == Skill.RepellingShot).Result.Contains("手动")); Suite.True(rows.Single(r => r.Skill == Skill.SilentNocturne).Result.Contains("582")); Suite.True(rows.Single(r => r.Skill == Skill.PowerfulShot).Result.Contains("优先选择")); }); suite.Run("Audit never claims Sprint ready with a valid attack target", () => { var s = Snap(Enemy(10)) with { Moving = true }; var rows = DecisionAudit.Evaluate(s, new(), null, "等待", (_, _) => null, (_, _) => true); Suite.True(rows.Single(r => r.Skill == Skill.Sprint).Result.Contains("不自动冲刺")); }); } }