using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using Cysharp.Threading.Tasks; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; #if NET5_0_OR_GREATER using Microsoft.Extensions.DependencyInjection; #endif namespace BITKit { public class AppIsNotPlayingException : Exception { public override string Message => "Application Is Not Playing"; } public class BITApp { public static class Time { public static float DeltaTime { get; internal set; } public static double TimeAsDouble { get; internal set; } } [System.Serializable] public record AppSettings { public List whiteList = new(); public List blackList = new() { "System", "Unity", "UnityEngine", "Microsoft", "Godot", "Internal", "GodotPlugins", // ReSharper disable once StringLiteralTypo "Cysharp", "kcp2k", }; } #if NET5_0_OR_GREATER /// /// 依赖服务集合 /// public static ServiceCollection ServiceCollection { get; internal set; } = new(); /// /// 依赖服务提供接口 /// public static ServiceProvider ServiceProvider { get; private set; } /// /// 服务创建后的回调 /// public static Action OnServiceProviderBuilded; #endif /// /// 主线程 /// public static SynchronizationContext SynchronizationContext { get; private set; } [System.Serializable] public class OpenPath : IAction, IDisposable { public string path; public void Dispose() { path = null; } public void Execute() { path = path.Replace(@"/", @"\"); BIT4Log.Log($"正在打开文件夹:{path}"); try { var process = Process.Start("explorer.exe", path); SwitchToThisWindow(process.MainWindowHandle, true); } catch (System.Exception e) { BIT4Log.LogException(e); } } } [System.Serializable] public class OpenAPP : IAction, IDisposable { public string path; public string WorkingDirectory; public void Dispose() { path = WorkingDirectory = null; } public void Execute() { if (File.Exists(path)) { ProcessStartInfo startInfo = new(path) { UseShellExecute = true }; if (string.IsNullOrEmpty(WorkingDirectory) is false) { startInfo.WorkingDirectory = WorkingDirectory; } var process = Process.Start(startInfo); SwitchToThisWindow(process.MainWindowHandle, true); } } } [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern bool SwitchToThisWindow(IntPtr hWnd, bool fAltTab); public static string AppName { get; private set; } = nameof(BITApp); public static CancellationTokenSource CancellationTokenSource = new(); public static InitializationState State; public static Assembly[] Assemblies; public static AppSettings Settings { get; protected set; } static IEnumerable excuteOnAwake; static IEnumerable excuteOnStart; static IEnumerable excuteOnStops; public static async void Start(string appName = nameof(BITApp),AppSettings settings=default) { Time.TimeAsDouble = 0; Time.DeltaTime = 1 / 60f; SynchronizationContext=SynchronizationContext.Current; Settings = settings??new AppSettings(); CancellationTokenSource = new CancellationTokenSource(); AppName = appName; ThreadHelper.LogCurrentThread(); await Init(); } static async Task Init() { try { if (State is not InitializationState.None) { BIT4Log.Warnning("警告:上次启动可能未正确退出"); State = InitializationState.None; } //加载app-settings.json var appSettingsPath = Path.Combine(Environment.CurrentDirectory, "appsettings.json"); if (PathHelper.TryGetText(appSettingsPath,out var json)) { DataParser.Set(json); BIT4Log.Log("已加载全局appsettings"); } //内部反射初始化 ThreadHelper.InitAPP(); await UniTask.SwitchToThreadPool(); ThreadHelper.LogCurrentThread(); Stopwatch stopwatch = new(); stopwatch.Start(); Stopwatch reflectionHelperWatch = new(); reflectionHelperWatch.Start(); ReflectionHelper.Init(); reflectionHelperWatch.Stop(); excuteOnAwake = await ReflectionHelper.GetMethods(); excuteOnStart = await ReflectionHelper.GetMethods(); excuteOnStops = await ReflectionHelper.GetMethods(); foreach (var x in excuteOnAwake) { x.Invoke(null, null); if (CancellationTokenSource.IsCancellationRequested) return; } foreach (var x in excuteOnStart) { x.Invoke(null, null); if (CancellationTokenSource.IsCancellationRequested) return; } stopwatch.Stop(); State = InitializationState.Initialized; BIT4Log.Log($"初始化耗时:{stopwatch.ElapsedMilliseconds}ms"); BIT4Log.Log($"已完成初始化"); } catch (System.Exception e) { BIT4Log.Warnning($"{nameof(BITApp)}初始化错误:"); BIT4Log.LogException(e); } } public static async Task Stop() { BIT4Log.Log($"正在停止{nameof(BITApp)}"); CancellationTokenSource.Cancel(); try { foreach (var x in excuteOnStops) { x.Invoke(null, null); } } catch (System.Exception e) { if (e is not NullReferenceException) BIT4Log.LogException(e); } await UniTask.Yield(); CancellationTokenSource = default; State = InitializationState.None; BIT4Log.Log($"已停止{nameof(BITApp)}"); } public static void Run(string path, string WorkingDirectory = "") { using var open = new OpenAPP() { path = path, WorkingDirectory = WorkingDirectory }; open.Execute(); } public static void Open(string path) { using var open = new OpenPath() { path = path }; open.Execute(); } #if NET5_0_OR_GREATER public static void BuildService() { ServiceProvider = ServiceCollection.BuildServiceProvider(); OnServiceProviderBuilded?.Invoke(ServiceProvider); } #endif } }