Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Runtime Netcode Patcher v0.2.5
NicholaScott.BepInEx.RuntimeNetcodeRPCValidator.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Unity.Collections; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: AssemblyCompany("NicholaScott.BepInEx.RuntimeNetcodeRPCValidator")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.5.0")] [assembly: AssemblyInformationalVersion("0.2.5+6e2f89b3631ae55d2f51a00ccfd3f20fec9d2372")] [assembly: AssemblyProduct("RuntimeNetcodeRPCValidator")] [assembly: AssemblyTitle("NicholaScott.BepInEx.RuntimeNetcodeRPCValidator")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace RuntimeNetcodeRPCValidator { public class AlreadyRegisteredException : Exception { public AlreadyRegisteredException(string PluginGUID) : base("Can't register plugin " + PluginGUID + " until the other instance of NetcodeValidator is Disposed of!") { } } public class InvalidPluginGuidException : Exception { public InvalidPluginGuidException(string pluginGUID) : base("Can't patch plugin " + pluginGUID + " because it doesn't exist!") { } } public class NotNetworkBehaviourException : Exception { public NotNetworkBehaviourException(Type type) : base("Netcode Runtime RPC Validator tried to NetcodeValidator.Patch type " + type.Name + " that doesn't inherit from NetworkBehaviour!") { } } public class MustCallFromDeclaredTypeException : Exception { public MustCallFromDeclaredTypeException() : base("Netcode Runtime RPC Validator tried to run NetcodeValidator.PatchAll from a delegate! You must call PatchAll from a declared type.") { } } public static class FastBufferExtensions { private const BindingFlags BindingAll = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static void WriteSystemSerializable(this FastBufferWriter fastBufferWriter, object serializable) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) BinaryFormatter binaryFormatter = new BinaryFormatter(); using MemoryStream memoryStream = new MemoryStream(); binaryFormatter.Serialize(memoryStream, serializable); byte[] array = memoryStream.ToArray(); int num = array.Length; ((FastBufferWriter)(ref fastBufferWriter)).WriteValueSafe<int>(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref fastBufferWriter)).WriteBytes(array, -1, 0); } private static void ReadSystemSerializable(this FastBufferReader fastBufferReader, out object serializable) { //IL_0006: 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) int num = default(int); ((FastBufferReader)(ref fastBufferReader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); byte[] buffer = new byte[num]; ((FastBufferReader)(ref fastBufferReader)).ReadBytes(ref buffer, num, 0); using MemoryStream memoryStream = new MemoryStream(buffer); memoryStream.Seek(0L, SeekOrigin.Begin); BinaryFormatter binaryFormatter = new BinaryFormatter(); serializable = binaryFormatter.Deserialize(memoryStream); } private static void WriteNetcodeSerializable(this FastBufferWriter fastBufferWriter, object networkSerializable) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, -1); try { BufferSerializer<BufferSerializerWriter> val2 = default(BufferSerializer<BufferSerializerWriter>); val2..ctor(new BufferSerializerWriter(val)); object obj = ((networkSerializable is INetworkSerializable) ? networkSerializable : null); if (obj != null) { ((INetworkSerializable)obj).NetworkSerialize<BufferSerializerWriter>(val2); } byte[] array = ((FastBufferWriter)(ref val)).ToArray(); int num = array.Length; ((FastBufferWriter)(ref fastBufferWriter)).WriteValueSafe<int>(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref fastBufferWriter)).WriteBytes(array, -1, 0); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private static void ReadNetcodeSerializable(this FastBufferReader fastBufferReader, Type type, out object serializable) { //IL_0006: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) int num = default(int); ((FastBufferReader)(ref fastBufferReader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); byte[] array = new byte[num]; ((FastBufferReader)(ref fastBufferReader)).ReadBytes(ref array, num, 0); FastBufferReader val = default(FastBufferReader); ((FastBufferReader)(ref val))..ctor(array, (Allocator)2, -1, 0); try { BufferSerializer<BufferSerializerReader> val2 = default(BufferSerializer<BufferSerializerReader>); val2..ctor(new BufferSerializerReader(val)); serializable = Activator.CreateInstance(type); object obj = serializable; object obj2 = ((obj is INetworkSerializable) ? obj : null); if (obj2 != null) { ((INetworkSerializable)obj2).NetworkSerialize<BufferSerializerReader>(val2); } } finally { ((IDisposable)(FastBufferReader)(ref val)).Dispose(); } } public static void WriteMethodInfoAndParameters(this FastBufferWriter fastBufferWriter, MethodBase methodInfo, object[] args) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) ((FastBufferWriter)(ref fastBufferWriter)).WriteValueSafe(methodInfo.Name, false); ParameterInfo[] parameters = methodInfo.GetParameters(); int num = parameters.Length; ((FastBufferWriter)(ref fastBufferWriter)).WriteValueSafe<int>(ref num, default(ForPrimitives)); for (int i = 0; i < parameters.Length; i++) { ParameterInfo parameterInfo = parameters[i]; object obj = args[i]; bool flag = obj == null || parameterInfo.ParameterType == typeof(ServerRpcParams) || parameterInfo.ParameterType == typeof(ClientRpcParams); ((FastBufferWriter)(ref fastBufferWriter)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { continue; } if (parameterInfo.ParameterType.GetInterfaces().Contains(typeof(INetworkSerializable))) { fastBufferWriter.WriteNetcodeSerializable(obj); continue; } if (parameterInfo.ParameterType.IsSerializable) { fastBufferWriter.WriteSystemSerializable(obj); continue; } throw new SerializationException(TextHandler.ObjectNotSerializable(parameterInfo)); } } public static MethodInfo ReadMethodInfoAndParameters(this FastBufferReader fastBufferReader, Type methodDeclaringType, ref object[] args) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) string name = default(string); ((FastBufferReader)(ref fastBufferReader)).ReadValueSafe(ref name, false); int num = default(int); ((FastBufferReader)(ref fastBufferReader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); MethodInfo method = methodDeclaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (num != method?.GetParameters().Length) { throw new Exception(TextHandler.InconsistentParameterCount(method, num)); } bool flag = default(bool); for (int i = 0; i < num; i++) { ((FastBufferReader)(ref fastBufferReader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { continue; } ParameterInfo parameterInfo = method.GetParameters()[i]; object serializable; if (parameterInfo.ParameterType.GetInterfaces().Contains(typeof(INetworkSerializable))) { fastBufferReader.ReadNetcodeSerializable(parameterInfo.ParameterType, out serializable); } else { if (!parameterInfo.ParameterType.IsSerializable) { throw new SerializationException(TextHandler.ObjectNotSerializable(parameterInfo)); } fastBufferReader.ReadSystemSerializable(out serializable); } args[i] = serializable; } return method; } } public sealed class NetcodeValidator : IDisposable { private static readonly List<string> AlreadyRegistered = new List<string>(); internal const string TypeCustomMessageHandlerPrefix = "Net"; private static List<(NetcodeValidator validator, Type custom, Type native)> BoundNetworkObjects { get; } = new List<(NetcodeValidator, Type, Type)>(); private List<string> CustomMessageHandlers { get; } private Harmony Patcher { get; } public string PluginGuid { get; } internal static event Action<NetcodeValidator, Type> AddedNewBoundBehaviour; private event Action<string> AddedNewCustomMessageHandler; public NetcodeValidator(string pluginGuid) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue(pluginGuid, out var _)) { throw new InvalidPluginGuidException(pluginGuid); } if (AlreadyRegistered.Contains(pluginGuid)) { throw new AlreadyRegisteredException(pluginGuid); } AlreadyRegistered.Add(pluginGuid); PluginGuid = pluginGuid; CustomMessageHandlers = new List<string>(); Patcher = new Harmony(pluginGuid + "NicholaScott.BepInEx.RuntimeNetcodeRPCValidator"); Plugin.NetworkManagerInitialized += NetworkManagerInitialized; Plugin.NetworkManagerShutdown += NetworkManagerShutdown; } internal static void TryLoadRelatedComponentsInOrder(NetworkBehaviour __instance, MethodBase __originalMethod) { foreach (var item in from obj in BoundNetworkObjects where obj.native == __originalMethod.DeclaringType select obj into it orderby it.validator.PluginGuid select it) { Plugin.Logger.LogInfo((object)TextHandler.CustomComponentAddedToExistingObject(item, __originalMethod)); Component obj2 = ((Component)__instance).gameObject.AddComponent(item.custom); ((NetworkBehaviour)(object)((obj2 is NetworkBehaviour) ? obj2 : null)).SyncWithNetworkObject(); } } private bool Patch(MethodInfo rpcMethod, out bool isServerRpc, out bool isClientRpc) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown isServerRpc = ((MemberInfo)rpcMethod).GetCustomAttributes<ServerRpcAttribute>().Any(); isClientRpc = ((MemberInfo)rpcMethod).GetCustomAttributes<ClientRpcAttribute>().Any(); bool flag = rpcMethod.Name.EndsWith("ServerRpc"); bool flag2 = rpcMethod.Name.EndsWith("ClientRpc"); if (!isClientRpc && !isServerRpc && !flag2 && !flag) { return false; } if ((!isServerRpc && flag) || (!isClientRpc && flag2)) { Plugin.Logger.LogError((object)TextHandler.MethodLacksRpcAttribute(rpcMethod)); return false; } if ((isServerRpc && !flag) || (isClientRpc && !flag2)) { Plugin.Logger.LogError((object)TextHandler.MethodLacksSuffix(rpcMethod)); return false; } Patcher.Patch((MethodBase)rpcMethod, new HarmonyMethod(typeof(NetworkBehaviourExtensions), "MethodPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } public void BindToPreExistingObjectByBehaviour<TCustomBehaviour, TNativeBehaviour>() where TCustomBehaviour : NetworkBehaviour where TNativeBehaviour : NetworkBehaviour { if (Object.op_Implicit((Object)(object)NetworkManager.Singleton) && (NetworkManager.Singleton.IsListening || NetworkManager.Singleton.IsConnectedClient)) { Plugin.Logger.LogError((object)TextHandler.PluginTriedToBindToPreExistingObjectTooLate(this, typeof(TCustomBehaviour), typeof(TNativeBehaviour))); } else { OnAddedNewBoundBehaviour(this, typeof(TCustomBehaviour), typeof(TNativeBehaviour)); } } public void Patch(Type netBehaviourTyped) { if (netBehaviourTyped.BaseType != typeof(NetworkBehaviour)) { throw new NotNetworkBehaviourException(netBehaviourTyped); } OnAddedNewCustomMessageHandler("Net." + netBehaviourTyped.Name); int num = 0; int num2 = 0; MethodInfo[] methods = netBehaviourTyped.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo rpcMethod in methods) { if (Patch(rpcMethod, out var isServerRpc, out var isClientRpc)) { num += (isServerRpc ? 1 : 0); num2 += (isClientRpc ? 1 : 0); } } Plugin.Logger.LogInfo((object)TextHandler.SuccessfullyPatchedType(netBehaviourTyped, num, num2)); } public void Patch(Assembly assembly) { Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (type.BaseType == typeof(NetworkBehaviour)) { Patch(type); } } } public void PatchAll() { Assembly assembly = new StackTrace().GetFrame(1).GetMethod().ReflectedType?.Assembly; if (assembly == null) { throw new MustCallFromDeclaredTypeException(); } Patch(assembly); } public void UnpatchSelf() { Plugin.Logger.LogInfo((object)TextHandler.PluginUnpatchedAllRPCs(this)); Patcher.UnpatchSelf(); } private static void RegisterMessageHandlerWithNetworkManager(string handler) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler(handler, new HandleNamedMessageDelegate(NetworkBehaviourExtensions.ReceiveNetworkMessage)); } private void NetworkManagerInitialized() { AddedNewCustomMessageHandler += RegisterMessageHandlerWithNetworkManager; foreach (string customMessageHandler in CustomMessageHandlers) { RegisterMessageHandlerWithNetworkManager(customMessageHandler); } } private void NetworkManagerShutdown() { AddedNewCustomMessageHandler -= RegisterMessageHandlerWithNetworkManager; foreach (string customMessageHandler in CustomMessageHandlers) { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler(customMessageHandler); } } public void Dispose() { Plugin.NetworkManagerInitialized -= NetworkManagerInitialized; Plugin.NetworkManagerShutdown -= NetworkManagerShutdown; AlreadyRegistered.Remove(PluginGuid); if (Object.op_Implicit((Object)(object)NetworkManager.Singleton)) { NetworkManagerShutdown(); } if (Patcher.GetPatchedMethods().Any()) { UnpatchSelf(); } } private void OnAddedNewCustomMessageHandler(string obj) { CustomMessageHandlers.Add(obj); this.AddedNewCustomMessageHandler?.Invoke(obj); } private static void OnAddedNewBoundBehaviour(NetcodeValidator validator, Type custom, Type native) { BoundNetworkObjects.Add((validator, custom, native)); NetcodeValidator.AddedNewBoundBehaviour?.Invoke(validator, native); } } public static class NetworkBehaviourExtensions { public enum RpcState { FromUser, FromNetworking } private static RpcState RpcSource; public static ClientRpcParams CreateSendToFromReceived(this ServerRpcParams senderId) { //IL_0002: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) ClientRpcParams result = default(ClientRpcParams); result.Send = new ClientRpcSendParams { TargetClientIds = new ulong[1] { senderId.Receive.SenderClientId } }; return result; } public static void SyncWithNetworkObject(this NetworkBehaviour networkBehaviour) { if (!networkBehaviour.NetworkObject.ChildNetworkBehaviours.Contains(networkBehaviour)) { networkBehaviour.NetworkObject.ChildNetworkBehaviours.Add(networkBehaviour); } networkBehaviour.UpdateNetworkProperties(); } private static bool ValidateRPCMethod(NetworkBehaviour networkBehaviour, MethodBase method, RpcState state, out RpcAttribute rpcAttribute) { bool flag = ((MemberInfo)method).GetCustomAttributes<ServerRpcAttribute>().Any(); bool flag2 = ((MemberInfo)method).GetCustomAttributes<ClientRpcAttribute>().Any(); bool num = flag && ((MemberInfo)method).GetCustomAttribute<ServerRpcAttribute>().RequireOwnership; rpcAttribute = (RpcAttribute)(flag ? ((object)((MemberInfo)method).GetCustomAttribute<ServerRpcAttribute>()) : ((object)((MemberInfo)method).GetCustomAttribute<ClientRpcAttribute>())); if (num && networkBehaviour.OwnerClientId != NetworkManager.Singleton.LocalClientId) { Plugin.Logger.LogError((object)TextHandler.NotOwnerOfNetworkObject((state == RpcState.FromUser) ? "We" : "Client", method, networkBehaviour.NetworkObject)); return false; } if (state == RpcState.FromUser && flag2 && !NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsHost) { Plugin.Logger.LogError((object)TextHandler.CantRunClientRpcFromClient(method)); return false; } if (state == RpcState.FromUser && !flag && !flag2) { Plugin.Logger.LogError((object)TextHandler.MethodPatchedButLacksAttributes(method)); return false; } if (state == RpcState.FromNetworking && !flag && !flag2) { Plugin.Logger.LogError((object)TextHandler.MethodPatchedAndNetworkCalledButLacksAttributes(method)); return false; } if (state == RpcState.FromNetworking && flag && !networkBehaviour.IsServer && !networkBehaviour.IsHost) { Plugin.Logger.LogError((object)TextHandler.CantRunServerRpcAsClient(method)); return false; } return true; } private static bool MethodPatchInternal(NetworkBehaviour networkBehaviour, MethodBase method, object[] args) { //IL_007d: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)NetworkManager.Singleton) || (!NetworkManager.Singleton.IsListening && !NetworkManager.Singleton.IsConnectedClient)) { Plugin.Logger.LogError((object)TextHandler.NoNetworkManagerPresentToSendRpc(networkBehaviour)); return false; } RpcState rpcSource = RpcSource; RpcSource = RpcState.FromUser; if (rpcSource == RpcState.FromNetworking) { return true; } if (!ValidateRPCMethod(networkBehaviour, method, rpcSource, out var rpcAttribute)) { return false; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor((method.GetParameters().Length + 1) * 128, (Allocator)2, -1); ulong networkObjectId = networkBehaviour.NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives)); ushort networkBehaviourId = networkBehaviour.NetworkBehaviourId; ((FastBufferWriter)(ref val)).WriteValueSafe<ushort>(ref networkBehaviourId, default(ForPrimitives)); val.WriteMethodInfoAndParameters(method, args); string text = new StringBuilder("Net").Append(".").Append(method.DeclaringType.Name).ToString(); NetworkDelivery val2 = (NetworkDelivery)(((int)rpcAttribute.Delivery == 0) ? 2 : 0); if (rpcAttribute is ServerRpcAttribute) { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(text, 0uL, val, val2); } else { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 0 && parameters[^1].ParameterType == typeof(ClientRpcParams)) { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(text, ((ClientRpcParams)args[^1]).Send.TargetClientIds, val, val2); } else { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll(text, val, val2); } } return false; } internal static void ReceiveNetworkMessage(ulong sender, FastBufferReader reader) { //IL_0006: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) ulong key = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref key, default(ForPrimitives)); ushort num = default(ushort); ((FastBufferReader)(ref reader)).ReadValueSafe<ushort>(ref num, default(ForPrimitives)); int position = ((FastBufferReader)(ref reader)).Position; string text = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false); ((FastBufferReader)(ref reader)).Seek(position); if (!NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(key, out var value)) { Plugin.Logger.LogError((object)TextHandler.RpcCalledBeforeObjectSpawned()); return; } NetworkBehaviour networkBehaviourAtOrderIndex = value.GetNetworkBehaviourAtOrderIndex(num); MethodInfo method = ((object)networkBehaviourAtOrderIndex).GetType().GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); RpcAttribute rpcAttribute; if (method == null) { Plugin.Logger.LogError((object)TextHandler.NetworkCalledNonExistentMethod(networkBehaviourAtOrderIndex, text)); } else if (ValidateRPCMethod(networkBehaviourAtOrderIndex, method, RpcState.FromNetworking, out rpcAttribute)) { RpcSource = RpcState.FromNetworking; ParameterInfo[] parameters = method.GetParameters(); bool num2 = rpcAttribute is ServerRpcAttribute && parameters.Length != 0 && parameters[^1].ParameterType == typeof(ServerRpcParams); object[] args = null; if (parameters.Length != 0) { args = new object[parameters.Length]; } reader.ReadMethodInfoAndParameters(method.DeclaringType, ref args); if (num2) { args[^1] = (object)new ServerRpcParams { Receive = new ServerRpcReceiveParams { SenderClientId = sender } }; } method.Invoke(networkBehaviourAtOrderIndex, args); } } internal static bool MethodPatch(NetworkBehaviour __instance, MethodBase __originalMethod, object[] __args) { return MethodPatchInternal(__instance, __originalMethod, __args); } } [BepInPlugin("NicholaScott.BepInEx.RuntimeNetcodeRPCValidator", "RuntimeNetcodeRPCValidator", "0.2.5")] public class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("NicholaScott.BepInEx.RuntimeNetcodeRPCValidator"); private List<Type> AlreadyPatchedNativeBehaviours { get; } = new List<Type>(); internal static ManualLogSource Logger { get; private set; } public static event Action NetworkManagerInitialized; public static event Action NetworkManagerShutdown; private void Awake() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; NetcodeValidator.AddedNewBoundBehaviour += NetcodeValidatorOnAddedNewBoundBehaviour; _harmony.Patch((MethodBase)AccessTools.Method(typeof(NetworkManager), "Initialize", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "OnNetworkManagerInitialized", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)AccessTools.Method(typeof(NetworkManager), "Shutdown", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "OnNetworkManagerShutdown", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private void NetcodeValidatorOnAddedNewBoundBehaviour(NetcodeValidator validator, Type netBehaviour) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown if (!AlreadyPatchedNativeBehaviours.Contains(netBehaviour)) { AlreadyPatchedNativeBehaviours.Add(netBehaviour); MethodBase methodBase = AccessTools.Method(netBehaviour, "Awake", (Type[])null, (Type[])null); if (methodBase == null) { methodBase = AccessTools.Method(netBehaviour, "Start", (Type[])null, (Type[])null); } if (methodBase == null) { methodBase = AccessTools.Constructor(netBehaviour, (Type[])null, false); } Logger.LogInfo((object)TextHandler.RegisteredPatchForType(validator, netBehaviour, methodBase)); HarmonyMethod val = new HarmonyMethod(typeof(NetcodeValidator), "TryLoadRelatedComponentsInOrder", (Type[])null); _harmony.Patch(methodBase, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } protected static void OnNetworkManagerInitialized() { Plugin.NetworkManagerInitialized?.Invoke(); } protected static void OnNetworkManagerShutdown() { Plugin.NetworkManagerShutdown?.Invoke(); } } internal static class TextHandler { private const string NoNetworkManagerPresentToSendRpcConst = "NetworkBehaviour {0} tried to send a RPC but the NetworkManager is non-existant!"; private const string MethodLacksAttributeConst = "Can't patch method {0}.{1} because it lacks a [{2}] attribute."; private const string MethodLacksSuffixConst = "Can't patch method {0}.{1} because it's name doesn't end with '{2}'!"; private const string SuccessfullyPatchedTypeConst = "Patched {0} ServerRPC{1} & {2} ClientRPC{3} on NetworkBehaviour {4}."; private const string NotOwnerOfNetworkObjectConst = "{0} tried to run ServerRPC {1} but not the owner of NetworkObject {2}"; private const string CantRunClientRpcFromClientConst = "Tried to run ClientRpc {0} but we're not a host! You should only call ClientRpc(s) from inside a ServerRpc OR if you've checked you're on the server with IsHost!"; private const string CantRunServerRpcAsClientConst = "Received message to run ServerRPC {0}.{1} but we're a client!"; private const string MethodPatchedButLacksAttributesConst = "Rpc Method {0} has been patched to attempt networking but lacks any RpcAttributes! This should never happen!"; private const string MethodPatchedAndNetworkCalledButLacksAttributesConst = "Rpc Method {0} has been patched && even received a network call to execute but lacks any RpcAttributes! This should never happen! Something is VERY fucky!!!"; private const string RpcCalledBeforeObjectSpawnedConst = "An RPC called on a NetworkObject that is not in the spawned objects list. Please make sure the NetworkObject is spawned before calling RPCs."; private const string NetworkCalledNonExistentMethodConst = "NetworkBehaviour {0} received RPC {1} but that method doesn't exist on {2}!"; private const string ObjectNotSerializableConst = "[Network] Parameter ({0} {1}) is not marked [Serializable] nor does it implement INetworkSerializable!"; private const string InconsistentParameterCountConst = "[Network] NetworkBehaviour received a RPC {0} but the number of parameters sent {1} != MethodInfo param count {2}"; private const string PluginTriedToBindToPreExistingObjectTooLateConst = "Plugin '{0}' tried to bind {1} to {2} but it's too late! Make sure you bind to any pre-existing NetworkObjects before NetworkManager.IsListening || IsConnectedClient."; private const string RegisteredPatchForTypeConst = "Successfully registered first patch for type {0}.{1} | Triggered by {2}"; private const string CustomComponentAddedToExistingObjectConst = "Successfully added {0} to {1} via {2}. Triggered by plugin {3}"; private const string PluginUnpatchedAllRPCsConst = "Plugin {0} has unpatched all RPCs!"; internal static string NoNetworkManagerPresentToSendRpc(NetworkBehaviour networkBehaviour) { return $"NetworkBehaviour {networkBehaviour.NetworkBehaviourId} tried to send a RPC but the NetworkManager is non-existant!"; } internal static string MethodLacksRpcAttribute(MethodInfo method) { return string.Format("Can't patch method {0}.{1} because it lacks a [{2}] attribute.", method.DeclaringType?.Name, method.Name, method.Name.EndsWith("ServerRpc") ? "ServerRpc" : "ClientRpc"); } internal static string MethodLacksSuffix(MethodBase method) { return string.Format("Can't patch method {0}.{1} because it's name doesn't end with '{2}'!", method.DeclaringType?.Name, method.Name, (((MemberInfo)method).GetCustomAttribute<ServerRpcAttribute>() != null) ? "ServerRpc" : "ClientRpc"); } internal static string SuccessfullyPatchedType(Type networkType, int serverRpcCount, int clientRpcCount) { return string.Format("Patched {0} ServerRPC{1} & {2} ClientRPC{3} on NetworkBehaviour {4}.", serverRpcCount, (serverRpcCount == 1) ? "" : "s", clientRpcCount, (clientRpcCount == 1) ? "" : "s", networkType.Name); } internal static string NotOwnerOfNetworkObject(string whoIsNotOwner, MethodBase method, NetworkObject networkObject) { return $"{whoIsNotOwner} tried to run ServerRPC {method.Name} but not the owner of NetworkObject {networkObject.NetworkObjectId}"; } internal static string CantRunClientRpcFromClient(MethodBase method) { return $"Tried to run ClientRpc {method.Name} but we're not a host! You should only call ClientRpc(s) from inside a ServerRpc OR if you've checked you're on the server with IsHost!"; } internal static string CantRunServerRpcAsClient(MethodBase method) { return $"Received message to run ServerRPC {method.DeclaringType?.Name}.{method.Name} but we're a client!"; } internal static string MethodPatchedButLacksAttributes(MethodBase method) { return $"Rpc Method {method.Name} has been patched to attempt networking but lacks any RpcAttributes! This should never happen!"; } internal static string MethodPatchedAndNetworkCalledButLacksAttributes(MethodBase method) { return $"Rpc Method {method.Name} has been patched && even received a network call to execute but lacks any RpcAttributes! This should never happen! Something is VERY fucky!!!"; } internal static string RpcCalledBeforeObjectSpawned() { return "An RPC called on a NetworkObject that is not in the spawned objects list. Please make sure the NetworkObject is spawned before calling RPCs."; } internal static string NetworkCalledNonExistentMethod(NetworkBehaviour networkBehaviour, string rpcName) { return $"NetworkBehaviour {networkBehaviour.NetworkBehaviourId} received RPC {rpcName} but that method doesn't exist on {((object)networkBehaviour).GetType().Name}!"; } internal static string ObjectNotSerializable(ParameterInfo paramInfo) { return $"[Network] Parameter ({paramInfo.ParameterType.Name} {paramInfo.Name}) is not marked [Serializable] nor does it implement INetworkSerializable!"; } internal static string InconsistentParameterCount(MethodBase method, int paramsSent) { return $"[Network] NetworkBehaviour received a RPC {method.Name} but the number of parameters sent {paramsSent} != MethodInfo param count {method.GetParameters().Length}"; } internal static string PluginTriedToBindToPreExistingObjectTooLate(NetcodeValidator netcodeValidator, Type from, Type to) { return $"Plugin '{netcodeValidator.PluginGuid}' tried to bind {from.Name} to {to.Name} but it's too late! Make sure you bind to any pre-existing NetworkObjects before NetworkManager.IsListening || IsConnectedClient."; } internal static string RegisteredPatchForType(NetcodeValidator validator, Type netBehaviour, MethodBase method) { return $"Successfully registered first patch for type {netBehaviour.Name}.{method.Name} | Triggered by {validator.PluginGuid}"; } internal static string CustomComponentAddedToExistingObject((NetcodeValidator validator, Type custom, Type native) it, MethodBase methodBase) { return $"Successfully added {it.custom.Name} to {it.native.Name} via {methodBase.Name}. Triggered by plugin {it.validator.PluginGuid}"; } internal static string PluginUnpatchedAllRPCs(NetcodeValidator netcodeValidator) { return $"Plugin {netcodeValidator.PluginGuid} has unpatched all RPCs!"; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "NicholaScott.BepInEx.RuntimeNetcodeRPCValidator"; public const string PLUGIN_NAME = "RuntimeNetcodeRPCValidator"; public const string PLUGIN_VERSION = "0.2.5"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }