using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.NET.Common; using GameLogBridge.Features; using HarmonyLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Game Log Bridge")] [assembly: AssemblyDescription("Game log forwarding for Romestead by Ice Box Studio")] [assembly: AssemblyCompany("Ice Box Studio")] [assembly: AssemblyProduct("Game Log Bridge")] [assembly: AssemblyCopyright("Copyright (C) 2026 Ice Box Studio")] [assembly: ComVisible(false)] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace GameLogBridge { [BepInPlugin("IceBoxStudio.Romestead.GameLogBridge", "Game Log Bridge", "1.0.0")] public sealed class GameLogBridge : BasePlugin { public static GameLogBridge Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } public override void Load() { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown Instance = this; Logger = ((BasePlugin)this).Log; bool flag = default(bool); try { ((BasePlugin)this).Log.LogInfo((object)"============================================="); ManualLogSource log = ((BasePlugin)this).Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(16, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("Game Log Bridge"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" initializing..."); } log.LogInfo(val); ManualLogSource log2 = ((BasePlugin)this).Log; val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Author: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("Ice Box Studio"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("https://steamcommunity.com/id/ibox666/"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")"); } log2.LogInfo(val); GameLogs.Start(((BasePlugin)this).Config.Bind("General", "Enabled", true, "Forward supported game logs, exception details and error dialog text to BepInEx."), ((BasePlugin)this).HarmonyInstance); ManualLogSource log3 = ((BasePlugin)this).Log; val = new BepInExInfoLogInterpolatedStringHandler(13, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("Game Log Bridge"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" initialized."); } log3.LogInfo(val); ((BasePlugin)this).Log.LogInfo((object)"============================================="); } catch (Exception ex) { ManualLogSource log4 = ((BasePlugin)this).Log; BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(23, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted("Game Log Bridge"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" initialization error: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(ex); } log4.LogError(val2); } } } public static class PluginInfo { public const string PLUGIN_GUID = "IceBoxStudio.Romestead.GameLogBridge"; public const string PLUGIN_NAME = "Game Log Bridge"; public const string PLUGIN_VERSION = "1.0.0"; public const string PLUGIN_AUTHOR = "Ice Box Studio"; public const string PLUGIN_AUTHOR_URL = "https://steamcommunity.com/id/ibox666/"; public const string THUNDERSTORE_TEAM = "Ice_Box_Studio_Romestead"; public const string THUNDERSTORE_MOD_NAME = "GameLogBridge"; public const string UPDATE_MANIFEST_URL = "https://cdn.jsdelivr.net/gh/ibox233/MyMod_Version@main/GameLogBridge.json"; } } namespace GameLogBridge.Features { internal static class GameLogs { private static readonly object Sync = new object(); private static readonly Queue Pending = new Queue(); private static readonly HashSet Seen = new HashSet(); private static readonly ConditionalWeakTable Errors = new ConditionalWeakTable(); private static Harmony harmony; private static ManualLogSource log; private static ConfigEntry enabled; private static bool started; private static bool processing; [ThreadStatic] private static bool writing; [MethodImpl(MethodImplOptions.NoInlining)] internal static void Start(ConfigEntry option, Harmony patcher) { lock (Sync) { if (started) { return; } enabled = option; harmony = patcher; log = Logger.CreateLogSource("Game"); started = true; AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Add(assemblies[i]); } } private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) { Add(args.LoadedAssembly); } private static void Add(Assembly assembly) { try { string name = assembly.GetName().Name; if (name != "Romestead" && name != "CandideCreator.Shared" && name != "RiptideNetworking" && name != "MonoGame.Framework" && name != "System.Windows.Forms") { return; } lock (Sync) { if (!Seen.Add(assembly)) { return; } Pending.Enqueue(assembly); if (processing) { return; } processing = true; } while (true) { Assembly assembly2; lock (Sync) { if (Pending.Count == 0) { processing = false; break; } assembly2 = Pending.Dequeue(); } try { Setup(assembly2); } catch (Exception) { } } } catch (Exception) { } } private static void Setup(Assembly assembly) { switch (assembly.GetName().Name) { case "Romestead": { Type type4 = assembly.GetType("Candide.Program", throwOnError: false); Patch(type4, "Game_UnhandledExceptionHandler", typeof(bool), typeof(Exception)); Patch(type4, "App_DispatcherUnhandledException", typeof(void), typeof(object), typeof(UnhandledExceptionEventArgs)); break; } case "CandideCreator.Shared": Patch(assembly.GetType("CandideCreator.Shared.Helpers.DebugHelper", throwOnError: false), "PrintAndConsole", typeof(void), typeof(string)); break; case "RiptideNetworking": { Type type5 = assembly.GetType("Riptide.Utils.RiptideLogger", throwOnError: false); Type type6 = assembly.GetType("Riptide.Utils.LogType", throwOnError: false); if ((object)type6 != null && type6.IsEnum) { Patch(type5, "Log", typeof(void), type6, typeof(string)); Patch(type5, "Log", typeof(void), type6, typeof(string), typeof(string)); } break; } case "MonoGame.Framework": Patch(assembly.GetType("Microsoft.Xna.Framework.Input.MessageBox", throwOnError: false), "Show", typeof(Task), typeof(string), typeof(string), typeof(IEnumerable)); break; case "System.Windows.Forms": { Type type = assembly.GetType("System.Windows.Forms.MessageBoxButtons", throwOnError: false); Type type2 = assembly.GetType("System.Windows.Forms.MessageBoxIcon", throwOnError: false); Type type3 = assembly.GetType("System.Windows.Forms.DialogResult", throwOnError: false); if ((object)type != null && type.IsEnum && (object)type2 != null && type2.IsEnum && (object)type3 != null && type3.IsEnum) { Patch(assembly.GetType("System.Windows.Forms.MessageBox", throwOnError: false), "Show", type3, typeof(string), typeof(string), type, type2); } break; } } } private static void Patch(Type type, string name, Type result, params Type[] args) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown try { MethodInfo methodInfo = type?.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, args, null); if (methodInfo == null || methodInfo.ReturnType != result || methodInfo.ContainsGenericParameters || methodInfo.GetMethodBody() == null) { return; } ParameterInfo[] parameters = methodInfo.GetParameters(); for (int i = 0; i < args.Length; i++) { if (parameters[i].ParameterType != args[i]) { return; } } MethodInfo method = typeof(GameLogs).GetMethod("Observe", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception) { } } private static void Observe(MethodBase __originalMethod, object[] __args) { //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) if (writing) { return; } writing = true; try { ConfigEntry obj = enabled; if (obj == null || !obj.Value) { return; } switch (__originalMethod.DeclaringType.FullName) { case "Candide.Program": { Exception ex = __args[0] as Exception; if (__originalMethod.Name == "App_DispatcherUnhandledException") { ex = (__args[1] as UnhandledExceptionEventArgs)?.ExceptionObject as Exception; } if (ex == null) { break; } lock (Errors) { if (Errors.TryGetValue(ex, out var _)) { break; } Errors.Add(ex, new object()); } Write((LogLevel)2, ex.ToString()); break; } case "CandideCreator.Shared.Helpers.DebugHelper": Write((LogLevel)16, (string)__args[0]); break; case "Riptide.Utils.RiptideLogger": { ? level = __args[0].ToString() switch { "Debug" => 32, "Warning" => 4, "Error" => 2, _ => 16, }; string message = ((__args.Length == 3) ? $"[{__args[1]}] {__args[2]}" : ((string)__args[1])); Write((LogLevel)level, message); break; } case "Microsoft.Xna.Framework.Input.MessageBox": Write((LogLevel)4, $"{__args[0]}: {__args[1]}"); break; case "System.Windows.Forms.MessageBox": { bool flag; switch (__args[3].ToString()) { case "Hand": case "Error": case "Stop": flag = true; break; default: flag = false; break; } Write((LogLevel)(flag ? 2 : 4), $"{__args[1]}: {__args[0]}"); break; } } } catch (Exception) { } finally { writing = false; } } private static void Write(LogLevel level, string message) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 log.Log(level, (object)message); if ((int)level != 2) { return; } foreach (ILogListener listener in Logger.Listeners) { DiskLogListener val = (DiskLogListener)(object)((listener is DiskLogListener) ? listener : null); if (val != null) { val.LogWriter?.Flush(); } } } } }