Some mods may be broken due to the recent Alloyed Collective update.
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); } } } }