diff --git a/com.unity.multiplayer.mlapi/Editor/CodeGen/NetworkBehaviourILPP.cs b/com.unity.multiplayer.mlapi/Editor/CodeGen/NetworkBehaviourILPP.cs index 69b455e8b0..d7e44a3127 100644 --- a/com.unity.multiplayer.mlapi/Editor/CodeGen/NetworkBehaviourILPP.cs +++ b/com.unity.multiplayer.mlapi/Editor/CodeGen/NetworkBehaviourILPP.cs @@ -57,7 +57,7 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) mainModule.GetTypes() .Where(t => t.IsSubclassOf(CodeGenHelpers.NetworkBehaviour_FullName)) .ToList() - .ForEach(ProcessNetworkBehaviour); + .ForEach(b => ProcessNetworkBehaviour(b, compiledAssembly.Defines)); } else { @@ -95,6 +95,8 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) private FieldReference m_NetworkManager_LogLevel_FieldRef; private FieldReference m_NetworkManager_ntable_FieldRef; private MethodReference m_NetworkManager_ntable_Add_MethodRef; + private FieldReference m_NetworkManager_rpc_name_table_FieldRef; + private MethodReference m_NetworkManager_rpc_name_table_Add_MethodRef; private TypeReference m_NetworkBehaviour_TypeRef; private MethodReference m_NetworkBehaviour_BeginSendServerRpc_MethodRef; private MethodReference m_NetworkBehaviour_EndSendServerRpc_MethodRef; @@ -164,6 +166,7 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) private const string k_NetworkManager_LogLevel = nameof(NetworkManager.LogLevel); #pragma warning disable 618 private const string k_NetworkManager_ntable = nameof(NetworkManager.__ntable); + private const string k_NetworkManager_rpc_name_table = nameof(NetworkManager.__rpc_name_table); private const string k_NetworkBehaviour_BeginSendServerRpc = nameof(NetworkBehaviour.__beginSendServerRpc); private const string k_NetworkBehaviour_EndSendServerRpc = nameof(NetworkBehaviour.__endSendServerRpc); @@ -235,6 +238,10 @@ private bool ImportReferences(ModuleDefinition moduleDefinition) m_NetworkManager_ntable_FieldRef = moduleDefinition.ImportReference(fieldInfo); m_NetworkManager_ntable_Add_MethodRef = moduleDefinition.ImportReference(fieldInfo.FieldType.GetMethod("Add")); break; + case k_NetworkManager_rpc_name_table: + m_NetworkManager_rpc_name_table_FieldRef = moduleDefinition.ImportReference(fieldInfo); + m_NetworkManager_rpc_name_table_Add_MethodRef = moduleDefinition.ImportReference(fieldInfo.FieldType.GetMethod("Add")); + break; } } @@ -523,9 +530,13 @@ private bool ImportReferences(ModuleDefinition moduleDefinition) return true; } - private void ProcessNetworkBehaviour(TypeDefinition typeDefinition) + private void ProcessNetworkBehaviour(TypeDefinition typeDefinition, string[] assemblyDefines) { - var staticHandlers = new List<(uint Hash, MethodDefinition Method)>(); + var rpcHandlers = new List<(uint RpcHash, MethodDefinition RpcHandler)>(); + var rpcNames = new List<(uint RpcHash, string RpcName)>(); + + bool isEditorOrDevelopment = assemblyDefines.Contains("UNITY_EDITOR") || assemblyDefines.Contains("DEVELOPMENT_BUILD"); + foreach (var methodDefinition in typeDefinition.Methods) { var rpcAttribute = CheckAndGetRPCAttribute(methodDefinition); @@ -541,10 +552,16 @@ private void ProcessNetworkBehaviour(TypeDefinition typeDefinition) } InjectWriteAndCallBlocks(methodDefinition, rpcAttribute, methodDefHash); - staticHandlers.Add((methodDefHash, GenerateStaticHandler(methodDefinition, rpcAttribute))); + + rpcHandlers.Add((methodDefHash, GenerateStaticHandler(methodDefinition, rpcAttribute))); + + if (isEditorOrDevelopment) + { + rpcNames.Add((methodDefHash, methodDefinition.Name)); + } } - if (staticHandlers.Count > 0) + if (rpcHandlers.Count > 0 || rpcNames.Count > 0) { var staticCtorMethodDef = typeDefinition.GetStaticConstructor(); if (staticCtorMethodDef == null) @@ -562,24 +579,29 @@ private void ProcessNetworkBehaviour(TypeDefinition typeDefinition) var instructions = new List(); var processor = staticCtorMethodDef.Body.GetILProcessor(); - foreach (var (hash, method) in staticHandlers) - { - if (hash == 0 || method == null) - { - continue; - } - typeDefinition.Methods.Add(method); + foreach (var (rpcHash, rpcHandler) in rpcHandlers) + { + typeDefinition.Methods.Add(rpcHandler); - // NetworkManager.__ntable.Add(HandlerHash, HandlerMethod); + // NetworkManager.__ntable.Add(RpcHash, HandleFunc); instructions.Add(processor.Create(OpCodes.Ldsfld, m_NetworkManager_ntable_FieldRef)); - instructions.Add(processor.Create(OpCodes.Ldc_I4, unchecked((int)hash))); + instructions.Add(processor.Create(OpCodes.Ldc_I4, unchecked((int)rpcHash))); instructions.Add(processor.Create(OpCodes.Ldnull)); - instructions.Add(processor.Create(OpCodes.Ldftn, method)); + instructions.Add(processor.Create(OpCodes.Ldftn, rpcHandler)); instructions.Add(processor.Create(OpCodes.Newobj, m_NetworkHandlerDelegateCtor_MethodRef)); instructions.Add(processor.Create(OpCodes.Call, m_NetworkManager_ntable_Add_MethodRef)); } + foreach (var (rpcHash, rpcName) in rpcNames) + { + // NetworkManager.__rpc_name_table.Add(RpcHash, RpcName); + instructions.Add(processor.Create(OpCodes.Ldsfld, m_NetworkManager_rpc_name_table_FieldRef)); + instructions.Add(processor.Create(OpCodes.Ldc_I4, unchecked((int)rpcHash))); + instructions.Add(processor.Create(OpCodes.Ldstr, rpcName)); + instructions.Add(processor.Create(OpCodes.Call, m_NetworkManager_rpc_name_table_Add_MethodRef)); + } + instructions.Reverse(); instructions.ForEach(instruction => processor.Body.Instructions.Insert(0, instruction)); } diff --git a/com.unity.multiplayer.mlapi/Editor/CodeGen/RuntimeAccessModifiersILPP.cs b/com.unity.multiplayer.mlapi/Editor/CodeGen/RuntimeAccessModifiersILPP.cs index 2ba7b3a5cc..0b86b809dd 100644 --- a/com.unity.multiplayer.mlapi/Editor/CodeGen/RuntimeAccessModifiersILPP.cs +++ b/com.unity.multiplayer.mlapi/Editor/CodeGen/RuntimeAccessModifiersILPP.cs @@ -1,6 +1,7 @@ #if UNITY_2020_2_OR_NEWER using System.Collections.Generic; using System.IO; +using System.Linq; using Mono.Cecil; using Mono.Cecil.Cil; using Unity.CompilationPipeline.Common.Diagnostics; @@ -49,7 +50,7 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) switch (typeDefinition.Name) { case nameof(NetworkManager): - ProcessNetworkManager(typeDefinition); + ProcessNetworkManager(typeDefinition, compiledAssembly.Defines); break; case nameof(NetworkBehaviour): ProcessNetworkBehaviour(typeDefinition); @@ -81,7 +82,7 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), m_Diagnostics); } - private void ProcessNetworkManager(TypeDefinition typeDefinition) + private void ProcessNetworkManager(TypeDefinition typeDefinition, string[] assemblyDefines) { foreach (var fieldDefinition in typeDefinition.Fields) { @@ -89,6 +90,14 @@ private void ProcessNetworkManager(TypeDefinition typeDefinition) { fieldDefinition.IsPublic = true; } + + if (assemblyDefines.Contains("UNITY_EDITOR") || assemblyDefines.Contains("DEVELOPMENT_BUILD")) + { + if (fieldDefinition.Name == nameof(NetworkManager.__rpc_name_table)) + { + fieldDefinition.IsPublic = true; + } + } } } diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 22fc7335c5..37c78a3a11 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -35,10 +35,21 @@ public class NetworkManager : MonoBehaviour, INetworkUpdateSystem, IProfilableTr #if UNITY_2020_2_OR_NEWER // RuntimeAccessModifiersILPP will make this `public` internal static readonly Dictionary> __ntable = new Dictionary>(); -#else + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + // RuntimeAccessModifiersILPP will make this `public` + internal static readonly Dictionary __rpc_name_table = new Dictionary(); +#else // !(UNITY_EDITOR || DEVELOPMENT_BUILD) + // RuntimeAccessModifiersILPP and NetworkBehaviourILPP requires a variable with this name to exist when outside of Debug build or Editor. + // If the name doesn't exist, generation and compilation errors occurs. + // For the sake of consistency, we are using the same type. + // Final note: this variable will not be used. Since it's never initialized, it will not be in the memory footprint. + internal static readonly Dictionary __rpc_name_table = null; +#endif // UNITY_EDITOR || DEVELOPMENT_BUILD +#else // !UNITY_2020_2_OR_NEWER [Obsolete("Please do not use, will no longer be exposed in the future versions (framework internal)")] public static readonly Dictionary> __ntable = new Dictionary>(); -#endif +#endif // UNITY_2020_2_OR_NEWER #pragma warning restore IDE1006 // restore naming rule violation check #if DEVELOPMENT_BUILD || UNITY_EDITOR