diff --git a/BetterGenshinImpact.Test/BetterGenshinImpact.Test.csproj b/BetterGenshinImpact.Test/BetterGenshinImpact.Test.csproj index 94f70e0d..66a35680 100644 --- a/BetterGenshinImpact.Test/BetterGenshinImpact.Test.csproj +++ b/BetterGenshinImpact.Test/BetterGenshinImpact.Test.csproj @@ -5,6 +5,7 @@ net8.0-windows10.0.22621.0 enable enable + true true diff --git a/BetterGenshinImpact.Win32/BetterGenshinImpact.Win32.csproj b/BetterGenshinImpact.Win32/BetterGenshinImpact.Win32.csproj index 8c1de519..9a858568 100644 --- a/BetterGenshinImpact.Win32/BetterGenshinImpact.Win32.csproj +++ b/BetterGenshinImpact.Win32/BetterGenshinImpact.Win32.csproj @@ -4,6 +4,7 @@ net8.0-windows10.0.22621.0 enable enable + true x64 diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index b3ddee7d..11dd367a 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -6,6 +6,7 @@ enable true true + true 12.0 true Assets\Images\logo.ico diff --git a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs index 00ab7d8e..f1ecd877 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs @@ -27,6 +27,8 @@ public class PathExecutor(CancellationTokenSource cts) private CameraRotateTask _rotateTask = new(cts); + private bool SkipWaypoint = false; + public async Task Pathing(PathingTask task) { _dpi = TaskContext.Instance().DpiScale; @@ -55,6 +57,12 @@ public class PathExecutor(CancellationTokenSource cts) { // Path不用走得很近,Target需要接近,但都需要先移动到对应位置 await MoveTo(waypoint); + // 跳过路径点后,当前路径点不处理 + if (SkipWaypoint) + { + SkipWaypoint = false; + continue; + } if (waypoint.Type == WaypointType.Target.Code || !string.IsNullOrEmpty(waypoint.Action)) { @@ -69,6 +77,8 @@ public class PathExecutor(CancellationTokenSource cts) { // 不管咋样,松开所有按键 Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_SHIFT); Simulation.SendInput.Mouse.RightButtonUp(); } } @@ -112,107 +122,116 @@ public class PathExecutor(CancellationTokenSource cts) private async Task MoveTo(Waypoint waypoint) { + Logger.LogInformation("粗略接近路径点,位置({x2},{y2})", $"{waypoint.X:F1}", $"{waypoint.Y:F1}"); var screen = CaptureToRectArea(); var position = Navigation.GetPosition(screen); var targetOrientation = Navigation.GetTargetOrientation(waypoint, position); - Logger.LogInformation("粗略接近途经点,位置({x2},{y2})", $"{waypoint.X:F1}", $"{waypoint.Y:F1}"); await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5); + + var hasCharacter = false; + // TODO 增加识别角色并切换的逻辑 + // 可以考虑放到游泳,攀爬,等移动逻辑中 + var startTime = DateTime.UtcNow; var lastPositionRecord = DateTime.UtcNow; - var fastMode = false; var prevPositions = new List(); - // 按下w,一直走 - Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + // 新增逻辑:普通向前移动,疾跑向前移动,飞行向前移动,游泳向前移动,攀爬向前移动,角色技能向前移动,脱离卡死 + // NormalForward + // SprintForward + // FlightForward + // SwimmingForward + // ClimbForward + // CharacterSkillForward + // GetOutOfTheJam + while (!cts.IsCancellationRequested) { - var now = DateTime.UtcNow; - if ((now - startTime).TotalSeconds > 60) - { - Logger.LogWarning("执行超时,跳过路径点"); - break; - } screen = CaptureToRectArea(); position = Navigation.GetPosition(screen); var distance = Navigation.GetDistance(waypoint, position); - Debug.WriteLine($"接近目标点中,距离为{distance}"); - if (distance < 4) + if (distance < 5) { - Logger.LogInformation("到达路径点附近"); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + Logger.LogInformation("已到达路径点附近"); break; } + // TODO 异常情况直接放到一个函数中处理,然后退出 + // 超时 + if (IsTimedOut(startTime)) + { + Logger.LogWarning("执行超时,跳过路径点"); + SkipWaypoint = true; + break; + } + // 距离终止判断 if (distance > 500) { Logger.LogWarning("距离过远,跳过路径点"); + SkipWaypoint = true; break; } - if ((now - lastPositionRecord).TotalMilliseconds > 1000) + // 卡死 + // TODO 攀爬时应该跳过,但是如何处理看似是walk,实际是攀爬的 + if (IsStuck(prevPositions, position, lastPositionRecord)) { - lastPositionRecord = now; - prevPositions.Add(position); - if (prevPositions.Count > 8) - { - var delta = prevPositions[^1] - prevPositions[^8]; - if (Math.Abs(delta.X) + Math.Abs(delta.Y) < 3) - { - Logger.LogWarning("疑似卡死,尝试脱离并跳过路径点"); - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); - await Delay(1500, cts); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); - await Delay(500, cts); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_S); - await Delay(1500, cts); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_A); - await Delay(1500, cts); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_D); - await Delay(500, cts); - return; - } - } + lastPositionRecord = DateTime.UtcNow; + // 脱离卡死 + await GetOutOfTheJam(); + SkipWaypoint = true; + break; } + Logger.LogInformation($"接近目标点中3,距离为{distance}"); // 旋转视角 targetOrientation = Navigation.GetTargetOrientation(waypoint, position); - _rotateTask.RotateToApproach(targetOrientation, screen); - // 根据指定方式进行移动 + await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5); + // 根据移动模式选择相应的行为 if (waypoint.MoveMode == MoveModeEnum.Fly.Code) { - var isFlying = Bv.GetMotionStatus(screen) == MotionStatus.Fly; - if (!isFlying) - { - Debug.WriteLine("未进入飞行状态,按下空格"); - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); - await Delay(200, cts); - } - continue; + await FlightForward(); + await Delay(1000, cts); } - // if (isFlying) - // { - // Simulation.SendInput.Mouse.LeftButtonClick(); - // await Delay(1000, cts); - // continue; - // } + if (waypoint.MoveMode == MoveModeEnum.Jump.Code) { - Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); - await Delay(200, cts); - continue; + ClimbForward(); + await Delay(1000, cts); } - // 跑步或者游泳 - if (distance > 20 != fastMode)// 距离大于20时可以使用疾跑/自由泳 + + if (waypoint.MoveMode == MoveModeEnum.Swim.Code) { - if (fastMode) + SwimmingForward(); + await Delay(1000, cts); + } + + + if (waypoint.MoveMode == MoveModeEnum.Walk.Code) + { + + if (distance >= 20) { - Simulation.SendInput.Mouse.RightButtonUp(); + if (hasCharacter) + { + CharacterSkillForward(); + await Delay(200, cts); + } + else + { + SprintForward(); + await Delay(500, cts); + } } else { - Simulation.SendInput.Mouse.RightButtonDown(); + // 结束e技能 + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); + NormalForward(); + await Delay(600, cts); } - fastMode = !fastMode; } - await Delay(100, cts); + + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_SHIFT); } - // 抬起w键 - Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); } private async Task MoveCloseTo(Waypoint waypoint) @@ -276,4 +295,119 @@ public class PathExecutor(CancellationTokenSource cts) await handler.RunAsync(cts); } } + + // 普通向前移动 + private void NormalForward() + { + Logger.LogInformation("正常向前移动"); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + } + + // 攀爬向前移动 + private void ClimbForward() + { + Logger.LogInformation("进行攀爬"); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + // TODO 角色处理逻辑:卡其娜,西诺宁 + } + + // 疾跑向前移动 + private void SprintForward() + { + Logger.LogInformation("疾跑向前移动"); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_SHIFT); + } + + // 飞行向前移动 + private async Task FlightForward() + { + Logger.LogInformation("进入飞行模式"); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + + var screen = CaptureToRectArea(); + var isFlying = Bv.GetMotionStatus(screen) == MotionStatus.Fly; + + if (!isFlying) + { + Logger.LogInformation("未进入飞行状态,按下空格展开翅膀"); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + await Delay(200, cts); // 延迟,确保飞行动作完成 + } + } + + // 游泳向前移动 + private void SwimmingForward() + { + Logger.LogInformation("进入游泳模式"); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + // TODO 添加芙宁娜处理 + // 有芙宁娜时定时释放e技能 + } + + private void CharacterSkillForward() + { + Logger.LogInformation("使用角色技能向前移动"); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_E).Sleep(500).KeyUp(User32.VK.VK_E); + // TODO 根据不同角色进行处理:夜兰,闲云,散兵,早柚,玛拉妮,基尼奇 + // 玛拉妮,散兵正常移动即可,但是夜兰,早柚是持续向前移动的,需要特殊处理 + // 闲云,基尼奇容易超出距离,但是问题不大 + } + + // 脱离卡死 + private async Task GetOutOfTheJam() + { + Logger.LogWarning("脱离卡死状态"); + // 脱离攀爬状态 + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + await Delay(1500, cts); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + await Delay(500, cts); + // 向后移动 + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_S); + await Task.Delay(1500); + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_S); + // 向左移动 + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_A); + await Task.Delay(1000); + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_A); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + await Delay(500, cts); + // 向右移动 + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_D); + await Task.Delay(1000); + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_D); + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X); + await Delay(500, cts); + // 跳跃 + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE); + await Task.Delay(200); // 等待跳跃动作 + } + + + public bool IsTimedOut(DateTime startTime) + { + var now = DateTime.UtcNow; + return (now - startTime).TotalSeconds > 60; + } + + public bool IsStuck(List prevPositions, Point2f position, DateTime lastPositionRecord) + { + if ((DateTime.UtcNow - lastPositionRecord).TotalMilliseconds > 1000) + { + prevPositions.Add(position); + if (prevPositions.Count > 8) + { + var delta = prevPositions[^1] - prevPositions[^8]; + if (Math.Abs(delta.X) + Math.Abs(delta.Y) < 3) + { + Logger.LogWarning("疑似卡死,尝试脱离并跳过路径点"); + return true; + } + } + } + return false; + } } diff --git a/Build/MicaSetup/MicaSetup.Uninst.csproj b/Build/MicaSetup/MicaSetup.Uninst.csproj index 4e56aad1..0f08fe86 100644 --- a/Build/MicaSetup/MicaSetup.Uninst.csproj +++ b/Build/MicaSetup/MicaSetup.Uninst.csproj @@ -7,6 +7,7 @@ 12.0 true true + true false AnyCPU;x64 Resources\Images\FaviconUninst.ico diff --git a/Build/MicaSetup/MicaSetup.csproj b/Build/MicaSetup/MicaSetup.csproj index f3f367db..9a661b52 100644 --- a/Build/MicaSetup/MicaSetup.csproj +++ b/Build/MicaSetup/MicaSetup.csproj @@ -7,6 +7,7 @@ 12.0 true true + true false AnyCPU;x64 Resources\Images\FaviconSetup.ico diff --git a/Fischless.GameCapture/Fischless.GameCapture.csproj b/Fischless.GameCapture/Fischless.GameCapture.csproj index 7b895bae..d2d0f11b 100644 --- a/Fischless.GameCapture/Fischless.GameCapture.csproj +++ b/Fischless.GameCapture/Fischless.GameCapture.csproj @@ -6,6 +6,7 @@ enable x64 True + true True 12.0 true diff --git a/Fischless.HotkeyCapture/Fischless.HotkeyCapture.csproj b/Fischless.HotkeyCapture/Fischless.HotkeyCapture.csproj index bd52b9cd..33e41d6a 100644 --- a/Fischless.HotkeyCapture/Fischless.HotkeyCapture.csproj +++ b/Fischless.HotkeyCapture/Fischless.HotkeyCapture.csproj @@ -7,6 +7,7 @@ x64 12.0 True + true True diff --git a/Fischless.KeyboardCapture/Fischless.KeyboardCapture.csproj b/Fischless.KeyboardCapture/Fischless.KeyboardCapture.csproj index c8eaf74b..9798cea2 100644 --- a/Fischless.KeyboardCapture/Fischless.KeyboardCapture.csproj +++ b/Fischless.KeyboardCapture/Fischless.KeyboardCapture.csproj @@ -6,6 +6,7 @@ enable x64 12.0 + true True diff --git a/Vision.WindowCapture.Test/Vision.WindowCapture.Test.csproj b/Vision.WindowCapture.Test/Vision.WindowCapture.Test.csproj index e155b5f3..fe7a21f4 100644 --- a/Vision.WindowCapture.Test/Vision.WindowCapture.Test.csproj +++ b/Vision.WindowCapture.Test/Vision.WindowCapture.Test.csproj @@ -7,6 +7,7 @@ true 12.0 true + true x64 diff --git a/Vision.WindowCapture/Vision.WindowCapture.csproj b/Vision.WindowCapture/Vision.WindowCapture.csproj index e4ed849d..a43e2a07 100644 --- a/Vision.WindowCapture/Vision.WindowCapture.csproj +++ b/Vision.WindowCapture/Vision.WindowCapture.csproj @@ -5,6 +5,7 @@ enable enable 12.0 + true true x64