com.unity.netcode.gameobjects@1.0.0-pre.8

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.8] - 2022-04-27

### Changed

- `unmanaged` structs are no longer universally accepted as RPC parameters because some structs (i.e., structs with pointers in them, such as `NativeList<T>`) can't be supported by the default memcpy struct serializer. Structs that are intended to be serialized across the network must add `INetworkSerializeByMemcpy` to the interface list (i.e., `struct Foo : INetworkSerializeByMemcpy`). This interface is empty and just serves to mark the struct as compatible with memcpy serialization. For external structs you can't edit, you can pass them to RPCs by wrapping them in `ForceNetworkSerializeByMemcpy<T>`. (#1901)

### Removed
- Removed `SIPTransport` (#1870)

- Removed `ClientNetworkTransform` from the package samples and moved to Boss Room's Utilities package which can be found [here](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/main/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/ClientAuthority/ClientNetworkTransform.cs).

### Fixed

- Fixed `NetworkTransform` generating false positive rotation delta checks when rolling over between 0 and 360 degrees. (#1890)
- Fixed client throwing an exception if it has messages in the outbound queue when processing the `NetworkEvent.Disconnect` event and is using UTP. (#1884)
- Fixed issue during client synchronization if 'ValidateSceneBeforeLoading' returned false it would halt the client synchronization process resulting in a client that was approved but not synchronized or fully connected with the server. (#1883)
- Fixed an issue where UNetTransport.StartServer would return success even if the underlying transport failed to start (#854)
- Passing generic types to RPCs no longer causes a native crash (#1901)
- Fixed an issue where calling `Shutdown` on a `NetworkManager` that was already shut down would cause an immediate shutdown the next time it was started (basically the fix makes `Shutdown` idempotent). (#1877)
This commit is contained in:
Unity Technologies
2022-04-27 00:00:00 +00:00
parent 60e2dabef4
commit add668dfd2
119 changed files with 4434 additions and 1801 deletions

View File

@@ -509,6 +509,12 @@ namespace Unity.Netcode.Editor.CodeGen
isValid = false;
}
if (methodDefinition.HasGenericParameters)
{
m_Diagnostics.AddError(methodDefinition, "RPC method must not be generic!");
isValid = false;
}
if (methodDefinition.ReturnType != methodDefinition.Module.TypeSystem.Void)
{
m_Diagnostics.AddError(methodDefinition, "RPC method must return `void`!");
@@ -533,6 +539,10 @@ namespace Unity.Netcode.Editor.CodeGen
{
rpcAttribute = customAttribute;
}
else
{
return null;
}
}
}
@@ -575,11 +585,17 @@ namespace Unity.Netcode.Editor.CodeGen
var checkType = paramType.Resolve();
if (paramType.IsArray)
{
checkType = paramType.GetElementType().Resolve();
checkType = ((ArrayType)paramType).ElementType.Resolve();
}
if ((parameters[0].ParameterType.Resolve() == checkType ||
(parameters[0].ParameterType.Resolve() == checkType.MakeByReferenceType().Resolve() && parameters[0].IsIn)))
(parameters[0].ParameterType.Resolve() == checkType.MakeByReferenceType().Resolve() && parameters[0].IsIn)))
{
return method;
}
if (parameters[0].ParameterType == paramType ||
(parameters[0].ParameterType == paramType.MakeByReferenceType() && parameters[0].IsIn))
{
return method;
}
@@ -593,8 +609,9 @@ namespace Unity.Netcode.Editor.CodeGen
{
var resolvedConstraint = constraint.Resolve();
if ((resolvedConstraint.IsInterface && !checkType.HasInterface(resolvedConstraint.FullName)) ||
(resolvedConstraint.IsClass && !checkType.Resolve().IsSubclassOf(resolvedConstraint.FullName)) ||
var resolvedConstraintName = resolvedConstraint.FullNameWithGenericParameters(new[] { method.GenericParameters[0] }, new[] { checkType });
if ((resolvedConstraint.IsInterface && !checkType.HasInterface(resolvedConstraintName)) ||
(resolvedConstraint.IsClass && !checkType.Resolve().IsSubclassOf(resolvedConstraintName)) ||
(resolvedConstraint.Name == "ValueType" && !checkType.IsValueType))
{
meetsConstraints = false;
@@ -605,7 +622,14 @@ namespace Unity.Netcode.Editor.CodeGen
if (meetsConstraints)
{
var instanceMethod = new GenericInstanceMethod(method);
instanceMethod.GenericArguments.Add(checkType);
if (paramType.IsArray)
{
instanceMethod.GenericArguments.Add(((ArrayType)paramType).ElementType);
}
else
{
instanceMethod.GenericArguments.Add(paramType);
}
return instanceMethod;
}
}
@@ -653,13 +677,7 @@ namespace Unity.Netcode.Editor.CodeGen
}
}
// Try NetworkSerializable first because INetworkSerializable may also be valid for WriteValueSafe
// and that would cause boxing if so.
var typeMethod = GetFastBufferWriterWriteMethod("WriteNetworkSerializable", paramType);
if (typeMethod == null)
{
typeMethod = GetFastBufferWriterWriteMethod(k_WriteValueMethodName, paramType);
}
var typeMethod = GetFastBufferWriterWriteMethod(k_WriteValueMethodName, paramType);
if (typeMethod != null)
{
methodRef = m_MainModule.ImportReference(typeMethod);
@@ -699,29 +717,53 @@ namespace Unity.Netcode.Editor.CodeGen
var checkType = paramType.Resolve();
if (paramType.IsArray)
{
checkType = paramType.GetElementType().Resolve();
checkType = ((ArrayType)paramType).ElementType.Resolve();
}
if (methodParam.Resolve() == checkType.Resolve() || methodParam.Resolve() == checkType.MakeByReferenceType().Resolve())
{
return method;
}
if (methodParam.Resolve() == paramType || methodParam.Resolve() == paramType.MakeByReferenceType().Resolve())
{
return method;
}
if (method.HasGenericParameters && method.GenericParameters.Count == 1)
{
if (method.GenericParameters[0].HasConstraints)
{
var meetsConstraints = true;
foreach (var constraint in method.GenericParameters[0].Constraints)
{
var resolvedConstraint = constraint.Resolve();
if ((resolvedConstraint.IsInterface && checkType.HasInterface(resolvedConstraint.FullName)) ||
(resolvedConstraint.IsClass && checkType.Resolve().IsSubclassOf(resolvedConstraint.FullName)))
var resolvedConstraintName = resolvedConstraint.FullNameWithGenericParameters(new[] { method.GenericParameters[0] }, new[] { checkType });
if ((resolvedConstraint.IsInterface && !checkType.HasInterface(resolvedConstraintName)) ||
(resolvedConstraint.IsClass && !checkType.Resolve().IsSubclassOf(resolvedConstraintName)) ||
(resolvedConstraint.Name == "ValueType" && !checkType.IsValueType))
{
var instanceMethod = new GenericInstanceMethod(method);
instanceMethod.GenericArguments.Add(checkType);
return instanceMethod;
meetsConstraints = false;
break;
}
}
if (meetsConstraints)
{
var instanceMethod = new GenericInstanceMethod(method);
if (paramType.IsArray)
{
instanceMethod.GenericArguments.Add(((ArrayType)paramType).ElementType);
}
else
{
instanceMethod.GenericArguments.Add(paramType);
}
return instanceMethod;
}
}
}
}
@@ -751,13 +793,7 @@ namespace Unity.Netcode.Editor.CodeGen
}
}
// Try NetworkSerializable first because INetworkSerializable may also be valid for ReadValueSafe
// and that would cause boxing if so.
var typeMethod = GetFastBufferReaderReadMethod("ReadNetworkSerializable", paramType);
if (typeMethod == null)
{
typeMethod = GetFastBufferReaderReadMethod(k_ReadValueMethodName, paramType);
}
var typeMethod = GetFastBufferReaderReadMethod(k_ReadValueMethodName, paramType);
if (typeMethod != null)
{
methodRef = m_MainModule.ImportReference(typeMethod);
@@ -1003,6 +1039,17 @@ namespace Unity.Netcode.Editor.CodeGen
// bufferWriter.WriteValueSafe(isSet);
instructions.Add(processor.Create(OpCodes.Ldloca, bufWriterLocIdx));
instructions.Add(processor.Create(OpCodes.Ldloca, isSetLocalIndex));
for (var i = 1; i < boolMethodRef.Parameters.Count; ++i)
{
var param = boolMethodRef.Parameters[i];
methodDefinition.Body.Variables.Add(new VariableDefinition(param.ParameterType));
int overloadParamLocalIdx = methodDefinition.Body.Variables.Count - 1;
instructions.Add(processor.Create(OpCodes.Ldloca, overloadParamLocalIdx));
instructions.Add(processor.Create(OpCodes.Initobj, param.ParameterType));
instructions.Add(processor.Create(OpCodes.Ldloc, overloadParamLocalIdx));
}
instructions.Add(processor.Create(OpCodes.Call, boolMethodRef));
// if(isSet) {
@@ -1055,11 +1102,38 @@ namespace Unity.Netcode.Editor.CodeGen
{
instructions.Add(processor.Create(OpCodes.Ldc_I4_0));
}
else
{
if (isExtensionMethod && methodRef.Parameters.Count > 2)
{
for (var i = 2; i < methodRef.Parameters.Count; ++i)
{
var param = methodRef.Parameters[i];
methodDefinition.Body.Variables.Add(new VariableDefinition(param.ParameterType));
int overloadParamLocalIdx = methodDefinition.Body.Variables.Count - 1;
instructions.Add(processor.Create(OpCodes.Ldloca, overloadParamLocalIdx));
instructions.Add(processor.Create(OpCodes.Initobj, param.ParameterType));
instructions.Add(processor.Create(OpCodes.Ldloc, overloadParamLocalIdx));
}
}
else if (!isExtensionMethod && methodRef.Parameters.Count > 1)
{
for (var i = 1; i < methodRef.Parameters.Count; ++i)
{
var param = methodRef.Parameters[i];
methodDefinition.Body.Variables.Add(new VariableDefinition(param.ParameterType));
int overloadParamLocalIdx = methodDefinition.Body.Variables.Count - 1;
instructions.Add(processor.Create(OpCodes.Ldloca, overloadParamLocalIdx));
instructions.Add(processor.Create(OpCodes.Initobj, param.ParameterType));
instructions.Add(processor.Create(OpCodes.Ldloc, overloadParamLocalIdx));
}
}
}
instructions.Add(processor.Create(OpCodes.Call, methodRef));
}
else
{
m_Diagnostics.AddError(methodDefinition, $"Don't know how to serialize {paramType.Name} - implement {nameof(INetworkSerializable)} or add an extension method for {nameof(FastBufferWriter)}.{k_WriteValueMethodName} to define serialization.");
m_Diagnostics.AddError(methodDefinition, $"Don't know how to serialize {paramType.Name} - implement {nameof(INetworkSerializable)}, tag memcpyable struct with {nameof(INetworkSerializeByMemcpy)}, or add an extension method for {nameof(FastBufferWriter)}.{k_WriteValueMethodName} to define serialization.");
continue;
}
@@ -1298,6 +1372,17 @@ namespace Unity.Netcode.Editor.CodeGen
int isSetLocalIndex = rpcHandler.Body.Variables.Count - 1;
processor.Emit(OpCodes.Ldarga, 1);
processor.Emit(OpCodes.Ldloca, isSetLocalIndex);
for (var i = 1; i < boolMethodRef.Parameters.Count; ++i)
{
var param = boolMethodRef.Parameters[i];
rpcHandler.Body.Variables.Add(new VariableDefinition(param.ParameterType));
int overloadParamLocalIdx = rpcHandler.Body.Variables.Count - 1;
processor.Emit(OpCodes.Ldloca, overloadParamLocalIdx);
processor.Emit(OpCodes.Initobj, param.ParameterType);
processor.Emit(OpCodes.Ldloc, overloadParamLocalIdx);
}
processor.Emit(OpCodes.Call, boolMethodRef);
// paramType param = null;
@@ -1331,11 +1416,38 @@ namespace Unity.Netcode.Editor.CodeGen
{
processor.Emit(OpCodes.Ldc_I4_0);
}
else
{
if (isExtensionMethod && methodRef.Parameters.Count > 2)
{
for (var i = 2; i < methodRef.Parameters.Count; ++i)
{
var param = methodRef.Parameters[i];
rpcHandler.Body.Variables.Add(new VariableDefinition(param.ParameterType));
int overloadParamLocalIdx = rpcHandler.Body.Variables.Count - 1;
processor.Emit(OpCodes.Ldloca, overloadParamLocalIdx);
processor.Emit(OpCodes.Initobj, param.ParameterType);
processor.Emit(OpCodes.Ldloc, overloadParamLocalIdx);
}
}
else if (!isExtensionMethod && methodRef.Parameters.Count > 1)
{
for (var i = 1; i < methodRef.Parameters.Count; ++i)
{
var param = methodRef.Parameters[i];
rpcHandler.Body.Variables.Add(new VariableDefinition(param.ParameterType));
int overloadParamLocalIdx = rpcHandler.Body.Variables.Count - 1;
processor.Emit(OpCodes.Ldloca, overloadParamLocalIdx);
processor.Emit(OpCodes.Initobj, param.ParameterType);
processor.Emit(OpCodes.Ldloc, overloadParamLocalIdx);
}
}
}
processor.Emit(OpCodes.Call, methodRef);
}
else
{
m_Diagnostics.AddError(methodDefinition, $"Don't know how to deserialize {paramType.Name} - implement {nameof(INetworkSerializable)} or add an extension method for {nameof(FastBufferReader)}.{k_ReadValueMethodName} to define serialization.");
m_Diagnostics.AddError(methodDefinition, $"Don't know how to serialize {paramType.Name} - implement {nameof(INetworkSerializable)}, tag memcpyable struct with {nameof(INetworkSerializeByMemcpy)}, or add an extension method for {nameof(FastBufferWriter)}.{k_WriteValueMethodName} to define serialization.");
continue;
}