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 GUI v3.0.3
BepInEx/patchers/BepInEx.GUI/BepInEx.GUI.Loader.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("BepInEx.GUI.Loader")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+bba91d0f08bc552e316d40748c77d3e95f9c4405")] [assembly: AssemblyProduct("BepInEx.GUI.Loader")] [assembly: AssemblyTitle("BepInEx.GUI.Loader")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx.GUI.Loader { public class CloseProcessOnChainloaderDone : ILogListener, IDisposable { private bool _disposed; private Process _process; public CloseProcessOnChainloaderDone(Process process) { _process = process; } public void Dispose() { _disposed = true; } public void LogEvent(object sender, LogEventArgs eventArgs) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!_disposed && eventArgs.Data.ToString() == "Chainloader startup complete") { LogLevel level = eventArgs.Level; if (((object)(LogLevel)(ref level)).Equals((object)(LogLevel)8) && Config.CloseWindowWhenGameLoadedConfig.Value) { Log.Message("Closing BepInEx.GUI"); KillBepInExGUIProcess(); } } } private void KillBepInExGUIProcess() { try { _process.Kill(); } catch (Exception ex) { Log.Error($"Error while trying to kill BepInEx GUI Process: {ex}"); Log.Error(ex); } finally { SendLogToClientSocket.Instance.Dispose(); Dispose(); } } } internal static class Config { internal const string FileName = "BepInEx.GUI.cfg"; internal const string EnableBepInExGUIConfigKey = "Enable BepInEx GUI"; internal const string EnableBepInExGUIConfigDescription = "Enable the custom BepInEx GUI"; internal const string CloseWindowWhenGameLoadedConfigKey = "Close Window When Game Loaded"; internal const string CloseWindowWhenGameLoadedConfigDescription = "Close the graphic user interface window when the game is loaded"; internal const string CloseWindowWhenGameClosesConfigKey = "Close Window When Game Closes"; internal const string CloseWindowWhenGameClosesConfigDescription = "Close the graphic user interface window when the game closes"; internal static string ConfigFilePath { get; private set; } private static ConfigFile File { get; set; } internal static ConfigEntry<bool> EnableBepInExGUIConfig { get; private set; } internal static ConfigEntry<bool> CloseWindowWhenGameLoadedConfig { get; private set; } internal static ConfigEntry<bool> CloseWindowWhenGameClosesConfig { get; private set; } internal static void Init(string folderFullPath) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown ConfigFilePath = Path.Combine(folderFullPath, "BepInEx.GUI.cfg"); File = new ConfigFile(ConfigFilePath, true); EnableBepInExGUIConfig = File.Bind<bool>("Settings", "Enable BepInEx GUI", true, "Enable the custom BepInEx GUI"); CloseWindowWhenGameLoadedConfig = File.Bind<bool>("Settings", "Close Window When Game Loaded", false, "Close the graphic user interface window when the game is loaded"); CloseWindowWhenGameClosesConfig = File.Bind<bool>("Settings", "Close Window When Game Closes", true, "Close the graphic user interface window when the game closes"); } } internal static class EntryPoint { public static IEnumerable<string> TargetDLLs { get; } = Array.Empty<string>(); public static void Patch(AssemblyDefinition _) { } public static void Initialize() { Log.Init(); try { InitializeInternal(); } catch (Exception ex) { Log.Error($"Failed to initialize : ({ex.GetType()}) {ex.Message}{Environment.NewLine}{ex}"); } } private static void InitializeInternal() { Config.Init(Paths.ConfigPath); if (((ConfigEntry<bool>)typeof(BepInPlugin).Assembly.GetType("BepInEx.ConsoleManager", throwOnError: true).GetField("ConfigConsoleEnabled", BindingFlags.Static | BindingFlags.Public).GetValue(null)).Value) { Log.Info("BepInEx regular console is enabled, aborting launch."); } else if (Config.EnableBepInExGUIConfig.Value) { FindAndLaunchGUI(); } else { Log.Info("Custom BepInEx.GUI is disabled in the config, aborting launch."); } } private static string FindGUIExecutable() { string[] files = Directory.GetFiles(Paths.PatcherPluginPath, "*", SearchOption.AllDirectories); foreach (string text in files) { if (Path.GetFileName(text) == "bepinex_gui.exe" && FileVersionInfo.GetVersionInfo(text).FileMajorPart == 3) { Log.Info("Found bepinex_gui v3 executable in " + text); return text; } } return null; } private static void FindAndLaunchGUI() { Log.Info("Finding and launching GUI"); string text = FindGUIExecutable(); if (text != null) { int num = FindFreePort(); Process process = LaunchGUI(text, num); if (process != null) { Logger.Listeners.Add((ILogListener)(object)new SendLogToClientSocket(num)); Logger.Listeners.Add((ILogListener)(object)new CloseProcessOnChainloaderDone(process)); } else { Log.Info("LaunchGUI failed"); } } else { Log.Info("bepinex_gui executable not found."); } } private static int FindFreePort() { int num = 0; Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 0); socket.Bind(localEP); localEP = (IPEndPoint)socket.LocalEndPoint; return localEP.Port; } finally { socket.Close(); } } private static Process LaunchGUI(string executablePath, int socketPort) { ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.FileName = executablePath; processStartInfo.WorkingDirectory = Path.GetDirectoryName(executablePath); processStartInfo.Arguments = $"\"{typeof(Paths).Assembly.GetName().Version}\" " + "\"" + Paths.ProcessName + "\" \"" + Paths.GameRootPath + "\" \"" + GetLogOutputFilePath() + "\" \"" + Config.ConfigFilePath + "\" " + $"\"{Process.GetCurrentProcess().Id}\" " + $"\"{socketPort}\""; return Process.Start(processStartInfo); } private static string GetLogOutputFilePath() { foreach (ILogListener listener in Logger.Listeners) { DiskLogListener val = (DiskLogListener)(object)((listener is DiskLogListener) ? listener : null); if (val != null) { return val.FileFullPath; } } return ""; } } internal static class Log { private static ManualLogSource _logSource; internal static void Init() { _logSource = Logger.CreateLogSource("BepInEx.GUI.Loader"); } internal static void Debug(object data) { _logSource.LogDebug(data); } internal static void Error(object data) { _logSource.LogError(data); } internal static void Fatal(object data) { _logSource.LogFatal(data); } internal static void Info(object data) { _logSource.LogInfo(data); } internal static void Message(object data) { _logSource.LogMessage(data); } internal static void Warning(object data) { _logSource.LogWarning(data); } } internal struct LogPacket { internal byte[] Bytes; internal unsafe LogPacket(LogEventArgs log) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected I4, but got Unknown byte[] bytes = Encoding.UTF8.GetBytes(((object)log).ToString()); int num = bytes.Length; Bytes = new byte[8 + num]; fixed (byte* ptr = Bytes) { *(int*)ptr = num; *(int*)(ptr + 4) = (int)log.Level; Marshal.Copy(bytes, 0, (IntPtr)(ptr + 8), num); } } } internal class SendLogToClientSocket : ILogListener, IDisposable { private int _freePort; private readonly Thread _thread; private readonly object _queueLock = new object(); private readonly Queue<LogEventArgs> _logQueue = new Queue<LogEventArgs>(); private bool _isDisposed; private bool _gotFirstLog; internal static SendLogToClientSocket Instance { get; private set; } internal SendLogToClientSocket(int freePort) { Instance = this; _freePort = freePort; _thread = new Thread((ThreadStart)delegate { TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), _freePort); tcpListener.Start(); while (true) { Log.Info("[SendLogToClient] Accepting Socket."); Socket clientSocket = tcpListener.AcceptSocket(); if (_isDisposed) { break; } SendPacketsToClientUntilConnectionIsClosed(clientSocket); } }); _thread.Start(); } private void SendPacketsToClientUntilConnectionIsClosed(Socket clientSocket) { while (!_isDisposed) { while (_logQueue.Count > 0) { LogEventArgs log; lock (_queueLock) { log = _logQueue.Peek(); } LogPacket logPacket = new LogPacket(log); try { clientSocket.Send(logPacket.Bytes); } catch (Exception arg) { Log.Error($"Error while trying to send log to socket: {arg}{Environment.NewLine}Disconnecting socket."); return; } lock (_queueLock) { _logQueue.Dequeue(); } } Thread.Sleep(17); } } public void Dispose() { _isDisposed = true; } internal void StoreLog(LogEventArgs eventArgs) { lock (_queueLock) { _logQueue.Enqueue(eventArgs); } } public void LogEvent(object sender, LogEventArgs eventArgs) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 if (_isDisposed || eventArgs.Data == null) { return; } if (!_gotFirstLog) { if ((int)eventArgs.Level == 8 && eventArgs.Source.SourceName == "BepInEx" && eventArgs.Data.ToString().StartsWith("BepInEx")) { _gotFirstLog = true; } } else { StoreLog(eventArgs); } } } }