Files
better-genshin-impact/BetterGenshinImpact/App.xaml.cs
2026-01-01 14:10:26 +08:00

323 lines
12 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.Core.Recognition.OCR;
using BetterGenshinImpact.Core.Recognition.ONNX;
using BetterGenshinImpact.GameTask;
using BetterGenshinImpact.Helpers;
using BetterGenshinImpact.Helpers.Extensions;
using BetterGenshinImpact.Helpers.Win32;
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;
// Wine 平台适配
using BetterGenshinImpact.Platform.Wine;
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,
retainedFileCountLimit: 31,
retainedFileTimeLimit: TimeSpan.FromDays(21))
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.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>();
services.AddSingleton<BgiOnnxFactory>();
services.AddSingleton<OcrFactory>();
services.AddSingleton(TimeProvider.System);
services.AddSingleton<IServerTimeProvider, ServerTimeProvider>();
// Configuration
//services.Configure<AppConfig>(context.Configuration.GetSection(nameof(AppConfig)));
}
)
.Build();
public static IServiceProvider ServiceProvider => _host.Services;
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)
{
// Wine 平台适配
WinePlatformAddon.ApplyApplicationConfig();
base.OnStartup(e);
try
{
// 分配控制台窗口以支持控制台输出
ConsoleHelper.AllocateConsole("BetterGI Console");
RegisterEvents();
await _host.StartAsync();
ServerTimeHelper.Initialize(_host.Services.GetRequiredService<IServerTimeProvider>());
await UrlProtocolHelper.RegisterAsync();
}
catch (Exception ex)
{
// DEBUG only, no overhead
Debug.WriteLine(ex);
ConsoleHelper.WriteError($"应用程序启动失败: {ex.Message}");
if (Debugger.IsAttached)
{
Debugger.Break();
}
}
}
/// <summary>
/// Occurs when the application is closing.
/// </summary>
protected override async void OnExit(ExitEventArgs e)
{
base.OnExit(e);
ConsoleHelper.WriteLine("BetterGI 应用程序正在关闭...");
TempManager.CleanUp();
await _host.StopAsync();
_host.Dispose();
// 释放控制台窗口
ConsoleHelper.FreeConsoleWindow();
}
/// <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");
}
}