Decompiled source of GameLogBridge v1.0.0

BepInEx/plugins/GameLogBridge/GameLogBridge.dll

Decompiled a week ago
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();
				}
			}
		}
	}
}