diff --git a/BetterGenshinImpact/Core/Script/Group/ScriptGroupProject.cs b/BetterGenshinImpact/Core/Script/Group/ScriptGroupProject.cs
index 09843a82..84630aad 100644
--- a/BetterGenshinImpact/Core/Script/Group/ScriptGroupProject.cs
+++ b/BetterGenshinImpact/Core/Script/Group/ScriptGroupProject.cs
@@ -1,6 +1,10 @@
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.Core.Recorder;
using BetterGenshinImpact.Core.Script.Project;
+using BetterGenshinImpact.GameTask;
+using BetterGenshinImpact.GameTask.AutoPathing;
+using BetterGenshinImpact.GameTask.AutoPathing.Model;
+using BetterGenshinImpact.ViewModel.Pages;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
@@ -64,14 +68,30 @@ public partial class ScriptGroupProject : ObservableObject
Type = "Javascript";
}
- public ScriptGroupProject(string kmName)
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// KeyMouse|Pathing
+ public ScriptGroupProject(string name, string folder, string type)
{
- Name = kmName;
- FolderName = kmName;
+ Name = name;
+ FolderName = folder;
Status = "Enabled";
Schedule = "Daily";
Project = null; // 不是JS脚本
- Type = "KeyMouse";
+ Type = type;
+ }
+
+ public static ScriptGroupProject BuildKeyMouseProject(string name)
+ {
+ return new ScriptGroupProject(name, name, "KeyMouse");
+ }
+
+ public static ScriptGroupProject BuildPathingProject(string name, string folder)
+ {
+ return new ScriptGroupProject(name, folder, "Pathing");
}
///
@@ -102,6 +122,13 @@ public partial class ScriptGroupProject : ObservableObject
var json = await File.ReadAllTextAsync(Global.Absolute(@$"User\KeyMouseScript\{Name}"));
await KeyMouseMacroPlayer.PlayMacro(json, CancellationContext.Instance.Cts.Token, false);
}
+ if (Type == "Pathing")
+ {
+ // 加载并执行
+ var task = PathingTask.BuildFromFilePath(Path.Combine(MapPathingViewModel.PathJsonPath, FolderName, Name));
+ TaskTriggerDispatcher.Instance().AddTrigger("AutoPick", null);
+ await new PathExecutor(CancellationContext.Instance.Cts).Pathing(task);
+ }
else
{
//throw new Exception("不支持的脚本类型");
@@ -129,7 +156,8 @@ public class ScriptGroupProjectExtensions
public static readonly Dictionary TypeDescriptions = new()
{
{ "Javascript", "JS脚本" },
- { "KeyMouse", "键鼠脚本" }
+ { "KeyMouse", "键鼠脚本" },
+ { "Pathing", "路径追踪" }
};
public static readonly Dictionary StatusDescriptions = new()
diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Model/PathingTask.cs b/BetterGenshinImpact/GameTask/AutoPathing/Model/PathingTask.cs
index d0e6a345..be965284 100644
--- a/BetterGenshinImpact/GameTask/AutoPathing/Model/PathingTask.cs
+++ b/BetterGenshinImpact/GameTask/AutoPathing/Model/PathingTask.cs
@@ -3,19 +3,28 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
+using System.Text.Json.Serialization;
namespace BetterGenshinImpact.GameTask.AutoPathing.Model;
[Serializable]
public class PathingTask
{
+ ///
+ /// 实际存储的文件名
+ ///
+ [JsonIgnore]
+ public string FileName { get; set; } = string.Empty;
+
public PathingTaskInfo Info { get; set; } = new();
public List Positions { get; set; } = [];
public static PathingTask BuildFromFilePath(string filePath)
{
var json = File.ReadAllText(filePath);
- return JsonSerializer.Deserialize(json, PathRecorder.JsonOptions) ?? throw new Exception("Failed to deserialize PathingTask");
+ var task = JsonSerializer.Deserialize(json, PathRecorder.JsonOptions) ?? throw new Exception("Failed to deserialize PathingTask");
+ task.FileName = Path.GetFileName(filePath);
+ return task;
}
public void SaveToFile(string filePath)
diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Navigation.cs b/BetterGenshinImpact/GameTask/AutoPathing/Navigation.cs
index 9183556a..d3e65d18 100644
--- a/BetterGenshinImpact/GameTask/AutoPathing/Navigation.cs
+++ b/BetterGenshinImpact/GameTask/AutoPathing/Navigation.cs
@@ -10,16 +10,22 @@ using Microsoft.Extensions.Logging;
namespace BetterGenshinImpact.GameTask.AutoPathing;
-internal class Navigation
+public class Navigation
{
+ private static bool _isWarmUp = false;
+
public static void WarmUp()
{
- TaskControl.Logger.LogInformation("地图特征点加载中,由于体积较大,首次加载速度较慢,请耐心等待...");
- EntireMap.Instance.GetFeatureMatcher();
- TaskControl.Logger.LogInformation("地图特征点加载完成!");
+ if (!_isWarmUp)
+ {
+ TaskControl.Logger.LogInformation("地图特征点加载中,由于体积较大,首次加载速度较慢,请耐心等待...");
+ EntireMap.Instance.GetFeatureMatcher();
+ TaskControl.Logger.LogInformation("地图特征点加载完成!");
+ }
+ _isWarmUp = true;
}
- internal static Point2f GetPosition(ImageRegion imageRegion)
+ public static Point2f GetPosition(ImageRegion imageRegion)
{
var greyMat = new Mat(imageRegion.SrcGreyMat, new Rect(62, 19, 212, 212));
var p = EntireMap.Instance.GetMiniMapPositionByFeatureMatch(greyMat);
@@ -29,7 +35,7 @@ internal class Navigation
return p;
}
- internal static int GetTargetOrientation(Waypoint waypoint, Point2f position)
+ public static int GetTargetOrientation(Waypoint waypoint, Point2f position)
{
double deltaX = waypoint.X - position.X;
double deltaY = waypoint.Y - position.Y;
@@ -48,7 +54,7 @@ internal class Navigation
return (int)(angle * (180.0 / Math.PI));
}
- internal static double GetDistance(Waypoint waypoint, Point2f position)
+ public static double GetDistance(Waypoint waypoint, Point2f position)
{
var x1 = waypoint.X;
var y1 = waypoint.Y;
diff --git a/BetterGenshinImpact/GameTask/GameTaskManager.cs b/BetterGenshinImpact/GameTask/GameTaskManager.cs
index b0328f70..93814954 100644
--- a/BetterGenshinImpact/GameTask/GameTaskManager.cs
+++ b/BetterGenshinImpact/GameTask/GameTaskManager.cs
@@ -80,7 +80,7 @@ internal class GameTaskManager
public static void AddTrigger(string name, object? externalConfig)
{
TriggerDictionary ??= new ConcurrentDictionary();
- TriggerDictionary.Clear();
+ TriggerDictionary.Clear(); //TODO 有问题,不应该清理
if (name == "AutoPick")
{
diff --git a/BetterGenshinImpact/Service/ScriptService.cs b/BetterGenshinImpact/Service/ScriptService.cs
index b49b6013..d5100fc5 100644
--- a/BetterGenshinImpact/Service/ScriptService.cs
+++ b/BetterGenshinImpact/Service/ScriptService.cs
@@ -80,6 +80,8 @@ public partial class ScriptService(HomePageViewModel homePageViewModel) : IScrip
public async Task RunMulti(IEnumerable projectList, string groupName)
{
+ var hasTimer = false;
+
// 重新加载脚本项目 并放入一个新的列表
var list = new List();
foreach (var project in projectList)
@@ -93,14 +95,23 @@ public partial class ScriptService(HomePageViewModel homePageViewModel) : IScrip
newProject.JsScriptSettingsObject = project.JsScriptSettingsObject;
list.Add(newProject);
}
- else
+ else if (project.Type == "KeyMouse")
{
- var newProject = new ScriptGroupProject(project.FolderName);
+ var newProject = ScriptGroupProject.BuildKeyMouseProject(project.FolderName);
newProject.Status = project.Status;
newProject.Schedule = project.Schedule;
newProject.RunNum = project.RunNum;
list.Add(newProject);
}
+ else if (project.Type == "Pathing")
+ {
+ var newProject = ScriptGroupProject.BuildPathingProject(project.Name, project.FolderName);
+ newProject.Status = project.Status;
+ newProject.Schedule = project.Schedule;
+ newProject.RunNum = project.RunNum;
+ list.Add(newProject);
+ hasTimer = true; // 路径追踪任务一定有实时任务操作
+ }
}
// 判断其中的
@@ -112,9 +123,8 @@ public partial class ScriptService(HomePageViewModel homePageViewModel) : IScrip
jsProjects.Add(project.Project);
}
}
- var hasTimer = false;
- if (jsProjects.Count > 0)
+ if (!hasTimer && jsProjects.Count > 0)
{
var codeList = await ReadCodeList(jsProjects);
hasTimer = HasTimerOperation(codeList);
@@ -169,11 +179,16 @@ public partial class ScriptService(HomePageViewModel homePageViewModel) : IScrip
_logger.LogInformation("→ 开始执行JS脚本: {Name}", project.Name);
await project.Run();
}
- else
+ else if (project.Type == "KeyMouse")
{
_logger.LogInformation("→ 开始执行键鼠脚本: {Name}", project.Name);
await project.Run();
}
+ else if (project.Type == "Pathing")
+ {
+ _logger.LogInformation("→ 开始执行路径追踪任务: {Name}", project.Name);
+ await project.Run();
+ }
await Task.Delay(2000);
}
diff --git a/BetterGenshinImpact/View/Pages/MapPathingPage.xaml b/BetterGenshinImpact/View/Pages/MapPathingPage.xaml
index 0a9962df..999bc649 100644
--- a/BetterGenshinImpact/View/Pages/MapPathingPage.xaml
+++ b/BetterGenshinImpact/View/Pages/MapPathingPage.xaml
@@ -60,13 +60,13 @@
-
+
-
+
+
diff --git a/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs b/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs
index 782aea0f..14093048 100644
--- a/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs
+++ b/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs
@@ -43,6 +43,17 @@ public partial class PromptDialog
return inst.DialogResult == true ? inst.ResponseText : defaultValue;
}
+ public static string Prompt(string question, string title, UIElement uiElement, Size size)
+ {
+ var inst = new PromptDialog(question, title, uiElement, "")
+ {
+ Width = size.Width,
+ Height = size.Height
+ };
+ inst.ShowDialog();
+ return inst.DialogResult == true ? inst.ResponseText : "";
+ }
+
public string ResponseText
{
get
@@ -55,7 +66,10 @@ public partial class PromptDialog
{
return comboBox.Text;
}
- return string.Empty;
+ else
+ {
+ return "true";
+ }
}
}
diff --git a/BetterGenshinImpact/ViewModel/Pages/MapPathingViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/MapPathingViewModel.cs
index 10659daa..738957b1 100644
--- a/BetterGenshinImpact/ViewModel/Pages/MapPathingViewModel.cs
+++ b/BetterGenshinImpact/ViewModel/Pages/MapPathingViewModel.cs
@@ -1,6 +1,11 @@
using BetterGenshinImpact.Core.Config;
+using BetterGenshinImpact.Core.Script;
using BetterGenshinImpact.Core.Script.Project;
+using BetterGenshinImpact.GameTask;
+using BetterGenshinImpact.GameTask.AutoPathing;
using BetterGenshinImpact.GameTask.AutoPathing.Model;
+using BetterGenshinImpact.GameTask.Model.Enum;
+using BetterGenshinImpact.View.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
@@ -10,15 +15,8 @@ using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Threading.Tasks;
-using BetterGenshinImpact.Core.Script;
-using BetterGenshinImpact.GameTask;
-using BetterGenshinImpact.GameTask.AutoPathing;
-using BetterGenshinImpact.GameTask.Model.Enum;
-using BetterGenshinImpact.View.Windows;
using Wpf.Ui.Controls;
using Wpf.Ui.Violeta.Controls;
-using BetterGenshinImpact.Core.Script.Dependence.Model;
namespace BetterGenshinImpact.ViewModel.Pages;
diff --git a/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs
index 6d280e1b..0eac0653 100644
--- a/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs
+++ b/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs
@@ -156,10 +156,106 @@ public partial class ScriptControlViewModel : ObservableObject, INavigationAware
var str = PromptDialog.Prompt("请选择需要添加的键鼠脚本", "请选择需要添加的键鼠脚本", combobox);
if (!string.IsNullOrEmpty(str))
{
- SelectedScriptGroup?.Projects.Add(new ScriptGroupProject(str));
+ SelectedScriptGroup?.Projects.Add(ScriptGroupProject.BuildKeyMouseProject(str));
}
}
+ [RelayCommand]
+ private void OnAddPathing()
+ {
+ var directories = LoadAllPathingScripts();
+ var stackPanel = CreatePathingScriptSelectionPanel(directories);
+
+ var result = PromptDialog.Prompt("请选择需要添加的路径追踪任务", "请选择需要添加的路径追踪任务", stackPanel, new Size(500, 600));
+ if (!string.IsNullOrEmpty(result))
+ {
+ AddSelectedPathingScripts((StackPanel)stackPanel.Content);
+ }
+ }
+
+ private ScrollViewer CreatePathingScriptSelectionPanel(Dictionary> directories)
+ {
+ var stackPanel = new StackPanel();
+
+ foreach (var directory in directories)
+ {
+ var parentCheckBox = new CheckBox
+ {
+ Content = directory.Key,
+ Tag = directory.Value
+ };
+
+ var childStackPanel = new StackPanel();
+ foreach (var fileInfo in directory.Value)
+ {
+ var childCheckBox = new CheckBox
+ {
+ Content = fileInfo.Name,
+ Tag = fileInfo,
+ Margin = new Thickness(30, 0, 0, 0)
+ };
+ childStackPanel.Children.Add(childCheckBox);
+ }
+
+ parentCheckBox.Checked += (s, e) => SetChildCheckBoxesState(childStackPanel, true);
+ parentCheckBox.Unchecked += (s, e) => SetChildCheckBoxesState(childStackPanel, false);
+
+ stackPanel.Children.Add(parentCheckBox);
+ stackPanel.Children.Add(childStackPanel);
+ }
+
+ var scrollViewer = new ScrollViewer
+ {
+ Content = stackPanel,
+ VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
+ Height = 435 // 固定高度
+ };
+
+ return scrollViewer;
+ }
+
+ private void SetChildCheckBoxesState(StackPanel childStackPanel, bool state)
+ {
+ foreach (CheckBox child in childStackPanel.Children)
+ {
+ child.IsChecked = state;
+ }
+ }
+
+ private void AddSelectedPathingScripts(StackPanel stackPanel)
+ {
+ foreach (var child in stackPanel.Children)
+ {
+ if (child is StackPanel childStackPanel)
+ {
+ foreach (var grandChild in childStackPanel.Children)
+ {
+ if (grandChild is CheckBox checkBox && checkBox.IsChecked == true)
+ {
+ var fileInfo = (FileInfo)checkBox.Tag;
+ SelectedScriptGroup?.Projects.Add(ScriptGroupProject.BuildPathingProject(fileInfo.Name, fileInfo.DirectoryName));
+ }
+ }
+ }
+ }
+ }
+
+ private Dictionary> LoadAllPathingScripts()
+ {
+ var folder = Global.Absolute(@"User\AutoPathing");
+ var directories = Directory.GetDirectories(folder);
+ var result = new Dictionary>();
+
+ foreach (var directory in directories)
+ {
+ var dirInfo = new DirectoryInfo(directory);
+ var files = dirInfo.GetFiles("*.*", SearchOption.TopDirectoryOnly).ToList();
+ result.Add(dirInfo.Name, files);
+ }
+
+ return result;
+ }
+
private List LoadAllJsScriptProjects()
{
var path = Global.ScriptPath();
@@ -465,6 +561,9 @@ public partial class ScriptControlViewModel : ObservableObject, INavigationAware
return;
}
- await _scriptService.RunMulti(SelectedScriptGroup.Projects, SelectedScriptGroup.Name);
+ await Task.Run(async () =>
+ {
+ await _scriptService.RunMulti(SelectedScriptGroup.Projects, SelectedScriptGroup.Name);
+ });
}
}