Decompiled source of BetterServerRpcErrorLog v0.0.3

NoteBoxz.BetterServerRpcErrorLog.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: AssemblyCompany("NoteBoxz.BetterServerRpcErrorLog")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.0.3.0")]
[assembly: AssemblyInformationalVersion("0.0.3+7e368df0bc7f1de3dc94dd2f6bb0dd9af1d26bce")]
[assembly: AssemblyProduct("BetterServerRpcErrorLog")]
[assembly: AssemblyTitle("NoteBoxz.BetterServerRpcErrorLog")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.3.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 BetterServerRpcErrorLog
{
	[BepInPlugin("NoteBoxz.BetterServerRpcErrorLog", "BetterServerRpcErrorLog", "0.0.3")]
	public class BetterServerRpcErrorLog : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <PatchDynamicCoroutine>d__24 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private Task <patchingTask>5__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PatchDynamicCoroutine>d__24(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<patchingTask>5__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<patchingTask>5__1 = Task.Run(delegate
					{
						List<Assembly> list = AppDomain.CurrentDomain.GetAssemblies().ToList();
						int count = list.Count;
						int num = 0;
						foreach (Assembly item in list)
						{
							try
							{
								ScanAssemblyToPatch(item);
								num++;
								if (num % 5 == 0 || num == count)
								{
									Logger.LogMessage((object)($"Patching progress: {num}/{count} assemblies processed " + $"{ServerRpcCount} ServerRpc methods patched, {RpcHandlerCount} RPC handlers patched"));
								}
							}
							catch (Exception ex)
							{
								Logger.LogError((object)("Error scanning assembly " + item.FullName + ": " + ex.Message));
							}
						}
						Logger.LogInfo((object)($"Dynamic patching complete. Processed {count} assemblies. " + $"Patched {ServerRpcCount} ServerRpc methods and {RpcHandlerCount} RPC handlers."));
					});
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<patchingTask>5__1.IsCompleted)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				if (<patchingTask>5__1.Exception != null)
				{
					Logger.LogError((object)$"Error during async patching: {<patchingTask>5__1.Exception}");
				}
				Object.Destroy((Object)(object)((Component)SharedCoroutineStarter.Instance).gameObject);
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static Harmony Harmony;

		public static ManualLogSource Logger { get; private set; }

		public static ConfigEntry<bool> LogAssemblyScanning { get; private set; }

		public static ConfigEntry<bool> RemoveFirstLineOfStackTrace { get; private set; }

		public static int ServerRpcCount { get; private set; }

		public static int RpcHandlerCount { get; private set; }

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			Harmony = new Harmony("NoteBoxz.BetterServerRpcErrorLog");
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Active, waiting for game to start before dynamic patching...");
			LogAssemblyScanning = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogAssemblyScanning", false, "Enable/disable logging of assembly scanning progress");
			RemoveFirstLineOfStackTrace = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RemoveFirstLineOfStackTrace", true, "Enable/disable removing the first line of the stack trace in the error log. This first line is usually from the mod itself and not the actual error.");
			Patch();
		}

		public static void Patch()
		{
			Logger.LogDebug((object)"Patching...");
			Harmony.PatchAll(Assembly.GetExecutingAssembly());
			Logger.LogDebug((object)"Patching complete!");
		}

		public static void PatchDynamic()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			Logger.LogInfo((object)"Dynamic patching...");
			ServerRpcCount = 0;
			GameObject val = new GameObject("SharedCoroutineStarter");
			Object.DontDestroyOnLoad((Object)(object)val);
			SharedCoroutineStarter.Instance = val.AddComponent<SharedCoroutineStarter>();
			((MonoBehaviour)SharedCoroutineStarter.Instance).StartCoroutine(PatchDynamicCoroutine());
		}

		[IteratorStateMachine(typeof(<PatchDynamicCoroutine>d__24))]
		private static IEnumerator PatchDynamicCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PatchDynamicCoroutine>d__24(0);
		}

		public static void ScanAssemblyToPatch(Assembly assembly)
		{
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Expected O, but got Unknown
			//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c1: Expected O, but got Unknown
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Expected O, but got Unknown
			List<MethodInfo> list = new List<MethodInfo>();
			List<MethodInfo> list2 = new List<MethodInfo>();
			List<string> list3 = new List<string>();
			if (LogAssemblyScanning.Value)
			{
				Logger.LogMessage((object)("----Scanning assembly " + assembly.GetName().Name + " for patch methods----"));
			}
			try
			{
				Type[] array;
				try
				{
					array = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					int num = ex.Types.Count((Type t) => t == null);
					if (LogAssemblyScanning.Value)
					{
						Logger.LogWarning((object)("Some types in assembly " + assembly.GetName().Name + " couldn't be loaded: " + ex.Message));
						Logger.LogWarning((object)$"Failed to load {num} types from {ex.Types.Length} total types");
					}
					array = ex.Types.Where((Type t) => t != null).ToArray();
				}
				Type[] array2 = array;
				foreach (Type type in array2)
				{
					try
					{
						list.AddRange(from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
							where m.Name.EndsWith("ServerRpc")
							select m);
						IEnumerable<MethodInfo> enumerable = from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
							where m.Name.StartsWith("__rpc_handler_") && IsRpcHandlerSignatureMatch(m)
							select m;
						foreach (MethodInfo item in enumerable)
						{
							if (ContainsOwnershipCheckAndErrorLog(item))
							{
								list2.Add(item);
								if (LogAssemblyScanning.Value)
								{
									Logger.LogInfo((object)("Found RPC handler with ownership check: " + GetUniqueMethodSignature(item)));
								}
							}
						}
					}
					catch (Exception ex2)
					{
						Logger.LogError((object)("Error accessing methods for type " + type.Name + ": " + ex2.Message));
					}
				}
				foreach (MethodInfo item2 in list)
				{
					try
					{
						string uniqueMethodSignature = GetUniqueMethodSignature(item2);
						if (list3.Contains(uniqueMethodSignature))
						{
							if (LogAssemblyScanning.Value)
							{
								Logger.LogWarning((object)("Already patched " + uniqueMethodSignature + ", skipping"));
							}
							continue;
						}
						ServerRpcAttribute val = (ServerRpcAttribute)item2.GetCustomAttribute(typeof(ServerRpcAttribute));
						if (val == null)
						{
							if (LogAssemblyScanning.Value)
							{
								Logger.LogWarning((object)("No ServerRpcAttribute found for " + uniqueMethodSignature + " despite ending with 'ServerRpc', skipping"));
							}
							continue;
						}
						if (!val.RequireOwnership)
						{
							if (LogAssemblyScanning.Value)
							{
								Logger.LogInfo((object)("ServerRpcAttribute found for " + uniqueMethodSignature + " but RequireOwnership is false, skipping"));
							}
							continue;
						}
						try
						{
							Harmony.Patch((MethodBase)item2, new HarmonyMethod(typeof(BetterServerRpcErrorLog).GetMethod("ServerRpcPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							ServerRpcCount++;
							if (LogAssemblyScanning.Value)
							{
								Logger.LogInfo((object)("Successfully patched ServerRpc " + uniqueMethodSignature));
							}
						}
						catch (Exception ex3)
						{
							Logger.LogError((object)("Failed to patch " + uniqueMethodSignature + ": " + ex3.Message));
						}
						list3.Add(uniqueMethodSignature);
					}
					catch (Exception ex4)
					{
						Logger.LogError((object)("Error processing patch method " + item2.Name + ": " + ex4.Message));
					}
				}
				foreach (MethodInfo item3 in list2)
				{
					try
					{
						string uniqueMethodSignature2 = GetUniqueMethodSignature(item3);
						if (list3.Contains(uniqueMethodSignature2))
						{
							if (LogAssemblyScanning.Value)
							{
								Logger.LogWarning((object)("Already patched RPC handler " + uniqueMethodSignature2 + ", skipping"));
							}
							continue;
						}
						try
						{
							Harmony.Patch((MethodBase)item3, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BetterServerRpcErrorLog).GetMethod("RpcHandlerTranspiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null);
							RpcHandlerCount++;
							if (LogAssemblyScanning.Value)
							{
								Logger.LogInfo((object)("Successfully patched RPC handler " + uniqueMethodSignature2));
							}
						}
						catch (Exception ex5)
						{
							Logger.LogError((object)("Failed to patch RPC handler " + uniqueMethodSignature2 + ": " + ex5.Message));
						}
						list3.Add(uniqueMethodSignature2);
					}
					catch (Exception ex6)
					{
						Logger.LogError((object)("Error processing RPC handler " + item3.Name + ": " + ex6.Message));
					}
				}
			}
			catch (Exception ex7)
			{
				Logger.LogError((object)("Error getting types from assembly " + assembly.GetName().Name + ": " + ex7.Message));
			}
		}

		private static bool IsRpcHandlerSignatureMatch(MethodInfo method)
		{
			ParameterInfo[] parameters = method.GetParameters();
			return parameters.Length == 3 && parameters[0].ParameterType == typeof(NetworkBehaviour) && parameters[1].ParameterType.Name == "FastBufferReader" && parameters[2].ParameterType.Name == "__RpcParams";
		}

		private static bool ContainsOwnershipCheckAndErrorLog(MethodInfo method)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MethodBody methodBody = method.GetMethodBody();
				if (methodBody == null)
				{
					return false;
				}
				string location = method.Module.Assembly.Location;
				if (string.IsNullOrEmpty(location))
				{
					return false;
				}
				AssemblyDefinition val = AssemblyDefinition.ReadAssembly(location);
				try
				{
					MethodDefinition val2 = FindMethodDefinition(val, method);
					if (val2 == null)
					{
						return false;
					}
					Enumerator<Instruction> enumerator = val2.Body.Instructions.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							Instruction current = enumerator.Current;
							if (current.OpCode == OpCodes.Ldstr && current.Operand is string text && text == "Only the owner can invoke a ServerRpc that requires ownership!")
							{
								return true;
							}
						}
					}
					finally
					{
						((IDisposable)enumerator).Dispose();
					}
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
				return false;
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error analyzing method " + method.Name + ": " + ex.Message));
				return false;
			}
		}

		private static MethodDefinition? FindMethodDefinition(AssemblyDefinition assembly, MethodInfo method)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<ModuleDefinition> enumerator = assembly.Modules.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					ModuleDefinition current = enumerator.Current;
					TypeDefinition type = current.GetType(method.DeclaringType.FullName);
					if (type == null)
					{
						continue;
					}
					Enumerator<MethodDefinition> enumerator2 = type.Methods.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							MethodDefinition current2 = enumerator2.Current;
							if (!(((MemberReference)current2).Name == method.Name) || ((MethodReference)current2).Parameters.Count != method.GetParameters().Length)
							{
								continue;
							}
							bool flag = true;
							for (int i = 0; i < ((MethodReference)current2).Parameters.Count; i++)
							{
								if (((MemberReference)((ParameterReference)((MethodReference)current2).Parameters[i]).ParameterType).Name != method.GetParameters()[i].ParameterType.Name)
								{
									flag = false;
									break;
								}
							}
							if (flag)
							{
								return current2;
							}
						}
					}
					finally
					{
						((IDisposable)enumerator2).Dispose();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			return null;
		}

		private static IEnumerable<CodeInstruction> RpcHandlerTranspiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			bool flag = false;
			for (int i = 0; i < list.Count - 2; i++)
			{
				if (list[i].opcode == OpCodes.Ldstr && list[i].operand is string text && text == "Only the owner can invoke a ServerRpc that requires ownership!" && list[i + 1].opcode == OpCodes.Call && list[i + 1].operand is MethodInfo methodInfo && methodInfo.Name == "LogError" && methodInfo.DeclaringType.Name == "Debug")
				{
					flag = true;
					list.Insert(i, new CodeInstruction(OpCodes.Ldarg_0, (object)null));
					list.Insert(i + 1, new CodeInstruction(OpCodes.Ldarg_2, (object)null));
					list.Insert(i + 2, new CodeInstruction(OpCodes.Call, (object)typeof(BetterServerRpcErrorLog).GetMethod("LogDetailedRpcHandlerError", BindingFlags.Static | BindingFlags.NonPublic)));
					list[i + 3] = new CodeInstruction(OpCodes.Nop, (object)null);
					list[i + 4] = new CodeInstruction(OpCodes.Nop, (object)null);
					break;
				}
			}
			if (!flag)
			{
				Logger.LogWarning((object)("RPC handler transpiler couldn't find the error log in " + __originalMethod.Name));
			}
			return list;
		}

		private static void LogDetailedRpcHandlerError(NetworkBehaviour target, __RpcParams rpcParams)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NetworkManager networkManager = target.NetworkManager;
				if (networkManager == null)
				{
					return;
				}
				string text = Environment.StackTrace;
				if (RemoveFirstLineOfStackTrace.Value)
				{
					string[] array = text.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
					List<int> indicesToRemove = new List<int>();
					for (int i = 0; i < array.Length; i++)
					{
						if (array[i].Contains("BetterServerRpcErrorLog.LogDetailedRpcHandlerError") || array[i].Contains("RpcHandlerTranspiler"))
						{
							indicesToRemove.Add(i);
						}
					}
					if (indicesToRemove.Count > 0)
					{
						text = string.Join(Environment.NewLine, array.Where((string line, int index) => !indicesToRemove.Contains(index)));
					}
				}
				Logger.LogError((object)("[RPC Handler] Only the owner can invoke a ServerRpc that requires ownership!" + $"\nCalled by client {rpcParams.Server.Receive.SenderClientId}, but owner is {target.OwnerClientId}" + "\nObject: " + ((Object)target).name + " (" + ((object)target).GetType().Name + ")\n" + text));
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in LogDetailedRpcHandlerError: " + ex.Message));
			}
		}

		private static void ServerRpcPrefix(MethodBase __originalMethod, NetworkBehaviour __instance)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			try
			{
				NetworkManager networkManager = __instance.NetworkManager;
				if (networkManager == null || !networkManager.IsListening || (int)__instance.__rpc_exec_stage == 1 || (!networkManager.IsClient && !networkManager.IsHost) || __instance.OwnerClientId == networkManager.LocalClientId)
				{
					return;
				}
				string empty = string.Empty;
				string text = Environment.StackTrace;
				if (RemoveFirstLineOfStackTrace.Value)
				{
					string[] array = text.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
					int indexToRemove = -1;
					for (int i = 0; i < array.Length; i++)
					{
						if (array[i].Contains("BetterServerRpcErrorLog.ServerRpcPrefix") || array[i].Contains("ServerRpcPrefix"))
						{
							indexToRemove = i;
							break;
						}
					}
					if (indexToRemove >= 0 && array.Length > indexToRemove + 1)
					{
						text = string.Join(Environment.NewLine, array.Where((string line, int index) => index != indexToRemove));
					}
				}
				Logger.LogError((object)($"stage({((object)(__RpcExecStage)(ref __instance.__rpc_exec_stage)).ToString()}) Non-owner called ServerRpc that requires ownership: {GetUniqueMethodSignature(__originalMethod)}" + $"\nCalled by client {networkManager.LocalClientId}, but owner is {__instance.OwnerClientId}\n" + text));
			}
			catch (Exception ex)
			{
				Logger.LogError((object)$"Error in ServerRpcPrefix for {GetUniqueMethodSignature(__originalMethod)}: {ex.Message}");
			}
		}

		private static object GetUniqueMethodSignature(MethodBase method)
		{
			string arg = string.Join(", ", from p in method.GetParameters()
				select p.ParameterType.Name);
			string text = $"{method.DeclaringType}.{method.Name}({arg})";
			if (method.IsGenericMethod)
			{
				string text2 = string.Join(", ", from t in method.GetGenericArguments()
					select t.Name);
				text = text + "<" + text2 + ">";
			}
			return text;
		}

		private static string GetUniqueMethodSignature(MethodInfo method)
		{
			string arg = string.Join(", ", from p in method.GetParameters()
				select p.ParameterType.Name);
			string text = $"{method.DeclaringType}.{method.Name}({arg})";
			if (method.IsGenericMethod)
			{
				string text2 = string.Join(", ", from t in method.GetGenericArguments()
					select t.Name);
				text = text + "<" + text2 + ">";
			}
			return text;
		}
	}
	public class SharedCoroutineStarter : MonoBehaviour
	{
		public static SharedCoroutineStarter Instance;
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "NoteBoxz.BetterServerRpcErrorLog";

		public const string PLUGIN_NAME = "BetterServerRpcErrorLog";

		public const string PLUGIN_VERSION = "0.0.3";
	}
}
namespace BetterServerRpcErrorLog.Patches
{
	[HarmonyPatch(typeof(InitializeGame))]
	internal class InitPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void Postfix()
		{
			BetterServerRpcErrorLog.PatchDynamic();
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}