Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BepInEx SplashScreen v2.2.1
patchers/BepInEx.SplashScreen/BepInEx.SplashScreen.Patcher.BepInEx5.dll
Decompiled 2 years agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Timers; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Mono.Cecil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("BepInEx.SplashScreen.Patcher")] [assembly: AssemblyDescription("Splash screen that shows loading progress when a game patched with BepInEx is loading.")] [assembly: AssemblyCompany("https://github.com/BepInEx/BepInEx.SplashScreen")] [assembly: AssemblyProduct("BepInEx.SplashScreen")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: ComVisible(false)] [assembly: Guid("449b9f51-bbe5-4d4a-8936-e0a3081d79cb")] [assembly: AssemblyVersion("2.2.0.0")] namespace BepInEx.SplashScreen; public static class BepInExSplashScreenPatcher { public const string Version = "1.0"; private static int _initialized; public static IEnumerable<string> TargetDLLs { get { Init(); return Enumerable.Empty<string>(); } } static BepInExSplashScreenPatcher() { Init(); } public static void Patch(AssemblyDefinition _) { Init(); } public static void Init() { if (Interlocked.Exchange(ref _initialized, 1) != 1) { SplashScreenController.SpawnSplash(); } } } internal class Metadata { public const string Version = "2.2"; } internal sealed class LoadingLogListener : ILogListener, IDisposable { private bool _disposed; private LoadingLogListener() { } public static LoadingLogListener StartListening() { LoadingLogListener loadingLogListener = new LoadingLogListener(); Logger.Listeners.Add((ILogListener)(object)loadingLogListener); return loadingLogListener; } public void Dispose() { _disposed = true; } public void LogEvent(object sender, LogEventArgs eventArgs) { if (_disposed || !(eventArgs.Source.SourceName == "BepInEx") || eventArgs.Data == null) { return; } try { string text = (eventArgs.Data as string) ?? eventArgs.Data.ToString(); if (text == "Chainloader startup complete") { Dispose(); Traverse threadingHelper = Traverse.CreateWithType("BepInEx.ThreadingHelper").Property("Instance", (object[])null); Traverse val = threadingHelper.Method("StartSyncInvoke", new Type[1] { typeof(Action) }, (object[])null); if (val.MethodExists()) { val.GetValue(new object[1] { (Action)delegate { try { threadingHelper.Method("StartCoroutine", new Type[1] { typeof(IEnumerator) }, (object[])null).GetValue(new object[1] { DelayedCo() }); } catch (Exception ex2) { SplashScreenController.Logger.LogError((object)("Unexpected crash when trying to StartCoroutine: " + ex2)); SplashScreenController.KillSplash(); } } }); } else { Process currentProcess = Process.GetCurrentProcess(); System.Timers.Timer timer = new System.Timers.Timer(500.0); timer.Elapsed += delegate { try { timer.Stop(); currentProcess.Refresh(); if (currentProcess.Responding) { timer.Dispose(); SplashScreenController.KillSplash(); } else { SplashScreenController.Logger.LogDebug((object)"Process not responding, waiting..."); timer.Start(); } } catch (Exception ex) { SplashScreenController.Logger.LogError((object)("Unexpected crash in timer.Elapsed: " + ex)); SplashScreenController.KillSplash(); } }; timer.AutoReset = false; timer.Start(); } } else if (text.StartsWith("Failed to run [BepInEx.Chainloader]", StringComparison.Ordinal) || string.Equals(text, "Could not run preloader!", StringComparison.Ordinal)) { Dispose(); SplashScreenController.KillSplash(); } SplashScreenController.SendMessage(text); } catch (Exception arg) { SplashScreenController.Logger.LogError((object)string.Format("Crash in {0}, aborting. Exception: {1}", "LogEvent", arg)); SplashScreenController.KillSplash(); } } private static IEnumerator DelayedCo() { for (int i = 0; i < 1; i++) { yield return null; } SplashScreenController.KillSplash(); } } public static class SplashScreenController { internal static readonly ManualLogSource Logger = Logger.CreateLogSource("Splash"); private static readonly Queue _StatusQueue = Queue.Synchronized(new Queue(10, 2f)); private static LoadingLogListener _logListener; private static Process _guiProcess; public static void SpawnSplash() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown try { ConfigFile val = (ConfigFile)AccessTools.Property(typeof(ConfigFile), "CoreConfig").GetValue(null, null); bool value = val.Bind<bool>("SplashScreen", "Enabled", true, "Display a splash screen with information about game load progress on game start-up.").Value; bool value2 = val.Bind<bool>("SplashScreen", "OnlyNoConsole", true, "Only display the splash screen if the logging console is turned off.").Value; if (!value) { Logger.LogDebug((object)"Not showing splash because the Enabled setting is off"); return; } ConfigEntry<bool> val2 = default(ConfigEntry<bool>); if (value2 && val.TryGetEntry<bool>("Logging.Console", "Enabled", ref val2) && val2.Value) { Logger.LogDebug((object)"Not showing splash because the console is enabled"); return; } string text = Path.Combine(Path.GetDirectoryName(typeof(SplashScreenController).Assembly.Location) ?? Paths.PatcherPluginPath, "BepInEx.SplashScreen.GUI.exe"); if (!File.Exists(text)) { throw new FileNotFoundException("Executable not found or inaccessible at " + text); } Logger.Log((LogLevel)32, (object)("Starting GUI process: " + text)); ProcessStartInfo startInfo = new ProcessStartInfo(text, Process.GetCurrentProcess().Id.ToString()) { UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8 }; _guiProcess = Process.Start(startInfo); Thread thread = new Thread(CommunicationThread); thread.IsBackground = true; thread.Start(_guiProcess); _logListener = LoadingLogListener.StartListening(); } catch (Exception ex) { Logger.LogError((object)("Failed to start GUI: " + ex)); KillSplash(); } } internal static void SendMessage(string message) { _StatusQueue.Enqueue(message); } private static void CommunicationThread(object processArg) { try { Process process = (Process)processArg; process.Exited += delegate { KillSplash(); }; process.OutputDataReceived += delegate(object sender, DataReceivedEventArgs args) { if (args.Data != null) { Logger.Log((LogLevel)32, (object)("[GUI] " + args.Data.Replace('\t', '\n').TrimEnd(new char[1] { '\n' }))); } }; process.BeginOutputReadLine(); process.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs args) { if (args.Data != null) { Logger.Log((LogLevel)2, (object)("[GUI] " + args.Data.Replace('\t', '\n').TrimEnd(new char[1] { '\n' }))); } }; process.BeginErrorReadLine(); process.StandardInput.AutoFlush = false; Logger.LogDebug((object)"Connected to the GUI process"); bool flag = false; while (!process.HasExited) { while (_StatusQueue.Count > 0 && process.StandardInput.BaseStream.CanWrite) { process.StandardInput.WriteLine(_StatusQueue.Dequeue()); flag = true; } if (flag) { flag = false; process.StandardInput.Flush(); } Thread.Sleep(150); } } catch (ThreadAbortException) { } catch (Exception arg) { Logger.LogError((object)string.Format("Crash in {0}, aborting. Exception: {1}", "CommunicationThread", arg)); } finally { KillSplash(); } } internal static void KillSplash() { try { _logListener?.Dispose(); _StatusQueue.Clear(); _StatusQueue.TrimToSize(); try { if (_guiProcess != null && !_guiProcess.HasExited) { Logger.LogDebug((object)"Closing GUI process"); _guiProcess.Kill(); } } catch (Exception) { } Logger.Dispose(); } catch (Exception value) { Console.WriteLine(value); } } }