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.4] - 2021-01-04 ### Added - Added `com.unity.modules.physics` and `com.unity.modules.physics2d` package dependencies (#1565) ### Removed - Removed `com.unity.modules.ai` package dependency (#1565) - Removed `FixedQueue`, `StreamExtensions`, `TypeExtensions` (#1398) ### Fixed - Fixed in-scene NetworkObjects that are moved into the DDOL scene not getting restored to their original active state (enabled/disabled) after a full scene transition (#1354) - Fixed invalid IL code being generated when using `this` instead of `this ref` for the FastBufferReader/FastBufferWriter parameter of an extension method. (#1393) - Fixed an issue where if you are running as a server (not host) the LoadEventCompleted and UnloadEventCompleted events would fire early by the NetworkSceneManager (#1379) - Fixed a runtime error when sending an array of an INetworkSerializable type that's implemented as a struct (#1402) - NetworkConfig will no longer throw an OverflowException in GetConfig() when ForceSamePrefabs is enabled and the number of prefabs causes the config blob size to exceed 1300 bytes. (#1385) - Fixed NetworkVariable not calling NetworkSerialize on INetworkSerializable types (#1383) - Fixed NullReferenceException on ImportReferences call in NetworkBehaviourILPP (#1434) - Fixed NetworkObjects not being despawned before they are destroyed during shutdown for client, host, and server instances. (#1390) - Fixed KeyNotFound exception when removing ownership of a newly spawned NetworkObject that is already owned by the server. (#1500) - Fixed NetworkManager.LocalClient not being set when starting as a host. (#1511) - Fixed a few memory leak cases when shutting down NetworkManager during Incoming Message Queue processing. (#1323) ### Changed - The SDK no longer limits message size to 64k. (The transport may still impose its own limits, but the SDK no longer does.) (#1384) - Updated com.unity.collections to 1.1.0 (#1451)
349 lines
12 KiB
C#
349 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Mono.Cecil;
|
|
using Mono.Cecil.Cil;
|
|
using Mono.Cecil.Rocks;
|
|
using Unity.CompilationPipeline.Common.Diagnostics;
|
|
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.Netcode.Editor.CodeGen
|
|
{
|
|
internal static class CodeGenHelpers
|
|
{
|
|
public const string RuntimeAssemblyName = "Unity.Netcode.Runtime";
|
|
|
|
public static readonly string NetworkBehaviour_FullName = typeof(NetworkBehaviour).FullName;
|
|
public static readonly string INetworkMessage_FullName = typeof(INetworkMessage).FullName;
|
|
public static readonly string ServerRpcAttribute_FullName = typeof(ServerRpcAttribute).FullName;
|
|
public static readonly string ClientRpcAttribute_FullName = typeof(ClientRpcAttribute).FullName;
|
|
public static readonly string ServerRpcParams_FullName = typeof(ServerRpcParams).FullName;
|
|
public static readonly string ClientRpcParams_FullName = typeof(ClientRpcParams).FullName;
|
|
public static readonly string INetworkSerializable_FullName = typeof(INetworkSerializable).FullName;
|
|
public static readonly string UnityColor_FullName = typeof(Color).FullName;
|
|
public static readonly string UnityColor32_FullName = typeof(Color32).FullName;
|
|
public static readonly string UnityVector2_FullName = typeof(Vector2).FullName;
|
|
public static readonly string UnityVector3_FullName = typeof(Vector3).FullName;
|
|
public static readonly string UnityVector4_FullName = typeof(Vector4).FullName;
|
|
public static readonly string UnityQuaternion_FullName = typeof(Quaternion).FullName;
|
|
public static readonly string UnityRay_FullName = typeof(Ray).FullName;
|
|
public static readonly string UnityRay2D_FullName = typeof(Ray2D).FullName;
|
|
|
|
public static uint Hash(this MethodDefinition methodDefinition)
|
|
{
|
|
var sigArr = Encoding.UTF8.GetBytes($"{methodDefinition.Module.Name} / {methodDefinition.FullName}");
|
|
var sigLen = sigArr.Length;
|
|
unsafe
|
|
{
|
|
fixed (byte* sigPtr = sigArr)
|
|
{
|
|
return XXHash.Hash32(sigPtr, sigLen);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool IsSubclassOf(this TypeDefinition typeDefinition, string classTypeFullName)
|
|
{
|
|
if (!typeDefinition.IsClass)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var baseTypeRef = typeDefinition.BaseType;
|
|
while (baseTypeRef != null)
|
|
{
|
|
if (baseTypeRef.FullName == classTypeFullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
try
|
|
{
|
|
baseTypeRef = baseTypeRef.Resolve().BaseType;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static bool HasInterface(this TypeReference typeReference, string interfaceTypeFullName)
|
|
{
|
|
if (typeReference.IsArray)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
var typeDef = typeReference.Resolve();
|
|
var typeFaces = typeDef.Interfaces;
|
|
return typeFaces.Any(iface => iface.InterfaceType.FullName == interfaceTypeFullName);
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool IsSerializable(this TypeReference typeReference)
|
|
{
|
|
var typeSystem = typeReference.Module.TypeSystem;
|
|
|
|
// C# primitives
|
|
if (typeReference == typeSystem.Boolean)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.Char)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.SByte)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.Byte)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.Int16)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.UInt16)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.Int32)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.UInt32)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.Int64)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.UInt64)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.Single)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.Double)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference == typeSystem.String)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Unity primitives
|
|
if (typeReference.FullName == UnityColor_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference.FullName == UnityColor32_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference.FullName == UnityVector2_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference.FullName == UnityVector3_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference.FullName == UnityVector4_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference.FullName == UnityQuaternion_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference.FullName == UnityRay_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (typeReference.FullName == UnityRay2D_FullName)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Enum
|
|
if (typeReference.GetEnumAsInt() != null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// INetworkSerializable
|
|
if (typeReference.HasInterface(INetworkSerializable_FullName))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Static array
|
|
if (typeReference.IsArray)
|
|
{
|
|
return typeReference.GetElementType().IsSerializable();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static TypeReference GetEnumAsInt(this TypeReference typeReference)
|
|
{
|
|
if (typeReference.IsArray)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
var typeDef = typeReference.Resolve();
|
|
return typeDef.IsEnum ? typeDef.GetEnumUnderlyingType() : null;
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static void AddError(this List<DiagnosticMessage> diagnostics, string message)
|
|
{
|
|
diagnostics.AddError((SequencePoint)null, message);
|
|
}
|
|
|
|
public static void AddError(this List<DiagnosticMessage> diagnostics, MethodDefinition methodDefinition, string message)
|
|
{
|
|
diagnostics.AddError(methodDefinition.DebugInformation.SequencePoints.FirstOrDefault(), message);
|
|
}
|
|
|
|
public static void AddError(this List<DiagnosticMessage> diagnostics, SequencePoint sequencePoint, string message)
|
|
{
|
|
diagnostics.Add(new DiagnosticMessage
|
|
{
|
|
DiagnosticType = DiagnosticType.Error,
|
|
File = sequencePoint?.Document.Url.Replace($"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}", ""),
|
|
Line = sequencePoint?.StartLine ?? 0,
|
|
Column = sequencePoint?.StartColumn ?? 0,
|
|
MessageData = $" - {message}"
|
|
});
|
|
}
|
|
|
|
public static void AddWarning(this List<DiagnosticMessage> diagnostics, string message)
|
|
{
|
|
diagnostics.AddWarning((SequencePoint)null, message);
|
|
}
|
|
|
|
public static void AddWarning(this List<DiagnosticMessage> diagnostics, MethodDefinition methodDefinition, string message)
|
|
{
|
|
diagnostics.AddWarning(methodDefinition.DebugInformation.SequencePoints.FirstOrDefault(), message);
|
|
}
|
|
|
|
public static void AddWarning(this List<DiagnosticMessage> diagnostics, SequencePoint sequencePoint, string message)
|
|
{
|
|
diagnostics.Add(new DiagnosticMessage
|
|
{
|
|
DiagnosticType = DiagnosticType.Warning,
|
|
File = sequencePoint?.Document.Url.Replace($"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}", ""),
|
|
Line = sequencePoint?.StartLine ?? 0,
|
|
Column = sequencePoint?.StartColumn ?? 0,
|
|
MessageData = $" - {message}"
|
|
});
|
|
}
|
|
|
|
public static void RemoveRecursiveReferences(this ModuleDefinition moduleDefinition)
|
|
{
|
|
// Weird behavior from Cecil: When importing a reference to a specific implementation of a generic
|
|
// method, it's importing the main module as a reference into itself. This causes Unity to have issues
|
|
// when attempting to iterate the assemblies to discover unit tests, as it goes into infinite recursion
|
|
// and eventually hits a stack overflow. I wasn't able to find any way to stop Cecil from importing the module
|
|
// into itself, so at the end of it all, we're just going to go back and remove it again.
|
|
var moduleName = moduleDefinition.Name;
|
|
if (moduleName.EndsWith(".dll") || moduleName.EndsWith(".exe"))
|
|
{
|
|
moduleName = moduleName.Substring(0, moduleName.Length - 4);
|
|
}
|
|
|
|
foreach (var reference in moduleDefinition.AssemblyReferences)
|
|
{
|
|
var referenceName = reference.Name.Split(',')[0];
|
|
if (referenceName.EndsWith(".dll") || referenceName.EndsWith(".exe"))
|
|
{
|
|
referenceName = referenceName.Substring(0, referenceName.Length - 4);
|
|
}
|
|
|
|
if (moduleName == referenceName)
|
|
{
|
|
try
|
|
{
|
|
moduleDefinition.AssemblyReferences.Remove(reference);
|
|
break;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
//
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static AssemblyDefinition AssemblyDefinitionFor(ICompiledAssembly compiledAssembly, out PostProcessorAssemblyResolver assemblyResolver)
|
|
{
|
|
assemblyResolver = new PostProcessorAssemblyResolver(compiledAssembly);
|
|
var readerParameters = new ReaderParameters
|
|
{
|
|
SymbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData),
|
|
SymbolReaderProvider = new PortablePdbReaderProvider(),
|
|
AssemblyResolver = assemblyResolver,
|
|
ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(),
|
|
ReadingMode = ReadingMode.Immediate
|
|
};
|
|
|
|
var assemblyDefinition = AssemblyDefinition.ReadAssembly(new MemoryStream(compiledAssembly.InMemoryAssembly.PeData), readerParameters);
|
|
|
|
//apparently, it will happen that when we ask to resolve a type that lives inside Unity.Netcode.Runtime, and we
|
|
//are also postprocessing Unity.Netcode.Runtime, type resolving will fail, because we do not actually try to resolve
|
|
//inside the assembly we are processing. Let's make sure we do that, so that we can use postprocessor features inside
|
|
//Unity.Netcode.Runtime itself as well.
|
|
assemblyResolver.AddAssemblyDefinitionBeingOperatedOn(assemblyDefinition);
|
|
|
|
return assemblyDefinition;
|
|
}
|
|
}
|
|
}
|