Files
better-genshin-impact/BetterGenshinImpact/App.xaml.cs
FishmanTheMurloc 6d4f8b80e8 Feat/multi lan (#1336)
* 记录一次对hutaofisher的访谈,帮助开发者理解其算法

* 本地化HelloWorld

* .csproj取消windows版本号,此处导致了IDE在新建代码文件和自动生成代码时,默认命名空间丢失的问题。已知VisualStudio和ReSharper存在这个问题。

* 优化扩展方法写法,改为从localizer扩展;Converter优化写法,避免冲突;新增两种语言,待测试ocr效果

* Revert ".csproj取消windows版本号,此处导致了IDE在新建代码文件和自动生成代码时,默认命名空间丢失的问题。已知VisualStudio和ReSharper存在这个问题。"

This reverts commit 8bd7ee74c5.

* localizer改为由构造函数传入以支持单元测试;一个英语上钩的单元测试

* 传送任务支持英语游戏界面;本地化参数挪至OtherConfig类下,但界面位置暂不挪动,待定

* 调整resx位置风格,放在直接使用字符串的类下;一条龙合成树脂及领取每日奖励支持游戏内中英双语

* 删除无用碎片文件

* 删去两个不必要的Sdcb包引用

* Paddle服务类去掉分类模型;检测和识别新增支持繁中和法语,配有单元测试;因小语种识别效果不理想,使用正则匹配替换多处识别文本相等或包含判断;钓鱼、一条龙合成树脂及领取每日奖励支持游戏内繁中和法语;

* 检查今日奖励任务的多语言化;右侧联机的P图标检测区域宽度缩减,避免英语角色名被误识别成P

* AutoDomainTask的游戏多语言化,由于我的游戏账号无法测试,仅配一些测试用例

* 修复有3个Mizuki导致异常的bug,临时用拼音代替新角色英文名,并为该数据初始化方法添加单元测试

* 瓦雷莎删去别名“牛牛”,因荒泷一斗已占用此别名;别名加载和读取优化

* 加个锁避免单元测试中多线程初始化paddle崩溃
2025-03-28 11:00:08 +08:00

295 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using BetterGenshinImpact.GameTask;
using BetterGenshinImpact.Helpers;
using BetterGenshinImpact.Helpers.Extensions;
using BetterGenshinImpact.Hutao;
using BetterGenshinImpact.Service;
using BetterGenshinImpact.Service.Interface;
using BetterGenshinImpact.Service.Notification;
using BetterGenshinImpact.Service.Notifier;
using BetterGenshinImpact.View;
using BetterGenshinImpact.View.Pages;
using BetterGenshinImpact.ViewModel;
using BetterGenshinImpact.ViewModel.Pages;
using BetterGenshinImpact.ViewModel.Pages.View;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.RichTextBox.Abstraction;
using Wpf.Ui;
using Wpf.Ui.DependencyInjection;
using Wpf.Ui.Violeta.Controls;
namespace BetterGenshinImpact;
public partial class App : Application
{
// The.NET Generic Host provides dependency injection, configuration, logging, and other services.
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
// https://docs.microsoft.com/dotnet/core/extensions/configuration
// https://docs.microsoft.com/dotnet/core/extensions/logging
private static readonly IHost _host = Host.CreateDefaultBuilder()
.CheckIntegration()
.UseElevated()
.UseSingleInstance("BetterGI")
.ConfigureLogging(builder => { builder.ClearProviders(); })
.ConfigureServices(
(context, services) =>
{
// 提前初始化配置
var configService = new ConfigService();
services.AddSingleton<IConfigService>(sp => configService);
var all = configService.Get();
var logFolder = Path.Combine(AppContext.BaseDirectory, "log");
Directory.CreateDirectory(logFolder);
var logFile = Path.Combine(logFolder, "better-genshin-impact.log");
var richTextBox = new RichTextBoxImpl();
services.AddSingleton<IRichTextBox>(richTextBox);
var loggerConfiguration = new LoggerConfiguration()
.WriteTo.File(logFile,
outputTemplate:
"[{Timestamp:HH:mm:ss.fff}] [{Level:u3}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}",
rollingInterval: RollingInterval.Day)
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Warning);
if (all.MaskWindowConfig.MaskEnabled)
{
loggerConfiguration.WriteTo.RichTextBox(richTextBox, LogEventLevel.Information,
"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}");
}
Log.Logger = loggerConfiguration.CreateLogger();
services.AddLogging(c => c.AddSerilog());
services.AddLocalization();
services.AddNavigationViewPageProvider();
// App Host
services.AddHostedService<ApplicationHostService>();
// Page resolver service
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IUpdateService, UpdateService>();
// Service containing navigation, same as INavigationWindow... but without window
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<ISnackbarService, SnackbarService>();
// Main window with navigation
services.AddView<INavigationWindow, MainWindow, MainWindowViewModel>();
services.AddSingleton<NotifyIconViewModel>();
// Views
services.AddView<HomePage, HomePageViewModel>();
services.AddView<ScriptControlPage, ScriptControlViewModel>();
services.AddView<TriggerSettingsPage, TriggerSettingsPageViewModel>();
services.AddView<MacroSettingsPage, MacroSettingsPageViewModel>();
services.AddView<CommonSettingsPage, CommonSettingsPageViewModel>();
services.AddView<TaskSettingsPage, TaskSettingsPageViewModel>();
services.AddView<HotKeyPage, HotKeyPageViewModel>();
services.AddView<NotificationSettingsPage, NotificationSettingsPageViewModel>();
services.AddView<KeyMouseRecordPage, KeyMouseRecordPageViewModel>();
services.AddView<JsListPage, JsListViewModel>();
services.AddView<MapPathingPage, MapPathingViewModel>();
services.AddView<OneDragonFlowPage, OneDragonFlowViewModel>();
services.AddSingleton<PathingConfigViewModel>();
// services.AddView<PathingConfigView, PathingConfigViewModel>();
services.AddView<KeyBindingsSettingsPage, KeyBindingsSettingsPageViewModel>();
// 一条龙 ViewModels
// services.AddSingleton<CraftViewModel>();
// services.AddSingleton<DailyCommissionViewModel>();
// services.AddSingleton<DailyRewardViewModel>();
// services.AddSingleton<DomainViewModel>();
// services.AddSingleton<ForgingViewModel>();
// services.AddSingleton<LeyLineBlossomViewModel>();
// services.AddSingleton<MailViewModel>();
// services.AddSingleton<SereniteaPotViewModel>();
// services.AddSingleton<TcgViewModel>();
// My Services
services.AddSingleton<TaskTriggerDispatcher>();
services.AddSingleton<NotificationService>();
services.AddHostedService(sp => sp.GetRequiredService<NotificationService>());
services.AddSingleton<NotifierManager>();
services.AddSingleton<IScriptService, ScriptService>();
services.AddSingleton<HutaoNamedPipe>();
// Configuration
//services.Configure<AppConfig>(context.Configuration.GetSection(nameof(AppConfig)));
}
)
.Build();
public static ILogger<T> GetLogger<T>()
{
return _host.Services.GetService<ILogger<T>>()!;
}
/// <summary>
/// Gets registered service.
/// </summary>
/// <typeparam name="T">Type of the service to get.</typeparam>
/// <returns>Instance of the service or <see langword="null"/>.</returns>
public static T? GetService<T>() where T : class
{
return _host.Services.GetService(typeof(T)) as T;
}
/// <summary>
/// Gets registered service.
/// </summary>
/// <returns>Instance of the service or <see langword="null"/>.</returns>
/// <returns></returns>
public static object? GetService(Type type)
{
return _host.Services.GetService(type);
}
/// <summary>
/// Occurs when the application is loading.
/// </summary>
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
try
{
RegisterEvents();
await _host.StartAsync();
await UrlProtocolHelper.RegisterAsync();
}
catch (Exception ex)
{
// DEBUG only, no overhead
Debug.WriteLine(ex);
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
}
/// <summary>
/// Occurs when the application is closing.
/// </summary>
protected override async void OnExit(ExitEventArgs e)
{
base.OnExit(e);
TempManager.CleanUp();
await _host.StopAsync();
_host.Dispose();
}
/// <summary>
/// 注册事件
/// </summary>
private void RegisterEvents()
{
//Task线程内未捕获异常处理事件
TaskScheduler.UnobservedTaskException += TaskSchedulerUnobservedTaskException;
//UI线程未捕获异常处理事件UI主线程
this.DispatcherUnhandledException += AppDispatcherUnhandledException;
//非UI线程未捕获异常处理事件(例如自己创建的一个子线程)
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
}
private static void TaskSchedulerUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
{
try
{
HandleException(e.Exception);
}
catch (Exception ex)
{
HandleException(ex);
}
finally
{
e.SetObserved();
}
}
//非UI线程未捕获异常处理事件(例如自己创建的一个子线程)
private static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
if (e.ExceptionObject is Exception exception)
{
HandleException(exception);
}
}
catch (Exception ex)
{
HandleException(ex);
}
finally
{
//ignore
}
}
//UI线程未捕获异常处理事件UI主线程
private static void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
try
{
HandleException(e.Exception);
}
catch (Exception ex)
{
HandleException(ex);
}
finally
{
//处理完后我们需要将Handler=true表示已此异常已处理过
e.Handled = true;
}
}
private static void HandleException(Exception e)
{
if (e.InnerException != null)
{
e = e.InnerException;
}
try
{
ExceptionReport.Show(e);
}
catch
{
// Fallback.
System.Windows.Forms.MessageBox.Show(
$"""
程序异常:{e.Source}
--
{e.StackTrace}
--
{e.Message}
"""
);
}
// log
GetLogger<App>().LogDebug(e, "UnHandle Exception");
}
}