diff --git a/BetterGenshinImpact/GameTask/AutoFight/Script/CombatCommand.cs b/BetterGenshinImpact/GameTask/AutoFight/Script/CombatCommand.cs index c230c95c..a7798714 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Script/CombatCommand.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Script/CombatCommand.cs @@ -64,12 +64,22 @@ public class CombatCommand public void Execute(CombatScenes combatScenes) { - var avatar = combatScenes.SelectAvatar(Name); + // 如果是当前角色 + Avatar? avatar; + if (Name == CombatScriptParser.CurrentAvatarName) + { + avatar = combatScenes.Avatars[0]; // 随便取一个角色 + } + else + { + avatar = combatScenes.SelectAvatar(Name); + } if (avatar == null) { return; } + // 非宏类脚本,等待切换角色成功 if (Method != Method.Wait && Method != Method.MouseDown @@ -235,4 +245,4 @@ public class CombatCommand throw new NotImplementedException(); } } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoFight/Script/CombatScriptParser.cs b/BetterGenshinImpact/GameTask/AutoFight/Script/CombatScriptParser.cs index b4505c32..27e6bc55 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Script/CombatScriptParser.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Script/CombatScriptParser.cs @@ -10,6 +10,8 @@ namespace BetterGenshinImpact.GameTask.AutoFight.Script; public class CombatScriptParser { + public static string CurrentAvatarName = "当前角色"; + public static CombatScriptBag ReadAndParse(string path) { if (File.Exists(path)) @@ -50,7 +52,15 @@ public class CombatScriptParser public static CombatScript Parse(string path) { var script = File.ReadAllText(path); - var lines = script.Split(["\r\n", "\r", "\n", ";"], StringSplitOptions.RemoveEmptyEntries); + var combatScript = ParseContext(script); + combatScript.Path = path; + combatScript.Name = Path.GetFileNameWithoutExtension(path); + return combatScript; + } + + public static CombatScript ParseContext(string context, bool validate = true) + { + var lines = context.Split(["\r\n", "\r", "\n", ";"], StringSplitOptions.RemoveEmptyEntries); var result = new List(); foreach (var line in lines) { @@ -66,19 +76,16 @@ public class CombatScriptParser result.Add(l); } - var combatScript = Parse(result); - combatScript.Path = path; - combatScript.Name = Path.GetFileNameWithoutExtension(path); - return combatScript; + return ParseLines(result, validate); } - public static CombatScript Parse(List lines) + private static CombatScript ParseLines(List lines, bool validate = true) { List combatCommands = []; HashSet combatAvatarNames = []; foreach (var line in lines) { - var oneLineCombatCommands = ParseLine(line, combatAvatarNames); + var oneLineCombatCommands = ParseLine(line, combatAvatarNames, validate); combatCommands.AddRange(oneLineCombatCommands); } @@ -88,20 +95,29 @@ public class CombatScriptParser return new CombatScript(combatAvatarNames, combatCommands); } - public static List ParseLine(string line, HashSet combatAvatarNames) + private static List ParseLine(string line, HashSet combatAvatarNames, bool validate = true) { var oneLineCombatCommands = new List(); // 以空格分隔角色和指令 截取第一个空格前的内容为角色名称,后面的为指令 + // 20241116更新 不输入角色名称时,直接以当前角色为准 var firstSpaceIndex = line.IndexOf(' '); - if (firstSpaceIndex < 0) + var character = CurrentAvatarName; + var commands = line; + if (firstSpaceIndex > 0) { - Logger.LogError("战斗脚本格式错误,必须以空格分隔角色和指令"); - throw new Exception("战斗脚本格式错误,必须以空格分隔角色和指令"); + character = line[..firstSpaceIndex]; + character = DefaultAutoFightConfig.AvatarAliasToStandardName(character); + commands = line[(firstSpaceIndex + 1)..]; + } + else + { + if (validate) + { + Logger.LogError("战斗脚本格式错误,必须以空格分隔角色和指令"); + throw new Exception("战斗脚本格式错误,必须以空格分隔角色和指令"); + } } - var character = line[..firstSpaceIndex]; - character = DefaultAutoFightConfig.AvatarAliasToStandardName(character); - var commands = line[(firstSpaceIndex + 1)..]; oneLineCombatCommands.AddRange(ParseLineCommands(commands, character)); combatAvatarNames.Add(character); return oneLineCombatCommands; @@ -155,4 +171,4 @@ public class CombatScriptParser return oneLineCombatCommands; } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ActionFactory.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ActionFactory.cs index d3bfff4e..aee781b0 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ActionFactory.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ActionFactory.cs @@ -22,6 +22,7 @@ public class ActionFactory "hydro_collect" => new ElementalCollectHandler(ElementalType.Hydro), "electro_collect" => new ElementalCollectHandler(ElementalType.Electro), "anemo_collect" => new ElementalCollectHandler(ElementalType.Anemo), + "combat_script" => new CombatScriptHandler(), _ => throw new ArgumentException("未知的后置 action 类型") }; }); diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/AutoFightHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/AutoFightHandler.cs index 903659ce..5296f2ff 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/AutoFightHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/AutoFightHandler.cs @@ -5,13 +5,14 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoPathing.Model; using Microsoft.Extensions.Logging; namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; internal class AutoFightHandler : IActionHandler { - public async Task RunAsync(CancellationToken ct) + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { await StartFight(ct); } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/CombatScriptHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/CombatScriptHandler.cs new file mode 100644 index 00000000..d1b8da77 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/CombatScriptHandler.cs @@ -0,0 +1,64 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoPathing.Model; +using Microsoft.Extensions.Logging; +using static BetterGenshinImpact.GameTask.Common.TaskControl; + +namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; + +public class CombatScriptHandler : IActionHandler +{ + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) + { + if (waypointForTrack is { CombatScript: not null }) + { + Logger.LogInformation("执行 {Text}", "战斗策略脚本"); + var combatScript = waypointForTrack.CombatScript; + var combatScenes = await RunnerContext.Instance.GetCombatScenes(ct); + if (combatScenes == null) + { + Logger.LogError("队伍识别未初始化成功!"); + return; + } + + + try + { + // 通用化战斗策略 + foreach (var command in combatScript.CombatCommands) + { + command.Execute(combatScenes); + } + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + Debug.WriteLine(e.StackTrace); + } + } + else + { + Logger.LogError("战斗脚本action_params内容为空"); + } + } + + // private static bool IsOnlyCurrentAvatar(CombatScript combatScript) + // { + // var isCurrentAvatar = false; + // if (combatScript.AvatarNames.Count == 1) + // { + // foreach (var avatarName in combatScript.AvatarNames) + // { + // if (avatarName == CombatScriptParser.CurrentAvatarName) + // { + // isCurrentAvatar = true; + // break; + // } + // } + // } + // + // return isCurrentAvatar; + // } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalCollectHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalCollectHandler.cs index 860f1f60..d4cf9e10 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalCollectHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalCollectHandler.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.GameTask.AutoFight.Config; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Model; +using BetterGenshinImpact.GameTask.AutoPathing.Model; using Microsoft.Extensions.Logging; using static BetterGenshinImpact.GameTask.Common.TaskControl; @@ -15,7 +16,7 @@ namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; /// public class ElementalCollectHandler(ElementalType elementalType) : IActionHandler { - public async Task RunAsync(CancellationToken ct) + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { var combatScenes = await RunnerContext.Instance.GetCombatScenes(ct); if (combatScenes == null) diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs index 3bda166c..d2d111f4 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/ElementalSkillHandler.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoPathing.Model; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; @@ -14,7 +15,7 @@ namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; [Obsolete] public class ElementalSkillHandler : IActionHandler { - public async Task RunAsync(CancellationToken ct) + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { Logger.LogInformation("执行 {Text}", "释放元素战技"); Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E); diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/IActionHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/IActionHandler.cs index b98016ab..7cd28d92 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/IActionHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/IActionHandler.cs @@ -1,9 +1,10 @@ using System.Threading; using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoPathing.Model; namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; public interface IActionHandler { - Task RunAsync(CancellationToken ct); + Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack=null); } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs index 9a6a1664..10f3920d 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NahidaCollectHandler.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.GameTask.AutoPathing.Model; using BetterGenshinImpact.Helpers; using Microsoft.Extensions.Logging; using Vanara.PInvoke; @@ -16,7 +17,7 @@ public class NahidaCollectHandler : IActionHandler { private DateTime lastETime = DateTime.MinValue; - public async Task RunAsync(CancellationToken ct) + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { Logger.LogInformation("执行 {Nhd} 长按E转圈拾取", "纳西妲"); diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs index 59ac298d..d3fe9747 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/NormalAttackHandler.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.Core.Simulator; using Microsoft.Extensions.Logging; using System.Threading; using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoPathing.Model; using static BetterGenshinImpact.GameTask.Common.TaskControl; namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; @@ -13,7 +14,7 @@ namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; [Obsolete] public class NormalAttackHandler : IActionHandler { - public async Task RunAsync(CancellationToken ct) + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { Logger.LogInformation("执行 {Text}", "普通攻击"); Simulation.SendInput.Mouse.LeftButtonClick(); diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs index 88724b2f..694620e9 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/PickAroundHandler.cs @@ -4,6 +4,7 @@ using BetterGenshinImpact.GameTask.Common; using Microsoft.Extensions.Logging; using System.Threading; using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoPathing.Model; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; @@ -14,7 +15,7 @@ namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; /// public class PickAroundHandler : IActionHandler { - public async Task RunAsync(CancellationToken ct) + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { var screen = CaptureToRectArea(); var angle = 0; diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs index 4e6abc1d..b6d7c166 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/UpDownGrabLeaf.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.GameTask.AutoPathing.Model; using Microsoft.Extensions.Logging; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; @@ -13,7 +14,7 @@ namespace BetterGenshinImpact.GameTask.AutoPathing.Handler; /// public class UpDownGrabLeaf : IActionHandler { - public async Task RunAsync(CancellationToken ct) + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { await Delay(500, ct); Logger.LogInformation("开始上下晃动视角抓{Syy}", "四叶印"); diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Model/Enum/ActionEnum.cs b/BetterGenshinImpact/GameTask/AutoPathing/Model/Enum/ActionEnum.cs index 2c6e5804..d41fde62 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Model/Enum/ActionEnum.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Model/Enum/ActionEnum.cs @@ -14,6 +14,8 @@ public class ActionEnum(string code, string msg) public static readonly ActionEnum HydroCollect = new("hydro_collect", "水元素力采集"); public static readonly ActionEnum ElectroCollect = new("electro_collect", "雷元素力采集"); public static readonly ActionEnum AnemoCollect = new("anemo_collect", "风元素力采集"); + + public static readonly ActionEnum CombatScript = new("combat_script", "战斗策略脚本"); // 这个必须要 action_params 里面有脚本 // 还有要加入的其他动作 // 滚轮F diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs b/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs index 44754769..786b3402 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs @@ -23,4 +23,6 @@ public class Waypoint /// /// public string? Action { get; set; } + + public string? ActionParams { get; set; } } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs b/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs index 01278f72..1224d7bc 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs @@ -1,5 +1,7 @@ using BetterGenshinImpact.GameTask.Common.Map; using System; +using BetterGenshinImpact.GameTask.AutoFight.Script; +using BetterGenshinImpact.GameTask.AutoPathing.Model.Enum; namespace BetterGenshinImpact.GameTask.AutoPathing.Model; @@ -15,6 +17,11 @@ public class WaypointForTrack : Waypoint public double MatX { get; set; } public double MatY { get; set; } + + /// + /// 存在 combat_script 的 action 的话,这个值会存在 + /// + public CombatScript? CombatScript { get; set; } public WaypointForTrack(Waypoint waypoint) { @@ -27,5 +34,10 @@ public class WaypointForTrack : Waypoint (MatX, MatY) = MapCoordinate.GameToMain2048(waypoint.X, waypoint.Y); X = MatX; Y = MatY; + + if (waypoint.Action == ActionEnum.CombatScript.Code && waypoint.ActionParams is { } str) + { + CombatScript = CombatScriptParser.ParseContext(str, false); + } } } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs index 5eaf5abf..fffbbcaf 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs @@ -126,10 +126,14 @@ public class PathExecutor(CancellationToken ct) // Path不用走得很近,Target需要接近,但都需要先移动到对应位置 await MoveTo(waypoint); - if (waypoint.Type == WaypointType.Target.Code || !string.IsNullOrEmpty(waypoint.Action)) + if (waypoint.Type == WaypointType.Target.Code ) { await MoveCloseTo(waypoint); - // 到达点位后执行 action + } + + if (!string.IsNullOrEmpty(waypoint.Action)) + { + // 执行 action await AfterMoveToTarget(waypoint); } } @@ -611,17 +615,18 @@ public class PathExecutor(CancellationToken ct) } } - private async Task AfterMoveToTarget(Waypoint waypoint) + private async Task AfterMoveToTarget(WaypointForTrack waypoint) { if (waypoint.Action == ActionEnum.NahidaCollect.Code || waypoint.Action == ActionEnum.PickAround.Code || waypoint.Action == ActionEnum.Fight.Code || waypoint.Action == ActionEnum.HydroCollect.Code || waypoint.Action == ActionEnum.ElectroCollect.Code - || waypoint.Action == ActionEnum.AnemoCollect.Code) + || waypoint.Action == ActionEnum.AnemoCollect.Code + || waypoint.Action == ActionEnum.CombatScript.Code) { var handler = ActionFactory.GetAfterHandler(waypoint.Action); - await handler.RunAsync(ct); + await handler.RunAsync(ct, waypoint); await Delay(1000, ct); } }