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<string>("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<string>("Ice Box Studio");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("(");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("https://steamcommunity.com/id/ibox666/");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
}
log2.LogInfo(val);
GameLogs.Start(((BasePlugin)this).Config.Bind<bool>("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<string>("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<string>("Game Log Bridge");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" initialization error: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(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<Assembly> Pending = new Queue<Assembly>();
private static readonly HashSet<Assembly> Seen = new HashSet<Assembly>();
private static readonly ConditionalWeakTable<Exception, object> Errors = new ConditionalWeakTable<Exception, object>();
private static Harmony harmony;
private static ManualLogSource log;
private static ConfigEntry<bool> enabled;
private static bool started;
private static bool processing;
[ThreadStatic]
private static bool writing;
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void Start(ConfigEntry<bool> 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<int?>), typeof(string), typeof(string), typeof(IEnumerable<string>));
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<bool> 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();
}
}
}
}
}