Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,196 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MLAPI.Messaging;
|
||||
using MLAPI.Serialization;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using Mono.Cecil.Rocks;
|
||||
using Unity.CompilationPipeline.Common.Diagnostics;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
using UnityEngine;
|
||||
|
||||
#if !UNITY_2019_4_OR_NEWER
|
||||
#error MLAPI requires Unity 2019.4 or newer
|
||||
#endif
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
internal static class CodeGenHelpers
|
||||
{
|
||||
public const string RuntimeAssemblyName = "Unity.Multiplayer.MLAPI.Runtime";
|
||||
|
||||
public static readonly string NetworkBehaviour_FullName = typeof(NetworkBehaviour).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 INetworkSerializable_NetworkSerialize_Name = nameof(INetworkSerializable.NetworkSerialize);
|
||||
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 AssemblyDefinition AssemblyDefinitionFor(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
var 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 MLAPI.Runtime, and we
|
||||
//are also postprocessing MLAPI.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
|
||||
//MLAPI.Runtime itself as well.
|
||||
assemblyResolver.AddAssemblyDefinitionBeingOperatedOn(assemblyDefinition);
|
||||
|
||||
return assemblyDefinition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0e5541b3bca0e43b48c2e694fffef5b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,42 @@
|
|||
#if !UNITY_2020_2_OR_NEWER
|
||||
using System.IO;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
internal class ILPostProcessCompiledAssembly : ICompiledAssembly
|
||||
{
|
||||
private readonly string m_AssemblyFilename;
|
||||
private readonly string m_OutputPath;
|
||||
private InMemoryAssembly m_InMemoryAssembly;
|
||||
|
||||
public ILPostProcessCompiledAssembly(string asmName, string[] refs, string[] defines, string outputPath)
|
||||
{
|
||||
m_AssemblyFilename = asmName;
|
||||
Name = Path.GetFileNameWithoutExtension(m_AssemblyFilename);
|
||||
References = refs;
|
||||
Defines = defines;
|
||||
m_OutputPath = outputPath;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string[] References { get; }
|
||||
public string[] Defines { get; }
|
||||
|
||||
public InMemoryAssembly InMemoryAssembly
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_InMemoryAssembly == null)
|
||||
{
|
||||
m_InMemoryAssembly = new InMemoryAssembly(
|
||||
File.ReadAllBytes(Path.Combine(m_OutputPath, m_AssemblyFilename)),
|
||||
File.ReadAllBytes(Path.Combine(m_OutputPath, $"{Path.GetFileNameWithoutExtension(m_AssemblyFilename)}.pdb")));
|
||||
}
|
||||
|
||||
return m_InMemoryAssembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c63d199856aa44f4581ec4de75bf3f44
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,13 @@
|
|||
#if !UNITY_2020_2_OR_NEWER
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
public abstract class ILPostProcessor
|
||||
{
|
||||
public abstract bool WillProcess(ICompiledAssembly compiledAssembly);
|
||||
public abstract ILPostProcessResult Process(ICompiledAssembly compiledAssembly);
|
||||
public abstract ILPostProcessor GetInstance();
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cbffd9b273517da4a9c4a3218771e0b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,239 @@
|
|||
#if !UNITY_2020_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Unity.CompilationPipeline.Common.Diagnostics;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Compilation;
|
||||
using UnityEngine;
|
||||
|
||||
using Assembly = System.Reflection.Assembly;
|
||||
|
||||
using ILPPInterface = Unity.CompilationPipeline.Common.ILPostProcessing.ILPostProcessor;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
// There is a behaviour difference between 2019.4 and 2020+ codegen
|
||||
// that essentially does checking on the existence of ILPP vs if a CodeGen assembly
|
||||
// is present. So in order to make sure ILPP runs properly in 2019.4 from a clean
|
||||
// import of the project we add this dummy ILPP which forces the callback to made
|
||||
// and meets the internal ScriptCompilation pipeline requirements
|
||||
internal sealed class ILPP2019CodegenWorkaround : ILPPInterface
|
||||
{
|
||||
public override ILPPInterface GetInstance()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool WillProcess(ICompiledAssembly compiledAssembly) => compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == CodeGenHelpers.RuntimeAssemblyName);
|
||||
|
||||
}
|
||||
|
||||
internal static class ILPostProcessProgram
|
||||
{
|
||||
private static ILPostProcessor[] s_ILPostProcessors { get; set; }
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void OnInitializeOnLoad()
|
||||
{
|
||||
CompilationPipeline.assemblyCompilationFinished += OnCompilationFinished;
|
||||
s_ILPostProcessors = FindAllPostProcessors();
|
||||
}
|
||||
|
||||
private static ILPostProcessor[] FindAllPostProcessors()
|
||||
{
|
||||
var typesDerivedFrom = TypeCache.GetTypesDerivedFrom<ILPostProcessor>();
|
||||
var localILPostProcessors = new List<ILPostProcessor>(typesDerivedFrom.Count);
|
||||
|
||||
foreach (var typeCollection in typesDerivedFrom)
|
||||
{
|
||||
try
|
||||
{
|
||||
localILPostProcessors.Add((ILPostProcessor)Activator.CreateInstance(typeCollection));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogError($"Could not create {nameof(ILPostProcessor)} ({typeCollection.FullName}):{Environment.NewLine}{exception.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
// Default sort by type full name
|
||||
localILPostProcessors.Sort((left, right) => string.Compare(left.GetType().FullName, right.GetType().FullName, StringComparison.Ordinal));
|
||||
|
||||
return localILPostProcessors.ToArray();
|
||||
}
|
||||
|
||||
private static void OnCompilationFinished(string targetAssembly, CompilerMessage[] messages)
|
||||
{
|
||||
if (messages.Length > 0)
|
||||
{
|
||||
if (messages.Any(msg => msg.type == CompilerMessageType.Error))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Should not run on the editor only assemblies
|
||||
if (targetAssembly.Contains("-Editor") || targetAssembly.Contains(".Editor"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Should not run on Unity Engine modules but we can run on the MLAPI Runtime DLL
|
||||
if ((targetAssembly.Contains("com.unity") || Path.GetFileName(targetAssembly).StartsWith("Unity")) && !targetAssembly.Contains("Unity.Multiplayer."))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.Log($"Running MLAPI ILPP on {targetAssembly}");
|
||||
|
||||
var outputDirectory = $"{Application.dataPath}/../{Path.GetDirectoryName(targetAssembly)}";
|
||||
var unityEngine = string.Empty;
|
||||
var mlapiRuntimeAssemblyPath = string.Empty;
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var usesMLAPI = false;
|
||||
var foundThisAssembly = false;
|
||||
|
||||
var depenencyPaths = new List<string>();
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
// Find the assembly currently being compiled from domain assembly list and check if it's using unet
|
||||
if (assembly.GetName().Name == Path.GetFileNameWithoutExtension(targetAssembly))
|
||||
{
|
||||
foundThisAssembly = true;
|
||||
foreach (var dependency in assembly.GetReferencedAssemblies())
|
||||
{
|
||||
// Since this assembly is already loaded in the domain this is a no-op and returns the
|
||||
// already loaded assembly
|
||||
depenencyPaths.Add(Assembly.Load(dependency).Location);
|
||||
if (dependency.Name.Contains(CodeGenHelpers.RuntimeAssemblyName))
|
||||
{
|
||||
usesMLAPI = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (assembly.Location.Contains("UnityEngine.CoreModule"))
|
||||
{
|
||||
unityEngine = assembly.Location;
|
||||
}
|
||||
|
||||
if (assembly.Location.Contains(CodeGenHelpers.RuntimeAssemblyName))
|
||||
{
|
||||
mlapiRuntimeAssemblyPath = assembly.Location;
|
||||
}
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
// in memory assembly, can't get location
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundThisAssembly)
|
||||
{
|
||||
// Target assembly not found in current domain, trying to load it to check references
|
||||
// will lead to trouble in the build pipeline, so lets assume it should go to weaver.
|
||||
// Add all assemblies in current domain to dependency list since there could be a
|
||||
// dependency lurking there (there might be generated assemblies so ignore file not found exceptions).
|
||||
// (can happen in runtime test framework on editor platform and when doing full library reimport)
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder))
|
||||
{
|
||||
depenencyPaths.Add(Assembly.Load(assembly.GetName().Name).Location);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
usesMLAPI = true;
|
||||
}
|
||||
|
||||
// We check if we are the MLAPI!
|
||||
if (!usesMLAPI)
|
||||
{
|
||||
// we shall also check and see if it we are ourself
|
||||
usesMLAPI = targetAssembly.Contains(CodeGenHelpers.RuntimeAssemblyName);
|
||||
}
|
||||
|
||||
if (!usesMLAPI)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(unityEngine))
|
||||
{
|
||||
Debug.LogError("Failed to find UnityEngine assembly");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(mlapiRuntimeAssemblyPath))
|
||||
{
|
||||
Debug.LogError("Failed to find mlapi runtime assembly");
|
||||
return;
|
||||
}
|
||||
|
||||
var assemblyPathName = Path.GetFileName(targetAssembly);
|
||||
|
||||
var targetCompiledAssembly = new ILPostProcessCompiledAssembly(assemblyPathName, depenencyPaths.ToArray(), null, outputDirectory);
|
||||
|
||||
void WriteAssembly(InMemoryAssembly inMemoryAssembly, string outputPath, string assName)
|
||||
{
|
||||
if (inMemoryAssembly == null)
|
||||
{
|
||||
throw new ArgumentException("InMemoryAssembly has never been accessed or modified");
|
||||
}
|
||||
|
||||
var asmPath = Path.Combine(outputPath, assName);
|
||||
var pdbFileName = $"{Path.GetFileNameWithoutExtension(assName)}.pdb";
|
||||
var pdbPath = Path.Combine(outputPath, pdbFileName);
|
||||
|
||||
File.WriteAllBytes(asmPath, inMemoryAssembly.PeData);
|
||||
File.WriteAllBytes(pdbPath, inMemoryAssembly.PdbData);
|
||||
}
|
||||
|
||||
foreach (var i in s_ILPostProcessors)
|
||||
{
|
||||
var result = i.Process(targetCompiledAssembly);
|
||||
if (result == null) continue;
|
||||
|
||||
if (result.Diagnostics.Count > 0)
|
||||
{
|
||||
Debug.LogError($"{nameof(ILPostProcessor)} - {i.GetType().Name} failed to run on {targetCompiledAssembly.Name}");
|
||||
|
||||
foreach (var message in result.Diagnostics)
|
||||
{
|
||||
switch (message.DiagnosticType)
|
||||
{
|
||||
case DiagnosticType.Error:
|
||||
Debug.LogError($"{nameof(ILPostProcessor)} Error - {message.MessageData} {message.File}:{message.Line}");
|
||||
break;
|
||||
case DiagnosticType.Warning:
|
||||
Debug.LogWarning($"{nameof(ILPostProcessor)} Warning - {message.MessageData} {message.File}:{message.Line}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// we now need to write out the result?
|
||||
WriteAssembly(result.InMemoryAssembly, outputDirectory, assemblyPathName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 72c7d2bd3d748db4d988e2204fe1083e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cf1c8b78182704372820a586c1c91d97
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,139 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Mono.Cecil;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
internal class PostProcessorAssemblyResolver : IAssemblyResolver
|
||||
{
|
||||
private readonly string[] m_AssemblyReferences;
|
||||
private readonly Dictionary<string, AssemblyDefinition> m_AssemblyCache = new Dictionary<string, AssemblyDefinition>();
|
||||
private readonly ICompiledAssembly m_CompiledAssembly;
|
||||
private AssemblyDefinition m_SelfAssembly;
|
||||
|
||||
public PostProcessorAssemblyResolver(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
m_CompiledAssembly = compiledAssembly;
|
||||
m_AssemblyReferences = compiledAssembly.References;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public AssemblyDefinition Resolve(AssemblyNameReference name) => Resolve(name, new ReaderParameters(ReadingMode.Deferred));
|
||||
|
||||
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
|
||||
{
|
||||
lock (m_AssemblyCache)
|
||||
{
|
||||
if (name.Name == m_CompiledAssembly.Name)
|
||||
{
|
||||
return m_SelfAssembly;
|
||||
}
|
||||
|
||||
var fileName = FindFile(name);
|
||||
if (fileName == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var lastWriteTime = File.GetLastWriteTime(fileName);
|
||||
var cacheKey = $"{fileName}{lastWriteTime}";
|
||||
if (m_AssemblyCache.TryGetValue(cacheKey, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
parameters.AssemblyResolver = this;
|
||||
|
||||
var ms = MemoryStreamFor(fileName);
|
||||
var pdb = $"{fileName}.pdb";
|
||||
if (File.Exists(pdb))
|
||||
{
|
||||
parameters.SymbolStream = MemoryStreamFor(pdb);
|
||||
}
|
||||
|
||||
var assemblyDefinition = AssemblyDefinition.ReadAssembly(ms, parameters);
|
||||
m_AssemblyCache.Add(cacheKey, assemblyDefinition);
|
||||
|
||||
return assemblyDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
private string FindFile(AssemblyNameReference name)
|
||||
{
|
||||
var fileName = m_AssemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == $"{name.Name}.dll");
|
||||
if (fileName != null)
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
// perhaps the type comes from an exe instead
|
||||
fileName = m_AssemblyReferences.FirstOrDefault(r => Path.GetFileName(r) == $"{name.Name}.exe");
|
||||
if (fileName != null)
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
//Unfortunately the current ICompiledAssembly API only provides direct references.
|
||||
//It is very much possible that a postprocessor ends up investigating a type in a directly
|
||||
//referenced assembly, that contains a field that is not in a directly referenced assembly.
|
||||
//if we don't do anything special for that situation, it will fail to resolve. We should fix this
|
||||
//in the ILPostProcessing API. As a workaround, we rely on the fact here that the indirect references
|
||||
//are always located next to direct references, so we search in all directories of direct references we
|
||||
//got passed, and if we find the file in there, we resolve to it.
|
||||
return m_AssemblyReferences
|
||||
.Select(Path.GetDirectoryName)
|
||||
.Distinct()
|
||||
.Select(parentDir => Path.Combine(parentDir, $"{name.Name}.dll"))
|
||||
.FirstOrDefault(File.Exists);
|
||||
}
|
||||
|
||||
private static MemoryStream MemoryStreamFor(string fileName)
|
||||
{
|
||||
return Retry(10, TimeSpan.FromSeconds(1), () =>
|
||||
{
|
||||
byte[] byteArray;
|
||||
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
byteArray = new byte[fs.Length];
|
||||
var readLength = fs.Read(byteArray, 0, (int)fs.Length);
|
||||
if (readLength != fs.Length)
|
||||
{
|
||||
throw new InvalidOperationException("File read length is not full length of file.");
|
||||
}
|
||||
}
|
||||
|
||||
return new MemoryStream(byteArray);
|
||||
});
|
||||
}
|
||||
|
||||
private static MemoryStream Retry(int retryCount, TimeSpan waitTime, Func<MemoryStream> func)
|
||||
{
|
||||
try
|
||||
{
|
||||
return func();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
if (retryCount == 0)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Caught IO Exception, trying {retryCount} more times");
|
||||
Thread.Sleep(waitTime);
|
||||
|
||||
return Retry(retryCount - 1, waitTime, func);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAssemblyDefinitionBeingOperatedOn(AssemblyDefinition assemblyDefinition)
|
||||
{
|
||||
m_SelfAssembly = assemblyDefinition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c247f4266b2864eb96e6a9ae6557d31
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,22 @@
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Mono.Cecil;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
internal class PostProcessorReflectionImporter : DefaultReflectionImporter
|
||||
{
|
||||
private const string k_SystemPrivateCoreLib = "System.Private.CoreLib";
|
||||
private readonly AssemblyNameReference m_CorrectCorlib;
|
||||
|
||||
public PostProcessorReflectionImporter(ModuleDefinition module) : base(module)
|
||||
{
|
||||
m_CorrectCorlib = module.AssemblyReferences.FirstOrDefault(a => a.Name == "mscorlib" || a.Name == "netstandard" || a.Name == k_SystemPrivateCoreLib);
|
||||
}
|
||||
|
||||
public override AssemblyNameReference ImportReference(AssemblyName reference)
|
||||
{
|
||||
return m_CorrectCorlib != null && reference.Name == k_SystemPrivateCoreLib ? m_CorrectCorlib : base.ImportReference(reference);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 484e8ad8c4dde382ea67036b32935ef1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,12 @@
|
|||
using Mono.Cecil;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
internal class PostProcessorReflectionImporterProvider : IReflectionImporterProvider
|
||||
{
|
||||
public IReflectionImporter GetReflectionImporter(ModuleDefinition moduleDefinition)
|
||||
{
|
||||
return new PostProcessorReflectionImporter(moduleDefinition);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f9273a5dad109ab0783891e36c983080
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,118 @@
|
|||
#if UNITY_2020_2_OR_NEWER
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using Unity.CompilationPipeline.Common.Diagnostics;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
using ILPPInterface = Unity.CompilationPipeline.Common.ILPostProcessing.ILPostProcessor;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
internal sealed class RuntimeAccessModifiersILPP : ILPPInterface
|
||||
{
|
||||
public override ILPPInterface GetInstance() => this;
|
||||
|
||||
public override bool WillProcess(ICompiledAssembly compiledAssembly) => compiledAssembly.Name == CodeGenHelpers.RuntimeAssemblyName;
|
||||
|
||||
private readonly List<DiagnosticMessage> m_Diagnostics = new List<DiagnosticMessage>();
|
||||
|
||||
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
if (!WillProcess(compiledAssembly)) return null;
|
||||
m_Diagnostics.Clear();
|
||||
|
||||
// read
|
||||
var assemblyDefinition = CodeGenHelpers.AssemblyDefinitionFor(compiledAssembly);
|
||||
if (assemblyDefinition == null)
|
||||
{
|
||||
m_Diagnostics.AddError($"Cannot read MLAPI Runtime assembly definition: {compiledAssembly.Name}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// process
|
||||
var mainModule = assemblyDefinition.MainModule;
|
||||
if (mainModule != null)
|
||||
{
|
||||
foreach (var typeDefinition in mainModule.Types)
|
||||
{
|
||||
if (!typeDefinition.IsClass) continue;
|
||||
|
||||
switch (typeDefinition.Name)
|
||||
{
|
||||
case nameof(NetworkManager):
|
||||
ProcessNetworkManager(typeDefinition);
|
||||
break;
|
||||
case nameof(NetworkBehaviour):
|
||||
ProcessNetworkBehaviour(typeDefinition);
|
||||
break;
|
||||
case nameof(Messaging.__RpcParams):
|
||||
typeDefinition.IsPublic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else m_Diagnostics.AddError($"Cannot get main module from MLAPI Runtime assembly definition: {compiledAssembly.Name}");
|
||||
|
||||
// write
|
||||
var pe = new MemoryStream();
|
||||
var pdb = new MemoryStream();
|
||||
|
||||
var writerParameters = new WriterParameters
|
||||
{
|
||||
SymbolWriterProvider = new PortablePdbWriterProvider(),
|
||||
SymbolStream = pdb,
|
||||
WriteSymbols = true
|
||||
};
|
||||
|
||||
assemblyDefinition.Write(pe, writerParameters);
|
||||
|
||||
return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), m_Diagnostics);
|
||||
}
|
||||
|
||||
private void ProcessNetworkManager(TypeDefinition typeDefinition)
|
||||
{
|
||||
foreach (var fieldDefinition in typeDefinition.Fields)
|
||||
{
|
||||
if (fieldDefinition.Name == nameof(NetworkManager.__ntable))
|
||||
{
|
||||
fieldDefinition.IsPublic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessNetworkBehaviour(TypeDefinition typeDefinition)
|
||||
{
|
||||
foreach (var nestedType in typeDefinition.NestedTypes)
|
||||
{
|
||||
if (nestedType.Name == nameof(NetworkBehaviour.__NExec))
|
||||
{
|
||||
nestedType.IsNestedFamily = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var fieldDefinition in typeDefinition.Fields)
|
||||
{
|
||||
if (fieldDefinition.Name == nameof(NetworkBehaviour.__nexec))
|
||||
{
|
||||
fieldDefinition.IsFamily = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var methodDefinition in typeDefinition.Methods)
|
||||
{
|
||||
switch (methodDefinition.Name)
|
||||
{
|
||||
case nameof(NetworkBehaviour.__beginSendServerRpc):
|
||||
case nameof(NetworkBehaviour.__endSendServerRpc):
|
||||
case nameof(NetworkBehaviour.__beginSendClientRpc):
|
||||
case nameof(NetworkBehaviour.__endSendClientRpc):
|
||||
methodDefinition.IsFamily = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c9f2f4b03d774432be69d4c2f53bd2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "Unity.Multiplayer.MLAPI.Editor.CodeGen",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.Multiplayer.MLAPI.Runtime"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"Mono.Cecil.dll",
|
||||
"Mono.Cecil.Mdb.dll",
|
||||
"Mono.Cecil.Pdb.dll",
|
||||
"Mono.Cecil.Rocks.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fe4fa159f4a96442ba22af67ddf20c65
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c61e8fe9a68a486fbbc3128d233ded2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015, 2016 Sedat Kapanoglu
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cf89ecbf6f9954c8ea6d0848b1e79d87
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,291 @@
|
|||
// <copyright file="XXHash.cs" company="Sedat Kapanoglu">
|
||||
// Copyright (c) 2015-2019 Sedat Kapanoglu
|
||||
// MIT License (see LICENSE file for details)
|
||||
// </copyright>
|
||||
|
||||
// @mfatihmar (Unity): Modified for Unity support
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MLAPI.Editor.CodeGen
|
||||
{
|
||||
/// <summary>
|
||||
/// XXHash implementation.
|
||||
/// </summary>
|
||||
internal static class XXHash
|
||||
{
|
||||
private const ulong k_Prime64v1 = 11400714785074694791ul;
|
||||
private const ulong k_Prime64v2 = 14029467366897019727ul;
|
||||
private const ulong k_Prime64v3 = 1609587929392839161ul;
|
||||
private const ulong k_Prime64v4 = 9650029242287828579ul;
|
||||
private const ulong k_Prime64v5 = 2870177450012600261ul;
|
||||
|
||||
private const uint k_Prime32v1 = 2654435761u;
|
||||
private const uint k_Prime32v2 = 2246822519u;
|
||||
private const uint k_Prime32v3 = 3266489917u;
|
||||
private const uint k_Prime32v4 = 668265263u;
|
||||
private const uint k_Prime32v5 = 374761393u;
|
||||
|
||||
/// <summary>
|
||||
/// Generate a 32-bit xxHash value.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Input buffer.</param>
|
||||
/// <param name="bufferLength">Input buffer length.</param>
|
||||
/// <param name="seed">Optional seed.</param>
|
||||
/// <returns>32-bit hash value.</returns>
|
||||
public static unsafe uint Hash32(byte* buffer, int bufferLength, uint seed = 0)
|
||||
{
|
||||
const int stripeLength = 16;
|
||||
|
||||
int len = bufferLength;
|
||||
int remainingLen = len;
|
||||
uint acc;
|
||||
|
||||
byte* pInput = buffer;
|
||||
if (len >= stripeLength)
|
||||
{
|
||||
uint acc1 = seed + k_Prime32v1 + k_Prime32v2;
|
||||
uint acc2 = seed + k_Prime32v2;
|
||||
uint acc3 = seed;
|
||||
uint acc4 = seed - k_Prime32v1;
|
||||
|
||||
do
|
||||
{
|
||||
acc = processStripe32(ref pInput, ref acc1, ref acc2, ref acc3, ref acc4);
|
||||
remainingLen -= stripeLength;
|
||||
} while (remainingLen >= stripeLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
acc = seed + k_Prime32v5;
|
||||
}
|
||||
|
||||
acc += (uint)len;
|
||||
acc = processRemaining32(pInput, acc, remainingLen);
|
||||
|
||||
return avalanche32(acc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a 64-bit xxHash value.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Input buffer.</param>
|
||||
/// <param name="bufferLength">Input buffer length.</param>
|
||||
/// <param name="seed">Optional seed.</param>
|
||||
/// <returns>Computed 64-bit hash value.</returns>
|
||||
public static unsafe ulong Hash64(byte* buffer, int bufferLength, ulong seed = 0)
|
||||
{
|
||||
const int stripeLength = 32;
|
||||
|
||||
int len = bufferLength;
|
||||
int remainingLen = len;
|
||||
ulong acc;
|
||||
|
||||
byte* pInput = buffer;
|
||||
if (len >= stripeLength)
|
||||
{
|
||||
ulong acc1 = seed + k_Prime64v1 + k_Prime64v2;
|
||||
ulong acc2 = seed + k_Prime64v2;
|
||||
ulong acc3 = seed;
|
||||
ulong acc4 = seed - k_Prime64v1;
|
||||
|
||||
do
|
||||
{
|
||||
acc = processStripe64(ref pInput, ref acc1, ref acc2, ref acc3, ref acc4);
|
||||
remainingLen -= stripeLength;
|
||||
} while (remainingLen >= stripeLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
acc = seed + k_Prime64v5;
|
||||
}
|
||||
|
||||
acc += (ulong)len;
|
||||
acc = processRemaining64(pInput, acc, remainingLen);
|
||||
|
||||
|
||||
return avalanche64(acc);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong processStripe64(
|
||||
ref byte* pInput,
|
||||
ref ulong acc1,
|
||||
ref ulong acc2,
|
||||
ref ulong acc3,
|
||||
ref ulong acc4)
|
||||
{
|
||||
processLane64(ref acc1, ref pInput);
|
||||
processLane64(ref acc2, ref pInput);
|
||||
processLane64(ref acc3, ref pInput);
|
||||
processLane64(ref acc4, ref pInput);
|
||||
|
||||
ulong acc = Bits.RotateLeft(acc1, 1)
|
||||
+ Bits.RotateLeft(acc2, 7)
|
||||
+ Bits.RotateLeft(acc3, 12)
|
||||
+ Bits.RotateLeft(acc4, 18);
|
||||
|
||||
mergeAccumulator64(ref acc, acc1);
|
||||
mergeAccumulator64(ref acc, acc2);
|
||||
mergeAccumulator64(ref acc, acc3);
|
||||
mergeAccumulator64(ref acc, acc4);
|
||||
return acc;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe void processLane64(ref ulong accn, ref byte* pInput)
|
||||
{
|
||||
ulong lane = *(ulong*)pInput;
|
||||
accn = round64(accn, lane);
|
||||
pInput += 8;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong processRemaining64(
|
||||
byte* pInput,
|
||||
ulong acc,
|
||||
int remainingLen)
|
||||
{
|
||||
for (ulong lane; remainingLen >= 8; remainingLen -= 8, pInput += 8)
|
||||
{
|
||||
lane = *(ulong*)pInput;
|
||||
|
||||
acc ^= round64(0, lane);
|
||||
acc = Bits.RotateLeft(acc, 27) * k_Prime64v1;
|
||||
acc += k_Prime64v4;
|
||||
}
|
||||
|
||||
for (uint lane32; remainingLen >= 4; remainingLen -= 4, pInput += 4)
|
||||
{
|
||||
lane32 = *(uint*)pInput;
|
||||
|
||||
acc ^= lane32 * k_Prime64v1;
|
||||
acc = Bits.RotateLeft(acc, 23) * k_Prime64v2;
|
||||
acc += k_Prime64v3;
|
||||
}
|
||||
|
||||
for (byte lane8; remainingLen >= 1; remainingLen--, pInput++)
|
||||
{
|
||||
lane8 = *pInput;
|
||||
acc ^= lane8 * k_Prime64v5;
|
||||
acc = Bits.RotateLeft(acc, 11) * k_Prime64v1;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong avalanche64(ulong acc)
|
||||
{
|
||||
acc ^= acc >> 33;
|
||||
acc *= k_Prime64v2;
|
||||
acc ^= acc >> 29;
|
||||
acc *= k_Prime64v3;
|
||||
acc ^= acc >> 32;
|
||||
return acc;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong round64(ulong accn, ulong lane)
|
||||
{
|
||||
accn += lane * k_Prime64v2;
|
||||
return Bits.RotateLeft(accn, 31) * k_Prime64v1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void mergeAccumulator64(ref ulong acc, ulong accn)
|
||||
{
|
||||
acc ^= round64(0, accn);
|
||||
acc *= k_Prime64v1;
|
||||
acc += k_Prime64v4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe uint processStripe32(
|
||||
ref byte* pInput,
|
||||
ref uint acc1,
|
||||
ref uint acc2,
|
||||
ref uint acc3,
|
||||
ref uint acc4)
|
||||
{
|
||||
processLane32(ref pInput, ref acc1);
|
||||
processLane32(ref pInput, ref acc2);
|
||||
processLane32(ref pInput, ref acc3);
|
||||
processLane32(ref pInput, ref acc4);
|
||||
|
||||
return Bits.RotateLeft(acc1, 1)
|
||||
+ Bits.RotateLeft(acc2, 7)
|
||||
+ Bits.RotateLeft(acc3, 12)
|
||||
+ Bits.RotateLeft(acc4, 18);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe void processLane32(ref byte* pInput, ref uint accn)
|
||||
{
|
||||
uint lane = *(uint*)pInput;
|
||||
accn = round32(accn, lane);
|
||||
pInput += 4;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe uint processRemaining32(
|
||||
byte* pInput,
|
||||
uint acc,
|
||||
int remainingLen)
|
||||
{
|
||||
for (uint lane; remainingLen >= 4; remainingLen -= 4, pInput += 4)
|
||||
{
|
||||
lane = *(uint*)pInput;
|
||||
acc += lane * k_Prime32v3;
|
||||
acc = Bits.RotateLeft(acc, 17) * k_Prime32v4;
|
||||
}
|
||||
|
||||
for (byte lane; remainingLen >= 1; remainingLen--, pInput++)
|
||||
{
|
||||
lane = *pInput;
|
||||
acc += lane * k_Prime32v5;
|
||||
acc = Bits.RotateLeft(acc, 11) * k_Prime32v1;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint round32(uint accn, uint lane)
|
||||
{
|
||||
accn += lane * k_Prime32v2;
|
||||
accn = Bits.RotateLeft(accn, 13);
|
||||
accn *= k_Prime32v1;
|
||||
return accn;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint avalanche32(uint acc)
|
||||
{
|
||||
acc ^= acc >> 15;
|
||||
acc *= k_Prime32v2;
|
||||
acc ^= acc >> 13;
|
||||
acc *= k_Prime32v3;
|
||||
acc ^= acc >> 16;
|
||||
return acc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bit operations.
|
||||
/// </summary>
|
||||
private static class Bits
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static ulong RotateLeft(ulong value, int bits)
|
||||
{
|
||||
return (value << bits) | (value >> (64 - bits));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static uint RotateLeft(uint value, int bits)
|
||||
{
|
||||
return (value << bits) | (value >> (32 - bits));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b5aa7a49e9e694f148d810d34577546b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue