Merge branch 'main' into d-v3

This commit is contained in:
辉鸭蛋
2026-05-09 01:14:31 +08:00
7 changed files with 122 additions and 15 deletions

4
.gitignore vendored
View File

@@ -31,10 +31,6 @@ github_actions_cache/
# Rider
.idea
.claude
CLAUDE.md
AGENTS.md
__pycache__/

View File

@@ -14,7 +14,8 @@
- 请尽量使用 Behaviors 库来实现交互,避免不符合 MVVM 规范的交互事件触发方式。
### 其他框架使用要求
请优先使用 Newtonsoft.Json 作为json序列化工具但是如果这个模型已经被System.Text.Json序列化过了那么就直接使用System.Text.Json反序列化。
1. 请优先使用 Newtonsoft.Json 作为json序列化工具但是如果这个模型已经被System.Text.Json序列化过了那么就直接使用System.Text.Json反序列化。
2. 所有简单的对话框弹出需求优先使用 ThemedMessageBox 弹出。而不是 WPF 自带的 MessageBox。
## MVVM 架构规则
@@ -77,4 +78,9 @@
services.AddSingleton<IExampleService, ExampleService>();
```
最后,程序能够编译就认为成功,无需实际运行程序。
最后,程序能够编译就认为成功,无需实际运行程序。
编译指令参考,如果出现程序占用场景,直接放弃编译验证即可
```
dotnet build BetterGenshinImpact.sln -c Debug
```

86
AGENTS.md Normal file
View File

@@ -0,0 +1,86 @@
本项目使用了 WPF-UI、 CommunityToolkit.Mvvm、Microsoft.Xaml.Behaviors.Wpf 来实现 MVVM 架构。在编写代码的时候请注意:
### 主要依赖框架
#### UI 框架
- **WPF-UI (4.0.2)** - 现代化 WPF UI 框架
- **gong-wpf-dragdrop(3.2.1)** - 拖拽框架
#### MVVM 框架
- **CommunityToolkit.Mvvm (8.2.2)** - 微软官方 MVVM 工具包
- 所有 ViewModel 必须继承自 `ObservableObject`
- 使用 `[ObservableProperty]` 特性自动生成属性
- 使用 `[RelayCommand]` 特性自动生成命令
- **Microsoft.Xaml.Behaviors.Wpf(1.1.122)** - WPF 行为扩展库
- 请尽量使用 Behaviors 库来实现交互,避免不符合 MVVM 规范的交互事件触发方式。
### 其他框架使用要求
1. 请优先使用 Newtonsoft.Json 作为json序列化工具但是如果这个模型已经被System.Text.Json序列化过了那么就直接使用System.Text.Json反序列化。
2. 所有简单的对话框弹出需求优先使用 ThemedMessageBox 弹出。而不是 WPF 自带的 MessageBox。
## MVVM 架构规则
### 基础架构
### ViewModel 编写规范
1. **继承规则**
```csharp
public partial class ExampleViewModel : ViewModel
{
[ObservableProperty]
private string _title = "";
[RelayCommand]
private void DoSomething()
{
// 实现逻辑
}
}
```
2. **属性命名**
- 私有字段使用下划线前缀: `_fieldName`
- 公共属性使用 PascalCase: `PropertyName`
- 使用 `[ObservableProperty]` 自动生成属性
3. **命令实现**
- 使用 `[RelayCommand]` 特性
- 异步命令使用 `[RelayCommand]` + `async Task`
### View 编写规范
1. **代码后置**
```csharp
public partial class ExamplePage : UserControl
{
public ExampleViewModel ViewModel { get; }
public ExamplePage(ExampleViewModel viewModel)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
}
}
```
2. **XAML 绑定**
- 使用 `{Binding}` 语法绑定 ViewModel 属性
- 命令绑定: `Command="{Binding ExampleCommand}"`
- 避免在 XAML 中编写复杂逻辑
### 依赖注入规范
1. **服务注册**
```csharp
// 在 App.xaml.cs 中注册
services.AddView<ExamplePage, ExampleViewModel>();
services.AddSingleton<IExampleService, ExampleService>();
```
最后,程序能够编译就认为成功,无需实际运行程序。
编译指令参考,如果出现程序占用场景,直接放弃编译验证即可
```
dotnet build BetterGenshinImpact.sln -c Debug
```

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyName>BetterGI</AssemblyName>
<Version>0.60.2-alpha.3</Version>
<Version>0.60.2-alpha.4</Version>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>

View File

@@ -208,4 +208,16 @@ public class BvLocator
RetryAction = action;
return this;
}
/// <summary>
/// 为 JavaScript 提供的动态参数重载
/// 解决 ClearScript 无法将 JS 函数隐式转换为 Action 委托的问题
/// </summary>
/// <param name="action">JS 回调函数</param>
/// <returns></returns>
public BvLocator WithRetryAction(dynamic action)
{
RetryAction = (results) => action(results);
return this;
}
}

View File

@@ -22,6 +22,7 @@ public class AutoFightAssets : BaseAssets<AutoFightAssets>
public Rect ERect;
public Rect ECooldownRect;
public Rect QRect;
public Rect QRectForClassify;
public Rect ZCooldownRect;
public Rect EndTipsUpperRect; // 挑战达成提示
public Rect EndTipsRect;
@@ -78,6 +79,8 @@ public class AutoFightAssets : BaseAssets<AutoFightAssets>
(int)(41 * AssetScale), (int)(18 * AssetScale));
QRect = new Rect(CaptureRect.Width - (int)(157 * AssetScale), CaptureRect.Height - (int)(165 * AssetScale),
(int)(110 * AssetScale), (int)(110 * AssetScale));
QRectForClassify = new Rect(CaptureRect.Width - (int)(172 * AssetScale), CaptureRect.Height - (int)(166 * AssetScale),
(int)(137 * AssetScale), (int)(137 * AssetScale));
ZCooldownRect = new Rect(CaptureRect.Width - (int)(130 * AssetScale), (int)(814 * AssetScale),
(int)(60 * AssetScale), (int)(24 * AssetScale));
// 小道具位置 1920-133,800,60,50

View File

@@ -25,6 +25,7 @@ using BetterGenshinImpact.GameTask.AutoPathing;
using BetterGenshinImpact.GameTask.AutoPathing.Model;
using BetterGenshinImpact.GameTask.AutoPathing.Model.Enum;
using BetterGenshinImpact.Core.Recognition.ONNX;
using BetterGenshinImpact.GameTask.Common;
using Compunet.YoloSharp;
using Compunet.YoloSharp.Data;
using Microsoft.Extensions.DependencyInjection;
@@ -600,8 +601,9 @@ public class Avatar
{
// CD 中立即返回,其余场景尝试释放
using var region1 = CaptureToRectArea();
if (IsBurstReadyByClassify(region1) == BurstReadyState.Cooldown)
if (IsBurstReadyByClassify(region1) != BurstReadyState.Ready)
{
// Logger.LogInformation("Q在CD跳过");
return;
}
@@ -612,6 +614,7 @@ public class Avatar
return;
}
// Logger.LogInformation("释放Q");
Simulation.SendInput.SimulateAction(GIActions.ElementalBurst);
Sleep(200, Ct);
@@ -627,8 +630,9 @@ public class Avatar
else
{
// 找到编号块判断是否进入了CD四星角色没有大招动画
if (IsBurstReadyByClassify(region) == BurstReadyState.Cooldown)
if (IsBurstReadyByClassify(region) != BurstReadyState.Ready)
{
// Logger.LogInformation("释放Q后检查到CD");
Sleep(1500, Ct);
return;
}
@@ -638,29 +642,29 @@ public class Avatar
private static BurstReadyState IsBurstReadyByClassify(ImageRegion imageRegion)
{
using var qRa = imageRegion.DeriveCrop(AutoFightAssets.Instance.QRect);
using var qRa = imageRegion.DeriveCrop(AutoFightAssets.Instance.QRectForClassify);
var result = QBurstClassifierLazy.Value.Predictor.Classify(qRa.CacheImage);
var topClass = result.GetTopClass();
var topClassName = topClass.Name.Name;
// Logger.LogInformation("Q技能冷却分类{ClassName},置信度:{Confidence:F2}", topClassName, topClass.Confidence);
// 置信度不足时,直接返回未知,避免误判导致漏放/乱放
if (topClass.Confidence <= 0.7)
{
Logger.LogDebug("Q技能冷却分类置信度不足{Confidence:F2},类别:{ClassName}", topClass.Confidence, topClassName);
// Logger.LogInformation("Q技能冷却分类置信度不足{Confidence:F2},类别:{ClassName}", topClass.Confidence, topClassName);
return BurstReadyState.Unknown;
}
if (topClassName.Contains("cd_1", StringComparison.OrdinalIgnoreCase))
if (topClassName.Contains("cd 1", StringComparison.OrdinalIgnoreCase))
{
return BurstReadyState.Cooldown;
}
if (topClassName.Contains("cd_0", StringComparison.OrdinalIgnoreCase))
if (topClassName.Contains("energy 1 cd 0", StringComparison.OrdinalIgnoreCase))
{
return BurstReadyState.Ready;
}
Logger.LogDebug("Q技能冷却分类出现未知类别{ClassName},置信度:{Confidence:F2}", topClassName, topClass.Confidence);
return BurstReadyState.Unknown;
}