com.unity.netcode.gameobjects@1.0.0-pre.6
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). ## [1.0.0-pre.6] - 2022-03-02 ### Added - NetworkAnimator now properly synchrhonizes all animation layers as well as runtime-adjusted weighting between them (#1765) - Added first set of tests for NetworkAnimator - parameter syncing, trigger set / reset, override network animator (#1735) ### Changed ### Fixed - Fixed an issue where sometimes the first client to connect to the server could see messages from the server as coming from itself. (#1683) - Fixed an issue where clients seemed to be able to send messages to ClientId 1, but these messages would actually still go to the server (id 0) instead of that client. (#1683) - Improved clarity of error messaging when a client attempts to send a message to a destination other than the server, which isn't allowed. (#1683) - Disallowed async keyword in RPCs (#1681) - Fixed an issue where Alpha release versions of Unity (version 2022.2.0a5 and later) will not compile due to the UNet Transport no longer existing (#1678) - Fixed messages larger than 64k being written with incorrectly truncated message size in header (#1686) (credit: @kaen) - Fixed overloading RPC methods causing collisions and failing on IL2CPP targets. (#1694) - Fixed spawn flow to propagate `IsSceneObject` down to children NetworkObjects, decouple implicit relationship between object spawning & `IsSceneObject` flag (#1685) - Fixed error when serializing ConnectionApprovalMessage with scene management disabled when one or more objects is hidden via the CheckObjectVisibility delegate (#1720) - Fixed CheckObjectVisibility delegate not being properly invoked for connecting clients when Scene Management is enabled. (#1680) - Fixed NetworkList to properly call INetworkSerializable's NetworkSerialize() method (#1682) - Fixed NetworkVariables containing more than 1300 bytes of data (such as large NetworkLists) no longer cause an OverflowException (the limit on data size is now whatever limit the chosen transport imposes on fragmented NetworkDelivery mechanisms) (#1725) - Fixed ServerRpcParams and ClientRpcParams must be the last parameter of an RPC in order to function properly. Added a compile-time check to ensure this is the case and trigger an error if they're placed elsewhere (#1721) - Fixed FastBufferReader being created with a length of 1 if provided an input of length 0 (#1724) - Fixed The NetworkConfig's checksum hash includes the NetworkTick so that clients with a different tickrate than the server are identified and not allowed to connect (#1728) - Fixed OwnedObjects not being properly modified when using ChangeOwnership (#1731) - Improved performance in NetworkAnimator (#1735) - Removed the "always sync" network animator (aka "autosend") parameters (#1746)
This commit is contained in:
@@ -7,7 +7,6 @@ using System.Runtime.CompilerServices;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using Mono.Cecil.Rocks;
|
||||
using Unity.Collections;
|
||||
using Unity.CompilationPipeline.Common.Diagnostics;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
using UnityEngine;
|
||||
@@ -17,7 +16,6 @@ using ILPPInterface = Unity.CompilationPipeline.Common.ILPostProcessing.ILPostPr
|
||||
|
||||
namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
|
||||
internal sealed class NetworkBehaviourILPP : ILPPInterface
|
||||
{
|
||||
private const string k_ReadValueMethodName = nameof(FastBufferReader.ReadValueSafe);
|
||||
@@ -25,7 +23,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
public override ILPPInterface GetInstance() => this;
|
||||
|
||||
public override bool WillProcess(ICompiledAssembly compiledAssembly) => compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == CodeGenHelpers.RuntimeAssemblyName);
|
||||
public override bool WillProcess(ICompiledAssembly compiledAssembly) =>
|
||||
compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == CodeGenHelpers.RuntimeAssemblyName);
|
||||
|
||||
private readonly List<DiagnosticMessage> m_Diagnostics = new List<DiagnosticMessage>();
|
||||
|
||||
@@ -109,8 +108,10 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
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_SendServerRpc_MethodRef;
|
||||
private MethodReference m_NetworkBehaviour_SendClientRpc_MethodRef;
|
||||
private MethodReference m_NetworkBehaviour_beginSendServerRpc_MethodRef;
|
||||
private MethodReference m_NetworkBehaviour_endSendServerRpc_MethodRef;
|
||||
private MethodReference m_NetworkBehaviour_beginSendClientRpc_MethodRef;
|
||||
private MethodReference m_NetworkBehaviour_endSendClientRpc_MethodRef;
|
||||
private FieldReference m_NetworkBehaviour_rpc_exec_stage_FieldRef;
|
||||
private MethodReference m_NetworkBehaviour_getNetworkManager_MethodRef;
|
||||
private MethodReference m_NetworkBehaviour_getOwnerClientId_MethodRef;
|
||||
@@ -124,8 +125,6 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
private TypeReference m_ClientRpcParams_TypeRef;
|
||||
|
||||
private TypeReference m_FastBufferWriter_TypeRef;
|
||||
private MethodReference m_FastBufferWriter_Constructor;
|
||||
private MethodReference m_FastBufferWriter_Dispose;
|
||||
private Dictionary<string, MethodReference> m_FastBufferWriter_WriteValue_MethodRefs = new Dictionary<string, MethodReference>();
|
||||
private List<MethodReference> m_FastBufferWriter_ExtensionMethodRefs = new List<MethodReference>();
|
||||
|
||||
@@ -144,8 +143,10 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
private const string k_NetworkManager_rpc_name_table = nameof(NetworkManager.__rpc_name_table);
|
||||
|
||||
private const string k_NetworkBehaviour_rpc_exec_stage = nameof(NetworkBehaviour.__rpc_exec_stage);
|
||||
private const string k_NetworkBehaviour_SendServerRpc = nameof(NetworkBehaviour.__sendServerRpc);
|
||||
private const string k_NetworkBehaviour_SendClientRpc = nameof(NetworkBehaviour.__sendClientRpc);
|
||||
private const string k_NetworkBehaviour_beginSendServerRpc = nameof(NetworkBehaviour.__beginSendServerRpc);
|
||||
private const string k_NetworkBehaviour_endSendServerRpc = nameof(NetworkBehaviour.__endSendServerRpc);
|
||||
private const string k_NetworkBehaviour_beginSendClientRpc = nameof(NetworkBehaviour.__beginSendClientRpc);
|
||||
private const string k_NetworkBehaviour_endSendClientRpc = nameof(NetworkBehaviour.__endSendClientRpc);
|
||||
private const string k_NetworkBehaviour_NetworkManager = nameof(NetworkBehaviour.NetworkManager);
|
||||
private const string k_NetworkBehaviour_OwnerClientId = nameof(NetworkBehaviour.OwnerClientId);
|
||||
|
||||
@@ -234,11 +235,17 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
switch (methodInfo.Name)
|
||||
{
|
||||
case k_NetworkBehaviour_SendServerRpc:
|
||||
m_NetworkBehaviour_SendServerRpc_MethodRef = moduleDefinition.ImportReference(methodInfo);
|
||||
case k_NetworkBehaviour_beginSendServerRpc:
|
||||
m_NetworkBehaviour_beginSendServerRpc_MethodRef = moduleDefinition.ImportReference(methodInfo);
|
||||
break;
|
||||
case k_NetworkBehaviour_SendClientRpc:
|
||||
m_NetworkBehaviour_SendClientRpc_MethodRef = moduleDefinition.ImportReference(methodInfo);
|
||||
case k_NetworkBehaviour_endSendServerRpc:
|
||||
m_NetworkBehaviour_endSendServerRpc_MethodRef = moduleDefinition.ImportReference(methodInfo);
|
||||
break;
|
||||
case k_NetworkBehaviour_beginSendClientRpc:
|
||||
m_NetworkBehaviour_beginSendClientRpc_MethodRef = moduleDefinition.ImportReference(methodInfo);
|
||||
break;
|
||||
case k_NetworkBehaviour_endSendClientRpc:
|
||||
m_NetworkBehaviour_endSendClientRpc_MethodRef = moduleDefinition.ImportReference(methodInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -299,17 +306,12 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
var fastBufferWriterType = typeof(FastBufferWriter);
|
||||
m_FastBufferWriter_TypeRef = moduleDefinition.ImportReference(fastBufferWriterType);
|
||||
|
||||
m_FastBufferWriter_Constructor = moduleDefinition.ImportReference(
|
||||
fastBufferWriterType.GetConstructor(new[] { typeof(int), typeof(Allocator), typeof(int) }));
|
||||
m_FastBufferWriter_Dispose = moduleDefinition.ImportReference(fastBufferWriterType.GetMethod("Dispose"));
|
||||
|
||||
var fastBufferReaderType = typeof(FastBufferReader);
|
||||
m_FastBufferReader_TypeRef = moduleDefinition.ImportReference(fastBufferReaderType);
|
||||
|
||||
// Find all extension methods for FastBufferReader and FastBufferWriter to enable user-implemented
|
||||
// methods to be called.
|
||||
var assemblies = new List<AssemblyDefinition>();
|
||||
assemblies.Add(m_MainModule.Assembly);
|
||||
var assemblies = new List<AssemblyDefinition> { m_MainModule.Assembly };
|
||||
foreach (var reference in m_MainModule.AssemblyReferences)
|
||||
{
|
||||
var assembly = m_AssemblyResolver.Resolve(reference);
|
||||
@@ -319,8 +321,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
}
|
||||
}
|
||||
|
||||
var extensionConstructor =
|
||||
moduleDefinition.ImportReference(typeof(ExtensionAttribute).GetConstructor(new Type[] { }));
|
||||
var extensionConstructor = moduleDefinition.ImportReference(typeof(ExtensionAttribute).GetConstructor(new Type[] { }));
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
foreach (var module in assembly.Modules)
|
||||
@@ -332,6 +333,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var method in type.Methods)
|
||||
{
|
||||
if (!method.IsStatic)
|
||||
@@ -356,13 +358,11 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
var parameters = method.Parameters;
|
||||
|
||||
if (parameters.Count == 2
|
||||
&& parameters[0].ParameterType.Resolve() == m_FastBufferWriter_TypeRef.MakeByReferenceType().Resolve())
|
||||
if (parameters.Count == 2 && parameters[0].ParameterType.Resolve() == m_FastBufferWriter_TypeRef.MakeByReferenceType().Resolve())
|
||||
{
|
||||
m_FastBufferWriter_ExtensionMethodRefs.Add(m_MainModule.ImportReference(method));
|
||||
}
|
||||
else if (parameters.Count == 2
|
||||
&& parameters[0].ParameterType.Resolve() == m_FastBufferReader_TypeRef.MakeByReferenceType().Resolve())
|
||||
else if (parameters.Count == 2 && parameters[0].ParameterType.Resolve() == m_FastBufferReader_TypeRef.MakeByReferenceType().Resolve())
|
||||
{
|
||||
m_FastBufferReader_ExtensionMethodRefs.Add(m_MainModule.ImportReference(method));
|
||||
}
|
||||
@@ -395,9 +395,20 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
continue;
|
||||
}
|
||||
|
||||
if (methodDefinition.HasCustomAttributes)
|
||||
{
|
||||
foreach (var attribute in methodDefinition.CustomAttributes)
|
||||
{
|
||||
if (attribute.AttributeType.Name == nameof(AsyncStateMachineAttribute))
|
||||
{
|
||||
m_Diagnostics.AddError(methodDefinition, $"{methodDefinition.FullName}: RPCs cannot be 'async'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InjectWriteAndCallBlocks(methodDefinition, rpcAttribute, rpcMethodId);
|
||||
|
||||
rpcHandlers.Add((rpcMethodId, GenerateStaticHandler(methodDefinition, rpcAttribute)));
|
||||
rpcHandlers.Add((rpcMethodId, GenerateStaticHandler(methodDefinition, rpcAttribute, rpcMethodId)));
|
||||
|
||||
if (isEditorOrDevelopment)
|
||||
{
|
||||
@@ -477,7 +488,6 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
private CustomAttribute CheckAndGetRpcAttribute(MethodDefinition methodDefinition)
|
||||
{
|
||||
CustomAttribute rpcAttribute = null;
|
||||
bool isServerRpc = false;
|
||||
foreach (var customAttribute in methodDefinition.CustomAttributes)
|
||||
{
|
||||
var customAttributeType_FullName = customAttribute.AttributeType.FullName;
|
||||
@@ -521,7 +531,6 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
isServerRpc = customAttributeType_FullName == CodeGenHelpers.ServerRpcAttribute_FullName;
|
||||
rpcAttribute = customAttribute;
|
||||
}
|
||||
}
|
||||
@@ -569,12 +578,12 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
checkType = paramType.GetElementType().Resolve();
|
||||
}
|
||||
|
||||
if (
|
||||
(parameters[0].ParameterType.Resolve() == checkType
|
||||
|| (parameters[0].ParameterType.Resolve() == checkType.MakeByReferenceType().Resolve() && parameters[0].IsIn)))
|
||||
if ((parameters[0].ParameterType.Resolve() == checkType ||
|
||||
(parameters[0].ParameterType.Resolve() == checkType.MakeByReferenceType().Resolve() && parameters[0].IsIn)))
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
if (method.HasGenericParameters && method.GenericParameters.Count == 1)
|
||||
{
|
||||
if (method.GenericParameters[0].HasConstraints)
|
||||
@@ -584,17 +593,15 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
var resolvedConstraint = constraint.Resolve();
|
||||
|
||||
if (
|
||||
(resolvedConstraint.IsInterface &&
|
||||
!checkType.HasInterface(resolvedConstraint.FullName))
|
||||
|| (resolvedConstraint.IsClass &&
|
||||
!checkType.Resolve().IsSubclassOf(resolvedConstraint.FullName))
|
||||
|| (resolvedConstraint.Name == "ValueType" && !checkType.IsValueType))
|
||||
if ((resolvedConstraint.IsInterface && !checkType.HasInterface(resolvedConstraint.FullName)) ||
|
||||
(resolvedConstraint.IsClass && !checkType.Resolve().IsSubclassOf(resolvedConstraint.FullName)) ||
|
||||
(resolvedConstraint.Name == "ValueType" && !checkType.IsValueType))
|
||||
{
|
||||
meetsConstraints = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (meetsConstraints)
|
||||
{
|
||||
var instanceMethod = new GenericInstanceMethod(method);
|
||||
@@ -624,8 +631,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
if (parameters[1].IsIn)
|
||||
{
|
||||
if (parameters[1].ParameterType.Resolve() == paramType.MakeByReferenceType().Resolve()
|
||||
&& ((ByReferenceType)parameters[1].ParameterType).ElementType.IsArray == paramType.IsArray)
|
||||
if (parameters[1].ParameterType.Resolve() == paramType.MakeByReferenceType().Resolve() &&
|
||||
((ByReferenceType)parameters[1].ParameterType).ElementType.IsArray == paramType.IsArray)
|
||||
{
|
||||
methodRef = method;
|
||||
m_FastBufferWriter_WriteValue_MethodRefs[assemblyQualifiedName] = methodRef;
|
||||
@@ -635,8 +642,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
else
|
||||
{
|
||||
|
||||
if (parameters[1].ParameterType.Resolve() == paramType.Resolve()
|
||||
&& parameters[1].ParameterType.IsArray == paramType.IsArray)
|
||||
if (parameters[1].ParameterType.Resolve() == paramType.Resolve() &&
|
||||
parameters[1].ParameterType.IsArray == paramType.IsArray)
|
||||
{
|
||||
methodRef = method;
|
||||
m_FastBufferWriter_WriteValue_MethodRefs[assemblyQualifiedName] = methodRef;
|
||||
@@ -707,11 +714,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
{
|
||||
var resolvedConstraint = constraint.Resolve();
|
||||
|
||||
if (
|
||||
(resolvedConstraint.IsInterface &&
|
||||
checkType.HasInterface(resolvedConstraint.FullName))
|
||||
|| (resolvedConstraint.IsClass &&
|
||||
checkType.Resolve().IsSubclassOf(resolvedConstraint.FullName)))
|
||||
if ((resolvedConstraint.IsInterface && checkType.HasInterface(resolvedConstraint.FullName)) ||
|
||||
(resolvedConstraint.IsClass && checkType.Resolve().IsSubclassOf(resolvedConstraint.FullName)))
|
||||
{
|
||||
var instanceMethod = new GenericInstanceMethod(method);
|
||||
instanceMethod.GenericArguments.Add(checkType);
|
||||
@@ -736,11 +740,10 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
foreach (var method in m_FastBufferReader_ExtensionMethodRefs)
|
||||
{
|
||||
var parameters = method.Resolve().Parameters;
|
||||
if (
|
||||
method.Name == k_ReadValueMethodName
|
||||
&& parameters[1].IsOut
|
||||
&& parameters[1].ParameterType.Resolve() == paramType.MakeByReferenceType().Resolve()
|
||||
&& ((ByReferenceType)parameters[1].ParameterType).ElementType.IsArray == paramType.IsArray)
|
||||
if (method.Name == k_ReadValueMethodName &&
|
||||
parameters[1].IsOut &&
|
||||
parameters[1].ParameterType.Resolve() == paramType.MakeByReferenceType().Resolve() &&
|
||||
((ByReferenceType)parameters[1].ParameterType).ElementType.IsArray == paramType.IsArray)
|
||||
{
|
||||
methodRef = method;
|
||||
m_FastBufferReader_ReadValue_MethodRefs[assemblyQualifiedName] = methodRef;
|
||||
@@ -772,8 +775,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
var instructions = new List<Instruction>();
|
||||
var processor = methodDefinition.Body.GetILProcessor();
|
||||
var isServerRpc = rpcAttribute.AttributeType.FullName == CodeGenHelpers.ServerRpcAttribute_FullName;
|
||||
var requireOwnership = true; // default value MUST be = `ServerRpcAttribute.RequireOwnership`
|
||||
var rpcDelivery = RpcDelivery.Reliable; // default value MUST be = `RpcAttribute.Delivery`
|
||||
var requireOwnership = true; // default value MUST be == `ServerRpcAttribute.RequireOwnership`
|
||||
var rpcDelivery = RpcDelivery.Reliable; // default value MUST be == `RpcAttribute.Delivery`
|
||||
foreach (var attrField in rpcAttribute.Fields)
|
||||
{
|
||||
switch (attrField.Name)
|
||||
@@ -797,9 +800,9 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
// NetworkManager networkManager;
|
||||
methodDefinition.Body.Variables.Add(new VariableDefinition(m_NetworkManager_TypeRef));
|
||||
int netManLocIdx = methodDefinition.Body.Variables.Count - 1;
|
||||
// NetworkSerializer serializer;
|
||||
// FastBufferWriter bufferWriter;
|
||||
methodDefinition.Body.Variables.Add(new VariableDefinition(m_FastBufferWriter_TypeRef));
|
||||
int serializerLocIdx = methodDefinition.Body.Variables.Count - 1;
|
||||
int bufWriterLocIdx = methodDefinition.Body.Variables.Count - 1;
|
||||
|
||||
// XXXRpcParams
|
||||
if (!hasRpcParams)
|
||||
@@ -854,6 +857,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
instructions.Add(beginInstr);
|
||||
|
||||
// var bufferWriter = __beginSendServerRpc(rpcMethodId, serverRpcParams, rpcDelivery) -> ServerRpc
|
||||
// var bufferWriter = __beginSendClientRpc(rpcMethodId, clientRpcParams, rpcDelivery) -> ClientRpc
|
||||
if (isServerRpc)
|
||||
{
|
||||
// ServerRpc
|
||||
@@ -867,8 +872,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_NetworkBehaviour_getOwnerClientId_MethodRef));
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, netManLocIdx));
|
||||
instructions.Add(
|
||||
processor.Create(OpCodes.Callvirt, m_NetworkManager_getLocalClientId_MethodRef));
|
||||
instructions.Add(processor.Create(OpCodes.Callvirt, m_NetworkManager_getLocalClientId_MethodRef));
|
||||
instructions.Add(processor.Create(OpCodes.Ceq));
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, 0));
|
||||
instructions.Add(processor.Create(OpCodes.Ceq));
|
||||
@@ -886,8 +890,7 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
instructions.Add(processor.Create(OpCodes.Brfalse, logNextInstr));
|
||||
|
||||
// Debug.LogError(...);
|
||||
instructions.Add(processor.Create(OpCodes.Ldstr,
|
||||
"Only the owner can invoke a ServerRpc that requires ownership!"));
|
||||
instructions.Add(processor.Create(OpCodes.Ldstr, "Only the owner can invoke a ServerRpc that requires ownership!"));
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_Debug_LogError_MethodRef));
|
||||
|
||||
instructions.Add(logNextInstr);
|
||||
@@ -895,31 +898,86 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
instructions.Add(roReturnInstr);
|
||||
instructions.Add(roLastInstr);
|
||||
}
|
||||
|
||||
// var bufferWriter = __beginSendServerRpc(rpcMethodId, serverRpcParams, rpcDelivery);
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
|
||||
// rpcMethodId
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, unchecked((int)rpcMethodId)));
|
||||
|
||||
// rpcParams
|
||||
instructions.Add(hasRpcParams ? processor.Create(OpCodes.Ldarg, paramCount) : processor.Create(OpCodes.Ldloc, rpcParamsIdx));
|
||||
|
||||
// rpcDelivery
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, (int)rpcDelivery));
|
||||
|
||||
// __beginSendServerRpc
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_NetworkBehaviour_beginSendServerRpc_MethodRef));
|
||||
instructions.Add(processor.Create(OpCodes.Stloc, bufWriterLocIdx));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ClientRpc
|
||||
|
||||
// var writer = new FastBufferWriter(1285, Allocator.Temp, 63985);
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, serializerLocIdx));
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, 1300 - sizeof(byte) - sizeof(ulong) - sizeof(uint) - sizeof(ushort)));
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4_2));
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, 64000 - sizeof(byte) - sizeof(ulong) - sizeof(uint) - sizeof(ushort)));
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_FastBufferWriter_Constructor));
|
||||
// var bufferWriter = __beginSendClientRpc(rpcMethodId, clientRpcParams, rpcDelivery);
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
|
||||
var firstInstruction = processor.Create(OpCodes.Nop);
|
||||
instructions.Add(firstInstruction);
|
||||
// rpcMethodId
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, unchecked((int)rpcMethodId)));
|
||||
|
||||
// rpcParams
|
||||
instructions.Add(hasRpcParams ? processor.Create(OpCodes.Ldarg, paramCount) : processor.Create(OpCodes.Ldloc, rpcParamsIdx));
|
||||
|
||||
// rpcDelivery
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, (int)rpcDelivery));
|
||||
|
||||
// __beginSendClientRpc
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_NetworkBehaviour_beginSendClientRpc_MethodRef));
|
||||
instructions.Add(processor.Create(OpCodes.Stloc, bufWriterLocIdx));
|
||||
}
|
||||
|
||||
// write method parameters into stream
|
||||
for (int paramIndex = 0; paramIndex < paramCount; ++paramIndex)
|
||||
{
|
||||
var paramDef = methodDefinition.Parameters[paramIndex];
|
||||
var paramType = paramDef.ParameterType;
|
||||
// ServerRpcParams
|
||||
if (paramType.FullName == CodeGenHelpers.ServerRpcParams_FullName && isServerRpc && paramIndex == paramCount - 1)
|
||||
if (paramType.FullName == CodeGenHelpers.ClientRpcSendParams_FullName ||
|
||||
paramType.FullName == CodeGenHelpers.ClientRpcReceiveParams_FullName)
|
||||
{
|
||||
m_Diagnostics.AddError($"Rpcs may not accept {paramType.FullName} as a parameter. Use {nameof(ClientRpcParams)} instead.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (paramType.FullName == CodeGenHelpers.ServerRpcSendParams_FullName ||
|
||||
paramType.FullName == CodeGenHelpers.ServerRpcReceiveParams_FullName)
|
||||
{
|
||||
m_Diagnostics.AddError($"Rpcs may not accept {paramType.FullName} as a parameter. Use {nameof(ServerRpcParams)} instead.");
|
||||
continue;
|
||||
}
|
||||
// ServerRpcParams
|
||||
if (paramType.FullName == CodeGenHelpers.ServerRpcParams_FullName)
|
||||
{
|
||||
if (paramIndex != paramCount - 1)
|
||||
{
|
||||
m_Diagnostics.AddError(methodDefinition, $"{nameof(ServerRpcParams)} must be the last parameter in a ServerRpc.");
|
||||
}
|
||||
if (!isServerRpc)
|
||||
{
|
||||
m_Diagnostics.AddError($"ClientRpcs may not accept {nameof(ServerRpcParams)} as a parameter.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// ClientRpcParams
|
||||
if (paramType.FullName == CodeGenHelpers.ClientRpcParams_FullName && !isServerRpc && paramIndex == paramCount - 1)
|
||||
if (paramType.FullName == CodeGenHelpers.ClientRpcParams_FullName)
|
||||
{
|
||||
if (paramIndex != paramCount - 1)
|
||||
{
|
||||
m_Diagnostics.AddError(methodDefinition, $"{nameof(ClientRpcParams)} must be the last parameter in a ClientRpc.");
|
||||
}
|
||||
if (isServerRpc)
|
||||
{
|
||||
m_Diagnostics.AddError($"ServerRpcs may not accept {nameof(ClientRpcParams)} as a parameter.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -942,8 +1000,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
instructions.Add(processor.Create(OpCodes.Cgt_Un));
|
||||
instructions.Add(processor.Create(OpCodes.Stloc, isSetLocalIndex));
|
||||
|
||||
// writer.WriteValueSafe(isSet);
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, serializerLocIdx));
|
||||
// bufferWriter.WriteValueSafe(isSet);
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, bufWriterLocIdx));
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, isSetLocalIndex));
|
||||
instructions.Add(processor.Create(OpCodes.Call, boolMethodRef));
|
||||
|
||||
@@ -956,11 +1014,11 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
var foundMethodRef = GetWriteMethodForParameter(paramType, out var methodRef);
|
||||
if (foundMethodRef)
|
||||
{
|
||||
// writer.WriteNetworkSerializable(param) for INetworkSerializable, OR
|
||||
// writer.WriteNetworkSerializable(param, -1, 0) for INetworkSerializable arrays, OR
|
||||
// writer.WriteValueSafe(param) for value types, OR
|
||||
// writer.WriteValueSafe(param, -1, 0) for arrays of value types, OR
|
||||
// writer.WriteValueSafe(param, false) for strings
|
||||
// bufferWriter.WriteNetworkSerializable(param) for INetworkSerializable, OR
|
||||
// bufferWriter.WriteNetworkSerializable(param, -1, 0) for INetworkSerializable arrays, OR
|
||||
// bufferWriter.WriteValueSafe(param) for value types, OR
|
||||
// bufferWriter.WriteValueSafe(param, -1, 0) for arrays of value types, OR
|
||||
// bufferWriter.WriteValueSafe(param, false) for strings
|
||||
var method = methodRef.Resolve();
|
||||
var checkParameter = method.Parameters[0];
|
||||
var isExtensionMethod = false;
|
||||
@@ -971,11 +1029,11 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
}
|
||||
if (!isExtensionMethod || method.Parameters[0].ParameterType.IsByReference)
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, serializerLocIdx));
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, bufWriterLocIdx));
|
||||
}
|
||||
else
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, serializerLocIdx));
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, bufWriterLocIdx));
|
||||
}
|
||||
if (checkParameter.IsIn || checkParameter.IsOut || checkParameter.ParameterType.IsByReference)
|
||||
{
|
||||
@@ -986,16 +1044,14 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg, paramIndex + 1));
|
||||
}
|
||||
// Special handling for WriteValue() on arrays and strings since they have additional arguments.
|
||||
if (paramType.IsArray
|
||||
&& ((!isExtensionMethod && methodRef.Parameters.Count == 3)
|
||||
|| (isExtensionMethod && methodRef.Parameters.Count == 4)))
|
||||
if (paramType.IsArray && ((!isExtensionMethod && methodRef.Parameters.Count == 3) ||
|
||||
(isExtensionMethod && methodRef.Parameters.Count == 4)))
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4_M1));
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4_0));
|
||||
}
|
||||
else if (paramType == typeSystem.String
|
||||
&& ((!isExtensionMethod && methodRef.Parameters.Count == 2)
|
||||
|| (isExtensionMethod && methodRef.Parameters.Count == 3)))
|
||||
else if (paramType == typeSystem.String && ((!isExtensionMethod && methodRef.Parameters.Count == 2) ||
|
||||
(isExtensionMethod && methodRef.Parameters.Count == 3)))
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4_0));
|
||||
}
|
||||
@@ -1015,20 +1071,20 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
|
||||
instructions.Add(endInstr);
|
||||
|
||||
// __sendServerRpc(ref serializer, rpcMethodId, serverRpcParams, rpcDelivery) -> ServerRpc
|
||||
// __sendClientRpc(ref serializer, rpcMethodId, clientRpcParams, rpcDelivery) -> ClientRpc
|
||||
// __endSendServerRpc(ref bufferWriter, rpcMethodId, serverRpcParams, rpcDelivery) -> ServerRpc
|
||||
// __endSendClientRpc(ref bufferWriter, rpcMethodId, clientRpcParams, rpcDelivery) -> ClientRpc
|
||||
if (isServerRpc)
|
||||
{
|
||||
// ServerRpc
|
||||
// __sendServerRpc(ref serializer, rpcMethodId, serverRpcParams, rpcDelivery);
|
||||
|
||||
// __endSendServerRpc(ref bufferWriter, rpcMethodId, serverRpcParams, rpcDelivery);
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
|
||||
// serializer
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, serializerLocIdx));
|
||||
// bufferWriter
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, bufWriterLocIdx));
|
||||
|
||||
// rpcMethodId
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, unchecked((int)rpcMethodId)));
|
||||
|
||||
if (hasRpcParams)
|
||||
{
|
||||
// rpcParams
|
||||
@@ -1039,25 +1095,24 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
// default
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, rpcParamsIdx));
|
||||
}
|
||||
|
||||
// rpcDelivery
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, (int)rpcDelivery));
|
||||
|
||||
// EndSendServerRpc
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_NetworkBehaviour_SendServerRpc_MethodRef));
|
||||
// __endSendServerRpc
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_NetworkBehaviour_endSendServerRpc_MethodRef));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ClientRpc
|
||||
// __sendClientRpc(ref serializer, rpcMethodId, clientRpcParams, rpcDelivery);
|
||||
|
||||
// __endSendClientRpc(ref bufferWriter, rpcMethodId, clientRpcParams, rpcDelivery);
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
|
||||
// serializer
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, serializerLocIdx));
|
||||
// bufferWriter
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca, bufWriterLocIdx));
|
||||
|
||||
// rpcMethodId
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, unchecked((int)rpcMethodId)));
|
||||
|
||||
if (hasRpcParams)
|
||||
{
|
||||
// rpcParams
|
||||
@@ -1068,36 +1123,11 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
// default
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, rpcParamsIdx));
|
||||
}
|
||||
|
||||
// rpcDelivery
|
||||
instructions.Add(processor.Create(OpCodes.Ldc_I4, (int)rpcDelivery));
|
||||
|
||||
// EndSendClientRpc
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_NetworkBehaviour_SendClientRpc_MethodRef));
|
||||
}
|
||||
|
||||
{
|
||||
// TODO: Figure out why try/catch here cause the try block not to execute at all.
|
||||
// End try block
|
||||
//instructions.Add(processor.Create(OpCodes.Leave, lastInstr));
|
||||
|
||||
// writer.Dispose();
|
||||
var handlerFirst = processor.Create(OpCodes.Ldloca, serializerLocIdx);
|
||||
instructions.Add(handlerFirst);
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_FastBufferWriter_Dispose));
|
||||
|
||||
// End finally block
|
||||
//instructions.Add(processor.Create(OpCodes.Endfinally));
|
||||
|
||||
// try { ... serialization code ... } finally { writer.Dispose(); }
|
||||
/*var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
|
||||
{
|
||||
TryStart = firstInstruction,
|
||||
TryEnd = handlerFirst,
|
||||
HandlerStart = handlerFirst,
|
||||
HandlerEnd = lastInstr
|
||||
};
|
||||
processor.Body.ExceptionHandlers.Add(handler);*/
|
||||
// __endSendClientRpc
|
||||
instructions.Add(processor.Create(OpCodes.Call, m_NetworkBehaviour_endSendClientRpc_MethodRef));
|
||||
}
|
||||
|
||||
instructions.Add(lastInstr);
|
||||
@@ -1132,25 +1162,21 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
instructions.ForEach(instruction => processor.Body.Instructions.Insert(0, instruction));
|
||||
}
|
||||
|
||||
private MethodDefinition GenerateStaticHandler(MethodDefinition methodDefinition, CustomAttribute rpcAttribute)
|
||||
private MethodDefinition GenerateStaticHandler(MethodDefinition methodDefinition, CustomAttribute rpcAttribute, uint rpcMethodId)
|
||||
{
|
||||
var typeSystem = methodDefinition.Module.TypeSystem;
|
||||
var nhandler = new MethodDefinition(
|
||||
$"{methodDefinition.Name}__nhandler",
|
||||
var rpcHandler = new MethodDefinition(
|
||||
$"__rpc_handler_{rpcMethodId}",
|
||||
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig,
|
||||
methodDefinition.Module.TypeSystem.Void);
|
||||
nhandler.Parameters.Add(new ParameterDefinition("target", ParameterAttributes.None, m_NetworkBehaviour_TypeRef));
|
||||
nhandler.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, m_FastBufferReader_TypeRef));
|
||||
nhandler.Parameters.Add(new ParameterDefinition("rpcParams", ParameterAttributes.None, m_RpcParams_TypeRef));
|
||||
rpcHandler.Parameters.Add(new ParameterDefinition("target", ParameterAttributes.None, m_NetworkBehaviour_TypeRef));
|
||||
rpcHandler.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, m_FastBufferReader_TypeRef));
|
||||
rpcHandler.Parameters.Add(new ParameterDefinition("rpcParams", ParameterAttributes.None, m_RpcParams_TypeRef));
|
||||
|
||||
var processor = nhandler.Body.GetILProcessor();
|
||||
|
||||
// begin Try/Catch
|
||||
var tryStart = processor.Create(OpCodes.Nop);
|
||||
processor.Append(tryStart);
|
||||
var processor = rpcHandler.Body.GetILProcessor();
|
||||
|
||||
var isServerRpc = rpcAttribute.AttributeType.FullName == CodeGenHelpers.ServerRpcAttribute_FullName;
|
||||
var requireOwnership = true; // default value MUST be = `ServerRpcAttribute.RequireOwnership`
|
||||
var requireOwnership = true; // default value MUST be == `ServerRpcAttribute.RequireOwnership`
|
||||
foreach (var attrField in rpcAttribute.Fields)
|
||||
{
|
||||
switch (attrField.Name)
|
||||
@@ -1161,10 +1187,10 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
}
|
||||
}
|
||||
|
||||
nhandler.Body.InitLocals = true;
|
||||
rpcHandler.Body.InitLocals = true;
|
||||
// NetworkManager networkManager;
|
||||
nhandler.Body.Variables.Add(new VariableDefinition(m_NetworkManager_TypeRef));
|
||||
int netManLocIdx = nhandler.Body.Variables.Count - 1;
|
||||
rpcHandler.Body.Variables.Add(new VariableDefinition(m_NetworkManager_TypeRef));
|
||||
int netManLocIdx = rpcHandler.Body.Variables.Count - 1;
|
||||
|
||||
{
|
||||
var returnInstr = processor.Create(OpCodes.Ret);
|
||||
@@ -1233,8 +1259,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
var paramType = paramDef.ParameterType;
|
||||
|
||||
// local variable
|
||||
nhandler.Body.Variables.Add(new VariableDefinition(paramType));
|
||||
int localIndex = nhandler.Body.Variables.Count - 1;
|
||||
rpcHandler.Body.Variables.Add(new VariableDefinition(paramType));
|
||||
int localIndex = rpcHandler.Body.Variables.Count - 1;
|
||||
paramLocalMap[paramIndex] = localIndex;
|
||||
|
||||
// ServerRpcParams, ClientRpcParams
|
||||
@@ -1268,8 +1294,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
}
|
||||
|
||||
// reader.ReadValueSafe(out bool isSet)
|
||||
nhandler.Body.Variables.Add(new VariableDefinition(typeSystem.Boolean));
|
||||
int isSetLocalIndex = nhandler.Body.Variables.Count - 1;
|
||||
rpcHandler.Body.Variables.Add(new VariableDefinition(typeSystem.Boolean));
|
||||
int isSetLocalIndex = rpcHandler.Body.Variables.Count - 1;
|
||||
processor.Emit(OpCodes.Ldarga, 1);
|
||||
processor.Emit(OpCodes.Ldloca, isSetLocalIndex);
|
||||
processor.Emit(OpCodes.Call, boolMethodRef);
|
||||
@@ -1336,55 +1362,8 @@ namespace Unity.Netcode.Editor.CodeGen
|
||||
processor.Emit(OpCodes.Ldc_I4, (int)NetworkBehaviour.__RpcExecStage.None);
|
||||
processor.Emit(OpCodes.Stfld, m_NetworkBehaviour_rpc_exec_stage_FieldRef);
|
||||
|
||||
// pull in the Exception Module
|
||||
var exception = m_MainModule.ImportReference(typeof(Exception));
|
||||
|
||||
// Get Exception.ToString()
|
||||
var exp = m_MainModule.ImportReference(typeof(Exception).GetMethod("ToString", new Type[] { }));
|
||||
|
||||
// Get String.Format (This is equivalent to an interpolated string)
|
||||
var stringFormat = m_MainModule.ImportReference(typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) }));
|
||||
|
||||
nhandler.Body.Variables.Add(new VariableDefinition(exception));
|
||||
int exceptionVariableIndex = nhandler.Body.Variables.Count - 1;
|
||||
|
||||
//try ends/catch begins
|
||||
var catchEnds = processor.Create(OpCodes.Nop);
|
||||
processor.Emit(OpCodes.Leave, catchEnds);
|
||||
|
||||
// Load the Exception onto the stack
|
||||
var catchStarts = processor.Create(OpCodes.Stloc, exceptionVariableIndex);
|
||||
processor.Append(catchStarts);
|
||||
|
||||
// Load string for the error log that will be shown
|
||||
processor.Emit(OpCodes.Ldstr, $"Unhandled RPC Exception:\n {{0}}");
|
||||
processor.Emit(OpCodes.Ldloc, exceptionVariableIndex);
|
||||
processor.Emit(OpCodes.Callvirt, exp);
|
||||
processor.Emit(OpCodes.Call, stringFormat);
|
||||
|
||||
// Call Debug.LogError
|
||||
processor.Emit(OpCodes.Call, m_Debug_LogError_MethodRef);
|
||||
|
||||
// reset NetworkBehaviour.__rpc_exec_stage = __RpcExecStage.None;
|
||||
processor.Emit(OpCodes.Ldarg_0);
|
||||
processor.Emit(OpCodes.Ldc_I4, (int)NetworkBehaviour.__RpcExecStage.None);
|
||||
processor.Emit(OpCodes.Stfld, m_NetworkBehaviour_rpc_exec_stage_FieldRef);
|
||||
|
||||
// catch ends
|
||||
processor.Append(catchEnds);
|
||||
|
||||
processor.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
|
||||
{
|
||||
CatchType = exception,
|
||||
TryStart = tryStart,
|
||||
TryEnd = catchStarts,
|
||||
HandlerStart = catchStarts,
|
||||
HandlerEnd = catchEnds
|
||||
});
|
||||
|
||||
processor.Emit(OpCodes.Ret);
|
||||
|
||||
return nhandler;
|
||||
return rpcHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user