diff --git a/Assets/DefaultPrefabObjects.asset b/Assets/DefaultPrefabObjects.asset
new file mode 100644
index 0000000..27e5f59
--- /dev/null
+++ b/Assets/DefaultPrefabObjects.asset
@@ -0,0 +1,22 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 3ad70174b079c2f4ebc7931d3dd1af6f, type: 3}
+ m_Name: DefaultPrefabObjects
+ m_EditorClassIdentifier:
+ _prefabs:
+ - {fileID: 4512293259955182956, guid: 300370bdf7819da41937e0beac65b32c, type: 3}
+ - {fileID: 611616139817875448, guid: bf5f023b4017a5e41a9815ec5745df3d, type: 3}
+ - {fileID: 9117857247562382210, guid: b2991431a5f893e49937d01b6da44ff8, type: 3}
+ - {fileID: 3624261834906416601, guid: e3f599c0ac723194a92f51c91ec73267, type: 3}
+ - {fileID: 3624261834906416601, guid: 4e1673ccc2acac543871855a0e8bed71, type: 3}
+ - {fileID: 201277550, guid: d904f93bc171bb144ba33c5155282f6f, type: 3}
+ - {fileID: 27039729695437543, guid: f820efff6a2871447b961fc755212ba3, type: 3}
diff --git a/Assets/DefaultPrefabObjects.asset.meta b/Assets/DefaultPrefabObjects.asset.meta
new file mode 100644
index 0000000..56c01ef
--- /dev/null
+++ b/Assets/DefaultPrefabObjects.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e6b71f999cc8fc647a3f73f7088802e0
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet.meta b/Assets/FishNet.meta
new file mode 100644
index 0000000..970e7b9
--- /dev/null
+++ b/Assets/FishNet.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1c10e8242689baa4795de57f9ef42ec3
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating.meta b/Assets/FishNet/CodeGenerating.meta
new file mode 100644
index 0000000..0da94fd
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: bbb4974b4302f435b9f4663c64d8f803
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Extension.meta b/Assets/FishNet/CodeGenerating/Extension.meta
new file mode 100644
index 0000000..fd3a139
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 206db668838ebc34b90ae36be24ce3be
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Extension/ILProcessorExtensions.cs b/Assets/FishNet/CodeGenerating/Extension/ILProcessorExtensions.cs
new file mode 100644
index 0000000..7e1c18a
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/ILProcessorExtensions.cs
@@ -0,0 +1,20 @@
+using FishNet.CodeGenerating.Helping.Extension;
+using MonoFN.Cecil.Cil;
+
+namespace FishNet.CodeGenerating.Extension
+{
+
+
+ internal static class ILProcessorExtensions
+ {
+ ///
+ /// Creates a variable type within the body and returns it's VariableDef.
+ ///
+ internal static VariableDefinition CreateVariable(this ILProcessor processor, CodegenSession session, System.Type variableType)
+ {
+ return processor.Body.Method.CreateVariable(session, variableType);
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Extension/ILProcessorExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Extension/ILProcessorExtensions.cs.meta
new file mode 100644
index 0000000..01e9737
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/ILProcessorExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 127d8312da53b3e49ba9e3e4c6348857
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Extension/MethodDefinitionExtensions.cs b/Assets/FishNet/CodeGenerating/Extension/MethodDefinitionExtensions.cs
new file mode 100644
index 0000000..1d42d6d
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/MethodDefinitionExtensions.cs
@@ -0,0 +1,131 @@
+using FishNet.CodeGenerating.Helping.Extension;
+using MonoFN.Cecil;
+using MonoFN.Cecil.Rocks;
+using MonoFN.Collections.Generic;
+using System.Collections.Generic;
+
+namespace FishNet.CodeGenerating.Extension
+{
+
+
+ internal static class MethodDefinitionExtensions
+ {
+ ///
+ /// Returns the proper OpCode to use for call methods.
+ ///
+ public static MonoFN.Cecil.Cil.OpCode GetCallOpCode(this MethodDefinition md)
+ {
+ if (md.Attributes.HasFlag(MethodAttributes.Virtual))
+ return MonoFN.Cecil.Cil.OpCodes.Callvirt;
+ else
+ return MonoFN.Cecil.Cil.OpCodes.Call;
+ }
+ ///
+ /// Returns the proper OpCode to use for call methods.
+ ///
+ public static MonoFN.Cecil.Cil.OpCode GetCallOpCode(this MethodReference mr, CodegenSession session)
+ {
+ return mr.CachedResolve(session).GetCallOpCode();
+ }
+
+ ///
+ /// Adds otherMd parameters to thisMR and returns added parameters.
+ ///
+ public static List CreateParameters(this MethodReference thisMr, CodegenSession session, MethodDefinition otherMd)
+ {
+ return thisMr.CachedResolve(session).CreateParameters(session, otherMd);
+ }
+ ///
+ /// Adds otherMr parameters to thisMR and returns added parameters.
+ ///
+ public static List CreateParameters(this MethodReference thisMr, CodegenSession session, MethodReference otherMr)
+ {
+ return thisMr.CachedResolve(session).CreateParameters(session, otherMr.CachedResolve(session));
+ }
+
+ ///
+ /// Adds otherMd parameters to thisMd and returns added parameters.
+ ///
+ public static List CreateParameters(this MethodDefinition thisMd, CodegenSession session, MethodDefinition otherMd)
+ {
+ List results = new List();
+
+ foreach (ParameterDefinition pd in otherMd.Parameters)
+ {
+ session.ImportReference(pd.ParameterType);
+ int currentCount = thisMd.Parameters.Count;
+ string name = (pd.Name + currentCount);
+ ParameterDefinition parameterDef = new ParameterDefinition(name, pd.Attributes, pd.ParameterType);
+ //Set any default values.
+ parameterDef.Constant = pd.Constant;
+ parameterDef.IsReturnValue = pd.IsReturnValue;
+ parameterDef.IsOut = pd.IsOut;
+ foreach (CustomAttribute item in pd.CustomAttributes)
+ parameterDef.CustomAttributes.Add(item);
+ parameterDef.HasConstant = pd.HasConstant;
+ parameterDef.HasDefault = pd.HasDefault;
+
+ thisMd.Parameters.Add(parameterDef);
+
+ results.Add(parameterDef);
+ }
+
+ return results;
+ }
+
+ ///
+ /// Returns a method reference while considering if declaring type is generic.
+ ///
+ public static MethodReference GetMethodReference(this MethodDefinition md, CodegenSession session)
+ {
+ MethodReference methodRef = session.ImportReference(md);
+
+ //Is generic.
+ if (md.DeclaringType.HasGenericParameters)
+ {
+ GenericInstanceType git = methodRef.DeclaringType.MakeGenericInstanceType();
+ MethodReference result = new MethodReference(md.Name, md.ReturnType)
+ {
+ HasThis = md.HasThis,
+ ExplicitThis = md.ExplicitThis,
+ DeclaringType = git,
+ CallingConvention = md.CallingConvention,
+ };
+ foreach (ParameterDefinition pd in md.Parameters)
+ {
+ session.ImportReference(pd.ParameterType);
+ result.Parameters.Add(pd);
+ }
+ return result;
+ }
+ else
+ {
+ return methodRef;
+ }
+ }
+
+
+ ///
+ /// Returns a method reference for a generic method.
+ ///
+ public static MethodReference GetMethodReference(this MethodDefinition md, CodegenSession session, TypeReference typeReference)
+ {
+ MethodReference methodRef = session.ImportReference(md);
+ return methodRef.GetMethodReference(session, typeReference);
+ }
+
+
+ ///
+ /// Returns a method reference for a generic method.
+ ///
+ public static MethodReference GetMethodReference(this MethodDefinition md, CodegenSession session, TypeReference[] typeReferences)
+ {
+ MethodReference methodRef = session.ImportReference(md);
+ return methodRef.GetMethodReference(session, typeReferences);
+ }
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Extension/MethodDefinitionExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Extension/MethodDefinitionExtensions.cs.meta
new file mode 100644
index 0000000..784e564
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/MethodDefinitionExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 866ed457fe28c3e4b9698d87b9abd709
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs b/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs
new file mode 100644
index 0000000..6c11c26
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs
@@ -0,0 +1,254 @@
+using FishNet.CodeGenerating.Helping.Extension;
+using MonoFN.Cecil;
+
+namespace FishNet.CodeGenerating.Extension
+{
+
+
+ internal static class TypeDefinitionExtensions
+ {
+
+
+ ///
+ /// Returns if a TypeDefinition is nullable.
+ ///
+ public static bool IsNullable(this TypeDefinition td)
+ {
+ return (td.Name == typeof(System.Nullable<>).Name);
+ }
+
+
+ public static MethodReference GetMethodReferenceInBase(this TypeDefinition td, CodegenSession session, string methodName)
+ {
+ MethodDefinition baseMd = td.GetMethodDefinitionInBase(session, methodName);
+ if (baseMd == null)
+ return null;
+
+
+ MethodReference baseMr;
+ TypeReference baseTr = td.BaseType;
+ if (baseTr.CachedResolve(session).HasGenericParameters)
+ {
+ GenericInstanceType git = (GenericInstanceType)baseTr;
+ baseMr = new MethodReference(baseMd.Name, baseMd.ReturnType, git)
+ {
+ HasThis = baseMd.HasThis,
+ CallingConvention = baseMd.CallingConvention,
+ ExplicitThis = baseMd.ExplicitThis,
+ };
+ foreach (ParameterDefinition pd in baseMd.Parameters)
+ {
+ session.ImportReference(pd.ParameterType);
+ baseMr.Parameters.Add(pd);
+ }
+ }
+ else
+ {
+ baseMr = session.ImportReference(baseMd);
+ }
+
+ return baseMr;
+ }
+ ///
+ /// Returns a method in the next base class.
+ ///
+ public static MethodDefinition GetMethodDefinitionInBase(this TypeDefinition td, CodegenSession session, string methodName)
+ {
+ if (td.BaseType == null)
+ {
+ session.LogError($"BaseType for {td.FullName} is null.");
+ return null;
+ }
+
+ TypeDefinition baseTd = td.BaseType.CachedResolve(session);
+ return baseTd.GetMethod(methodName);
+ }
+
+
+ ///
+ /// Returns a method in the next base class.
+ ///
+ public static MethodReference GetMethodReference(this TypeDefinition td, CodegenSession session, string methodName)
+ {
+ MethodDefinition md = td.GetMethod(methodName);
+ //Not found.
+ if (md == null)
+ return null;
+
+ return md.GetMethodReference(session);
+ }
+
+ ///
+ /// Gets a MethodReference or creates one if missing.
+ ///
+ public static MethodReference GetOrCreateMethodReference(this TypeDefinition td, CodegenSession session, string methodName, MethodAttributes attributes, TypeReference returnType, out bool created)
+ {
+ MethodDefinition md = td.GetMethod(methodName);
+ //Not found.
+ if (md == null)
+ {
+ md = new MethodDefinition(methodName, attributes, returnType);
+ td.Methods.Add(md);
+ created = true;
+ }
+ else
+ {
+ created = false;
+ }
+
+ return md.GetMethodReference(session);
+ }
+
+
+ ///
+ /// Gets a MethodDefinition or creates one if missing.
+ ///
+ public static MethodDefinition GetOrCreateMethodDefinition(this TypeDefinition td, CodegenSession session, string methodName, MethodAttributes attributes, TypeReference returnType, out bool created)
+ {
+ MethodDefinition md = td.GetMethod(methodName);
+ //Not found.
+ if (md == null)
+ {
+ md = new MethodDefinition(methodName, attributes, returnType);
+ td.Methods.Add(md);
+ created = true;
+ }
+ else
+ {
+ created = false;
+ }
+
+ return md;
+ }
+
+ ///
+ /// Gets a MethodDefinition or creates one if missing.
+ ///
+ public static MethodDefinition GetOrCreateMethodDefinition(this TypeDefinition td, CodegenSession session, string methodName, MethodDefinition methodTemplate, bool copyParameters, out bool created)
+ {
+ MethodDefinition md = td.GetMethod(methodName);
+ //Not found.
+ if (md == null)
+ {
+ TypeReference returnType = session.ImportReference(methodTemplate.ReturnType);
+ md = new MethodDefinition(methodName, methodTemplate.Attributes, returnType)
+ {
+ ExplicitThis = methodTemplate.ExplicitThis,
+ AggressiveInlining = methodTemplate.AggressiveInlining,
+ Attributes = methodTemplate.Attributes,
+ CallingConvention = methodTemplate.CallingConvention,
+ HasThis = methodTemplate.HasThis,
+ };
+ md.Body.InitLocals = methodTemplate.Body.InitLocals;
+
+ if (copyParameters)
+ {
+ foreach (ParameterDefinition pd in methodTemplate.Parameters)
+ md.Parameters.Add(pd);
+ }
+
+ td.Methods.Add(md);
+ created = true;
+ }
+ else
+ {
+ created = false;
+ }
+
+ return md;
+ }
+
+
+
+ ///
+ /// Returns a method in any inherited classes. The first found method is returned.
+ ///
+ public static MethodDefinition GetMethodDefinitionInAnyBase(this TypeDefinition td, CodegenSession session, string methodName)
+ {
+ while (td != null)
+ {
+ foreach (MethodDefinition md in td.Methods)
+ {
+ if (md.Name == methodName)
+ return md;
+ }
+
+ try
+ {
+ td = td.GetNextBaseTypeDefinition(session);
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Returns the next base type.
+ ///
+ public static TypeDefinition GetNextBaseTypeDefinition(this TypeDefinition typeDef, CodegenSession session)
+ {
+ return (typeDef.BaseType == null) ? null : typeDef.BaseType.CachedResolve(session);
+ }
+
+ ///
+ /// Creates a FieldReference.
+ ///
+ public static FieldReference CreateFieldReference(this FieldDefinition fd, CodegenSession session)
+ {
+ FieldReference fr;
+ TypeDefinition declaringType = fd.DeclaringType;
+ //Is generic.
+ if (declaringType.HasGenericParameters)
+ {
+ GenericInstanceType git = new GenericInstanceType(declaringType);
+ foreach (GenericParameter item in declaringType.GenericParameters)
+ git.GenericArguments.Add(item);
+ fr = new FieldReference(fd.Name, fd.FieldType, git);
+ return fr;
+ }
+ //Not generic.
+ else
+ {
+ return session.ImportReference(fd);
+ }
+ }
+
+ ///
+ /// Gets a FieldReference or creates it if missing.
+ ///
+ public static FieldReference GetOrCreateFieldReference(this TypeDefinition td, CodegenSession session, string fieldName, FieldAttributes attributes, TypeReference fieldTypeRef, out bool created)
+ {
+ FieldReference fr = td.GetFieldReference(fieldName, session);
+ if (fr == null)
+ {
+ fr = td.CreateFieldDefinition(session, fieldName, attributes, fieldTypeRef);
+ created = true;
+ }
+ else
+ {
+ created = false;
+ }
+
+ return fr;
+ }
+
+ ///
+ /// Creates a FieldReference.
+ ///
+ public static FieldReference CreateFieldDefinition(this TypeDefinition td, CodegenSession session, string fieldName, FieldAttributes attributes, TypeReference fieldTypeRef)
+ {
+ FieldDefinition fd = new FieldDefinition(fieldName, attributes, fieldTypeRef);
+ td.Fields.Add(fd);
+ return fd.CreateFieldReference(session);
+ }
+
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs.meta
new file mode 100644
index 0000000..dfb8256
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/TypeDefinitionExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c9f00cf3dc8b90b469c3c9cb8b87fc88
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs b/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs
new file mode 100644
index 0000000..35ab37f
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs
@@ -0,0 +1,59 @@
+
+using FishNet.CodeGenerating.Helping;
+using FishNet.CodeGenerating.Helping.Extension;
+using MonoFN.Cecil;
+using UnityEngine;
+
+namespace FishNet.CodeGenerating.Extension
+{
+
+
+ internal static class TypeReferenceExtensions
+ {
+
+ ///
+ /// Returns if a TypeReference is nullable.
+ ///
+ public static bool IsNullable(this TypeReference tr, CodegenSession session)
+ {
+ TypeDefinition td = tr.CachedResolve(session);
+ return td.IsNullable();
+ }
+
+ ///
+ /// Returns the fullname of a TypeReference without <>.
+ ///
+ ///
+ ///
+ public static string GetFullnameWithoutBrackets(this TypeReference tr)
+ {
+ string str = tr.FullName;
+ str = str.Replace("<", "");
+ str = str.Replace(">", "");
+ return str;
+ }
+
+ ///
+ /// Returns a method in the next base class.
+ ///
+ public static MethodReference GetMethodInBase(this TypeReference tr, CodegenSession session, string methodName)
+ {
+ return tr.CachedResolve(session).GetMethodInBase(session, methodName);
+ }
+
+ ///
+ /// Makes a GenericInstanceType.
+ ///
+ public static GenericInstanceType MakeGenericInstanceType(this TypeReference self)
+ {
+ GenericInstanceType instance = new GenericInstanceType(self);
+ foreach (GenericParameter argument in self.GenericParameters)
+ instance.GenericArguments.Add(argument);
+
+ return instance;
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs.meta
new file mode 100644
index 0000000..19d7526
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Extension/TypeReferenceExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 239b1b10db80c594d93b7ba4ee2c1ec5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/FN_README.txt b/Assets/FishNet/CodeGenerating/FN_README.txt
new file mode 100644
index 0000000..3efe3cf
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/FN_README.txt
@@ -0,0 +1,9 @@
+After updating a custom Cecil to fix conflict with Unity.Burst in 2021 perform the following:
+
+- Open cecil in it's own project; eg: do not place directly in FN.
+- Rename namespace.Mono to namespace.MonoFN.
+- Current project rename strings, "Mono to "MonoFN
+- Replace current project #if INSIDE_ROCKS to #if UNITY_EDITOR
+- Comment out `[assembly: AssemblyTitle ("MonoFN.Cecil.Rocks")]` within rocks\Mono.Cecil.Rocks\AssemblyInfo.cs.
+- Delete obj/bin/tests folders.
+- Copy into FN project.
diff --git a/Assets/FishNet/CodeGenerating/FN_README.txt.meta b/Assets/FishNet/CodeGenerating/FN_README.txt.meta
new file mode 100644
index 0000000..04e8428
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/FN_README.txt.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9133eb285bd7f3c4f89f4d7a2a079c6b
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers.meta b/Assets/FishNet/CodeGenerating/Helpers.meta
new file mode 100644
index 0000000..0dc1ce9
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: efeca2428bd9fe64d872a626b93ff0cf
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs b/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs
new file mode 100644
index 0000000..15b6c4f
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs
@@ -0,0 +1,94 @@
+using FishNet.CodeGenerating.Helping.Extension;
+using FishNet.Object;
+using FishNet.Object.Helping;
+using FishNet.Object.Prediction;
+using FishNet.Object.Synchronizing;
+using MonoFN.Cecil;
+
+
+namespace FishNet.CodeGenerating.Helping
+{
+ internal class AttributeHelper : CodegenBase
+ {
+ #region Reflection references.
+ internal string ReplicateAttribute_FullName;
+ internal string ReconcileAttribute_FullName;
+ private string ServerAttribute_FullName;
+ private string ClientAttribute_FullName;
+ private string ServerRpcAttribute_FullName;
+ private string ObserversRpcAttribute_FullName;
+ private string TargetRpcAttribute_FullName;
+ private string SyncVarAttribute_FullName;
+ private string SyncObjectAttribute_FullName;
+ #endregion
+
+ public override bool ImportReferences()
+ {
+ ServerAttribute_FullName = typeof(ServerAttribute).FullName;
+ ClientAttribute_FullName = typeof(ClientAttribute).FullName;
+ ServerRpcAttribute_FullName = typeof(ServerRpcAttribute).FullName;
+ ObserversRpcAttribute_FullName = typeof(ObserversRpcAttribute).FullName;
+ TargetRpcAttribute_FullName = typeof(TargetRpcAttribute).FullName;
+ SyncVarAttribute_FullName = typeof(SyncVarAttribute).FullName;
+ SyncObjectAttribute_FullName = typeof(SyncObjectAttribute).FullName;
+ ReplicateAttribute_FullName = typeof(ReplicateAttribute).FullName;
+ ReconcileAttribute_FullName = typeof(ReconcileAttribute).FullName;
+
+ return true;
+ }
+
+ ///
+ /// Returns type of Rpc attributeFullName is for.
+ ///
+ ///
+ ///
+ public RpcType GetRpcAttributeType(CustomAttribute ca)
+ {
+ if (ca.Is(ServerRpcAttribute_FullName))
+ return RpcType.Server;
+ else if (ca.Is(ObserversRpcAttribute_FullName))
+ return RpcType.Observers;
+ else if (ca.Is(TargetRpcAttribute_FullName))
+ return RpcType.Target;
+ else
+ return RpcType.None;
+ }
+
+
+ ///
+ /// Returns type of Rpc attributeFullName is for.
+ ///
+ ///
+ ///
+ internal QolAttributeType GetQolAttributeType(string attributeFullName)
+ {
+ if (attributeFullName == ServerAttribute_FullName)
+ return QolAttributeType.Server;
+ else if (attributeFullName == ClientAttribute_FullName)
+ return QolAttributeType.Client;
+ else
+ return QolAttributeType.None;
+ }
+
+
+ ///
+ /// Returns if attribute if a SyncVarAttribute.
+ ///
+ ///
+ ///
+ public bool IsSyncVarAttribute(string attributeFullName)
+ {
+ return (attributeFullName == SyncVarAttribute_FullName);
+ }
+ ///
+ /// Returns if attribute if a SyncObjectAttribute.
+ ///
+ ///
+ ///
+ public bool IsSyncObjectAttribute(string attributeFullName)
+ {
+ return (attributeFullName == SyncObjectAttribute_FullName);
+ }
+ }
+
+}
diff --git a/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs.meta
new file mode 100644
index 0000000..d84b8e4
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d32f3dc23b55598429c5cfe6156e6243
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs b/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs
new file mode 100644
index 0000000..6448c24
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs
@@ -0,0 +1,194 @@
+using FishNet.CodeGenerating.Helping;
+using FishNet.CodeGenerating.ILCore;
+using FishNet.CodeGenerating.Processing;
+using FishNet.CodeGenerating.Processing.Rpc;
+using MonoFN.Cecil;
+using System.Collections.Generic;
+using System.Linq;
+using Unity.CompilationPipeline.Common.Diagnostics;
+#if !UNITY_2020_1_OR_NEWER
+using UnityEngine;
+#endif
+using SR = System.Reflection;
+
+
+namespace FishNet.CodeGenerating
+{
+
+ internal class CodegenSession
+ {
+ ///
+ /// Current module for this session.
+ ///
+ internal ModuleDefinition Module;
+ ///
+ /// Outputs errors when codegen fails.
+ ///
+ internal List Diagnostics;
+ ///
+ /// SyncVars that are being accessed from an assembly other than the currently being processed one.
+ ///
+ internal List DifferentAssemblySyncVars = new List();
+
+
+ ///
+ /// CodegenBase classes for processing a module.
+ ///
+ private List _bases;
+ ///
+ /// Quick lookup of base classes.
+ ///
+ private Dictionary _basesCache = new Dictionary();
+
+ ///
+ /// Returns class of type if found within CodegenBase classes.
+ ///
+ ///
+ ///
+ internal T GetClass() where T : CodegenBase
+ {
+ string tName = typeof(T).Name;
+ return (T)_basesCache[tName];
+ }
+ ///
+ /// Resets all helpers while importing any information needed by them.
+ ///
+ ///
+ ///
+ internal bool Initialize(ModuleDefinition module)
+ {
+ Module = module;
+ Diagnostics = new List();
+
+ _bases = new List()
+ {
+ new ReaderImports(), new ReaderProcessor()
+ ,new WriterImports(), new WriterProcessor()
+ , new PhysicsHelper(), new TimeManagerHelper(), new AttributeHelper(), new GeneralHelper()
+ , new ObjectHelper(), new NetworkBehaviourHelper()
+ , new CreatedSyncVarGenerator(), new TransportHelper()
+ , new NetworkConnectionImports(), new PredictedObjectHelper(), new GeneratorHelper()
+ , new CustomSerializerProcessor()
+ , new NetworkBehaviourProcessor()
+ , new QolAttributeProcessor()
+ , new RpcProcessor()
+ , new NetworkBehaviourSyncProcessor()
+ , new PredictionProcessor()
+ };
+
+ //Add all to dictionary first, then import.
+ foreach (CodegenBase item in _bases)
+ {
+ string tName = item.GetType().Name;
+ _basesCache.Add(tName, item);
+ }
+
+ //Initialize.
+ foreach (CodegenBase item in _bases)
+ {
+ item.Initialize(this);
+ if (!item.ImportReferences())
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+
+ #region Logging.
+ ///
+ /// Logs a warning.
+ ///
+ ///
+ internal void LogWarning(string msg)
+ {
+#if UNITY_2020_1_OR_NEWER
+ Diagnostics.AddWarning(msg);
+#else
+ Debug.LogWarning(msg);
+#endif
+ }
+ ///
+ /// Logs an error.
+ ///
+ ///
+ internal void LogError(string msg)
+ {
+#if UNITY_2020_1_OR_NEWER
+ Diagnostics.AddError(msg);
+#else
+ Debug.LogError(msg);
+#endif
+ }
+ #endregion
+
+ #region ImportReference.
+
+ public MethodReference ImportReference(SR.MethodBase method)
+ {
+ return Module.ImportReference(method);
+ }
+
+ public MethodReference ImportReference(SR.MethodBase method, IGenericParameterProvider context)
+ {
+ return Module.ImportReference(method, context);
+ }
+
+ public TypeReference ImportReference(TypeReference type)
+ {
+ return Module.ImportReference(type);
+ }
+
+ public TypeReference ImportReference(TypeReference type, IGenericParameterProvider context)
+ {
+ return Module.ImportReference(type, context);
+ }
+
+ public FieldReference ImportReference(FieldReference field)
+ {
+ return Module.ImportReference(field);
+ }
+
+ public FieldReference ImportReference(FieldReference field, IGenericParameterProvider context)
+ {
+ return Module.ImportReference(field, context);
+ }
+ public MethodReference ImportReference(MethodReference method)
+ {
+ return Module.ImportReference(method);
+ }
+
+ public MethodReference ImportReference(MethodReference method, IGenericParameterProvider context)
+ {
+ return Module.ImportReference(method, context);
+ }
+ public TypeReference ImportReference(System.Type type)
+ {
+ return ImportReference(type, null);
+ }
+
+
+ public TypeReference ImportReference(System.Type type, IGenericParameterProvider context)
+ {
+ return Module.ImportReference(type, context);
+ }
+
+
+ public FieldReference ImportReference(SR.FieldInfo field)
+ {
+ return Module.ImportReference(field);
+ }
+
+ public FieldReference ImportReference(SR.FieldInfo field, IGenericParameterProvider context)
+ {
+ return Module.ImportReference(field, context);
+ }
+
+ #endregion
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta
new file mode 100644
index 0000000..3373edc
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3e8416eee3308f54fa942003de975420
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs b/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs
new file mode 100644
index 0000000..89b1cc7
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs
@@ -0,0 +1,121 @@
+using FishNet.CodeGenerating.Helping.Extension;
+using FishNet.CodeGenerating.Processing;
+using FishNet.Object.Synchronizing;
+using FishNet.Object.Synchronizing.Internal;
+using MonoFN.Cecil;
+using MonoFN.Cecil.Rocks;
+using System;
+using System.Collections.Generic;
+
+namespace FishNet.CodeGenerating.Helping
+{
+ internal class CreatedSyncVarGenerator : CodegenBase
+ {
+ private readonly Dictionary _createdSyncVars = new Dictionary();
+
+ #region Relfection references.
+ private TypeReference _syncBase_TypeRef;
+ internal TypeReference SyncVar_TypeRef;
+ private MethodReference _syncVar_Constructor_MethodRef;
+ #endregion
+
+ #region Const.
+ private const string GETVALUE_NAME = "GetValue";
+ private const string SETVALUE_NAME = "SetValue";
+ #endregion
+
+ /* //feature add and test the dirty boolean changes
+ * eg... instead of base.Dirty()
+ * do if (!base.Dirty()) return false;
+ * See synclist for more info. */
+
+ ///
+ /// Imports references needed by this helper.
+ ///
+ ///
+ ///
+ public override bool ImportReferences()
+ {
+ SyncVar_TypeRef = base.ImportReference(typeof(SyncVar<>));
+ MethodDefinition svConstructor = SyncVar_TypeRef.GetFirstConstructor(base.Session, true);
+ _syncVar_Constructor_MethodRef = base.ImportReference(svConstructor);
+
+ Type syncBaseType = typeof(SyncBase);
+ _syncBase_TypeRef = base.ImportReference(syncBaseType);
+
+ return true;
+ }
+
+ ///
+ /// Gets and optionally creates data for SyncVar
+ ///
+ ///
+ ///
+ internal CreatedSyncVar GetCreatedSyncVar(FieldDefinition originalFd, bool createMissing)
+ {
+ TypeReference dataTr = originalFd.FieldType;
+ TypeDefinition dataTd = dataTr.CachedResolve(base.Session);
+
+ string typeHash = dataTr.FullName + dataTr.IsArray.ToString();
+
+ if (_createdSyncVars.TryGetValue(typeHash, out CreatedSyncVar createdSyncVar))
+ {
+ return createdSyncVar;
+ }
+ else
+ {
+ if (!createMissing)
+ return null;
+
+ base.ImportReference(dataTd);
+
+ GenericInstanceType syncVarGit = SyncVar_TypeRef.MakeGenericInstanceType(new TypeReference[] { dataTr });
+ TypeReference genericDataTr = syncVarGit.GenericArguments[0];
+
+ //Make sure can serialize.
+ bool canSerialize = base.GetClass().HasSerializerAndDeserializer(genericDataTr, true);
+ if (!canSerialize)
+ {
+ base.LogError($"SyncVar {originalFd.Name} data type {genericDataTr.FullName} does not support serialization. Use a supported type or create a custom serializer.");
+ return null;
+ }
+
+ //Set needed methods from syncbase.
+ MethodReference setSyncIndexMr;
+ MethodReference genericSyncVarCtor = _syncVar_Constructor_MethodRef.MakeHostInstanceGeneric(base.Session, syncVarGit);
+
+ if (!base.GetClass().SetSyncBaseMethods(_syncBase_TypeRef.CachedResolve(base.Session), out setSyncIndexMr, out _))
+ return null;
+
+ MethodReference setValueMr = null;
+ MethodReference getValueMr = null;
+ foreach (MethodDefinition md in SyncVar_TypeRef.CachedResolve(base.Session).Methods)
+ {
+ //GetValue.
+ if (md.Name == GETVALUE_NAME)
+ {
+ MethodReference mr = base.ImportReference(md);
+ getValueMr = mr.MakeHostInstanceGeneric(base.Session, syncVarGit);
+ }
+ //SetValue.
+ else if (md.Name == SETVALUE_NAME)
+ {
+ MethodReference mr = base.ImportReference(md);
+ setValueMr = mr.MakeHostInstanceGeneric(base.Session, syncVarGit);
+ }
+ }
+
+ if (setValueMr == null || getValueMr == null)
+ return null;
+
+ CreatedSyncVar csv = new CreatedSyncVar(syncVarGit, dataTd, getValueMr, setValueMr, setSyncIndexMr, null, genericSyncVarCtor);
+ _createdSyncVars.Add(typeHash, csv);
+ return csv;
+ }
+ }
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs.meta
new file mode 100644
index 0000000..086dc59
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 935ec97b96b35b94f8c6880c6908304c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension.meta
new file mode 100644
index 0000000..a4c0b09
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: df90983b61081f84b990ac494ac8bdb6
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs
new file mode 100644
index 0000000..b11e91c
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs
@@ -0,0 +1,54 @@
+using MonoFN.Cecil;
+using System.Linq;
+
+namespace FishNet.CodeGenerating.Helping.Extension
+{
+
+ internal static class CustomAttributeExtensions
+ {
+ ///
+ /// Finds a field within an attribute.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static T GetField(this CustomAttribute customAttr, string field, T defaultValue)
+ {
+ foreach (CustomAttributeNamedArgument customField in customAttr.Fields)
+ {
+ if (customField.Name == field)
+ {
+ return (T)customField.Argument.Value;
+ }
+ }
+
+ return defaultValue;
+ }
+
+ ///
+ /// Returns if any of the attributes match IAtrribute.
+ ///
+ ///
+ ///
+ ///
+ internal static bool HasCustomAttribute(this ICustomAttributeProvider attributeProvider)
+ {
+ return attributeProvider.CustomAttributes.Any(attr => attr.AttributeType.Is());
+ }
+
+ ///
+ /// Returns if ca is of type target.
+ ///
+ ///
+ ///
+ ///
+ internal static bool Is(this CustomAttribute ca, string targetFullName)
+ {
+ return ca.AttributeType.FullName == targetFullName;
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs.meta
new file mode 100644
index 0000000..87b14e3
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/CustomAttributeExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a66d771ab331fae408142a5c04abd74e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs
new file mode 100644
index 0000000..5fda8fe
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs
@@ -0,0 +1,41 @@
+using MonoFN.Cecil;
+using MonoFN.Cecil.Cil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Unity.CompilationPipeline.Common.Diagnostics;
+
+namespace FishNet.CodeGenerating.Helping
+{
+ internal static class Diagnostics
+ {
+ internal static void AddError(this List diagnostics, string message)
+ {
+ diagnostics.AddMessage(DiagnosticType.Error, (SequencePoint)null, message);
+ }
+
+ internal static void AddWarning(this List diagnostics, string message)
+ {
+ diagnostics.AddMessage(DiagnosticType.Warning, (SequencePoint)null, message);
+ }
+
+ internal static void AddError(this List diagnostics, MethodDefinition methodDef, string message)
+ {
+ diagnostics.AddMessage(DiagnosticType.Error, methodDef.DebugInformation.SequencePoints.FirstOrDefault(), message);
+ }
+
+ internal static void AddMessage(this List diagnostics, DiagnosticType diagnosticType, SequencePoint sequencePoint, string message)
+ {
+ diagnostics.Add(new DiagnosticMessage
+ {
+ DiagnosticType = diagnosticType,
+ File = sequencePoint?.Document.Url.Replace($"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}", ""),
+ Line = sequencePoint?.StartLine ?? 0,
+ Column = sequencePoint?.StartColumn ?? 0,
+ MessageData = $" - {message}"
+ });
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs.meta
new file mode 100644
index 0000000..a70954f
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/Diagnostics.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fb7b65b572b01444cbe3c9d830cd3587
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs
new file mode 100644
index 0000000..803d4de
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs
@@ -0,0 +1,38 @@
+using FishNet.CodeGenerating.Extension;
+using MonoFN.Cecil;
+
+namespace FishNet.CodeGenerating.Helping.Extension
+{
+
+ internal static class FieldReferenceExtensions
+ {
+
+ ///
+ /// Gets a Resolve favoring cached results first.
+ ///
+ internal static FieldDefinition CachedResolve(this FieldReference fieldRef, CodegenSession session)
+ {
+ return session.GetClass().GetFieldReferenceResolve(fieldRef);
+ }
+
+
+ public static FieldReference MakeHostGenericIfNeeded(this FieldDefinition fd, CodegenSession session)
+ {
+ TypeReference declaringTr = fd.DeclaringType;
+
+ if (declaringTr.HasGenericParameters)
+ {
+ GenericInstanceType git = declaringTr.MakeGenericInstanceType();
+ FieldReference result = new FieldReference(fd.Name, fd.FieldType, git);
+ return result;
+ }
+ else
+ {
+ return session.ImportReference(fd);
+ }
+ }
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs.meta
new file mode 100644
index 0000000..c868340
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/FieldReferenceExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6d983ebd0c9e1b745902030c2f7a8e99
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs
new file mode 100644
index 0000000..2d38cdd
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs
@@ -0,0 +1,191 @@
+using FishNet.CodeGenerating.Helping.Extension;
+using MonoFN.Cecil;
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace FishNet.CodeGenerating.Helping
+{
+ internal static class Constructors
+ {
+
+ ///
+ /// Gets the first constructor that optionally has, or doesn't have parameters.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetFirstConstructor(this TypeReference typeRef, CodegenSession session, bool requireParameters)
+ {
+ return typeRef.CachedResolve(session).GetFirstConstructor(requireParameters);
+ }
+ ///
+ /// Gets the first constructor that optionally has, or doesn't have parameters.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetFirstConstructor(this TypeDefinition typeDef, bool requireParameters)
+ {
+
+ foreach (MethodDefinition methodDef in typeDef.Methods)
+ {
+ if (methodDef.IsConstructor && methodDef.IsPublic)
+ {
+ if (requireParameters && methodDef.Parameters.Count > 0)
+ return methodDef;
+ else if (!requireParameters && methodDef.Parameters.Count == 0)
+ return methodDef;
+ }
+
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets the first public constructor with no parameters.
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session)
+ {
+ return typeRef.CachedResolve(session).GetConstructor();
+ }
+ ///
+ /// Gets the first public constructor with no parameters.
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeDefinition typeDef)
+ {
+ foreach (MethodDefinition methodDef in typeDef.Methods)
+ {
+ if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == 0)
+ return methodDef;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets all constructors on typeDef.
+ ///
+ ///
+ public static List GetConstructors(this TypeDefinition typeDef)
+ {
+ List lst = new List();
+ foreach (MethodDefinition methodDef in typeDef.Methods)
+ {
+ if (methodDef.IsConstructor)
+ lst.Add(methodDef);
+ }
+
+ return lst;
+ }
+
+
+ ///
+ /// Gets constructor which has arguments.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, Type[] arguments)
+ {
+ return typeRef.CachedResolve(session).GetConstructor(arguments);
+ }
+
+ ///
+ /// Gets constructor which has arguments.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeDefinition typeDef, Type[] arguments)
+ {
+ Type[] argsCopy = (arguments == null) ? new Type[0] : arguments;
+ foreach (MethodDefinition methodDef in typeDef.Methods)
+ {
+ if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length)
+ {
+ bool match = true;
+ for (int i = 0; i < argsCopy.Length; i++)
+ {
+ if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName)
+ {
+ match = false;
+ break;
+ }
+ }
+
+ if (match)
+ return methodDef;
+ }
+ }
+ return null;
+ }
+
+
+ ///
+ /// Gets constructor which has arguments.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, TypeReference[] arguments)
+ {
+ return typeRef.CachedResolve(session).GetConstructor(arguments);
+ }
+
+ ///
+ /// Gets constructor which has arguments.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeDefinition typeDef, TypeReference[] arguments)
+ {
+ TypeReference[] argsCopy = (arguments == null) ? new TypeReference[0] : arguments;
+ foreach (MethodDefinition methodDef in typeDef.Methods)
+ {
+ if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length)
+ {
+ bool match = true;
+ for (int i = 0; i < argsCopy.Length; i++)
+ {
+ if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName)
+ {
+ match = false;
+ break;
+ }
+ }
+
+ if (match)
+ return methodDef;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Resolves the constructor with parameterCount for typeRef.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, int parameterCount)
+ {
+ return typeRef.CachedResolve(session).GetConstructor(parameterCount);
+ }
+
+
+ ///
+ /// Resolves the constructor with parameterCount for typeRef.
+ ///
+ ///
+ ///
+ public static MethodDefinition GetConstructor(this TypeDefinition typeDef, int parameterCount)
+ {
+ foreach (MethodDefinition methodDef in typeDef.Methods)
+ {
+ if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == parameterCount)
+ return methodDef;
+ }
+ return null;
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs.meta
new file mode 100644
index 0000000..c66fc8f
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/GetConstructor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1a7e03137ca78704e999f3a3dc68b953
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs
new file mode 100644
index 0000000..2ff3d20
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs
@@ -0,0 +1,169 @@
+using MonoFN.Cecil;
+using MonoFN.Cecil.Cil;
+using System.Collections.Generic;
+
+namespace FishNet.CodeGenerating.Helping.Extension
+{
+
+ internal static class ILProcessorExtensions
+ {
+
+ ///
+ /// Creates a debug log for text without any conditions.
+ ///
+ public static void DebugLog(this ILProcessor processor, CodegenSession session, string txt)
+ {
+ processor.Emit(OpCodes.Ldstr, txt);
+ processor.Emit(OpCodes.Call, session.GetClass().Debug_LogCommon_MethodRef);
+ }
+ ///
+ /// Creates a debug log for vd without any conditions.
+ ///
+ public static void DebugLog(this ILProcessor processor, CodegenSession session, VariableDefinition vd)
+ {
+ processor.Emit(OpCodes.Ldloc, vd);
+ processor.Emit(OpCodes.Box, vd.VariableType);
+ processor.Emit(OpCodes.Call, session.GetClass().Debug_LogCommon_MethodRef);
+ }
+ ///
+ /// Creates a debug log for vd without any conditions.
+ ///
+ public static void DebugLog(this ILProcessor processor, CodegenSession session, FieldDefinition fd, bool loadArg0)
+ {
+ if (loadArg0)
+ processor.Emit(OpCodes.Ldarg_0);
+ processor.Emit(OpCodes.Ldfld, fd);
+ processor.Emit(OpCodes.Box, fd.FieldType);
+ processor.Emit(OpCodes.Call, session.GetClass().Debug_LogCommon_MethodRef);
+ }
+ ///
+ /// Creates a debug log for pd without any conditions.
+ ///
+ public static void DebugLog(this ILProcessor processor, CodegenSession session, ParameterDefinition pd)
+ {
+ processor.Emit(OpCodes.Ldloc, pd);
+ processor.Emit(OpCodes.Box, pd.ParameterType);
+ processor.Emit(OpCodes.Call, session.GetClass().Debug_LogCommon_MethodRef);
+ }
+
+ /////
+ ///// Creates a debug log for mr without any conditions.
+ /////
+ //public static void DebugLog(this ILProcessor processor, MethodReference mr)
+ //{
+ // processor.Emit(OpCodes.Call, mr);
+ // processor.Emit(OpCodes.Box, mr.ReturnType);
+ // processor.Emit(OpCodes.Call, base.GetClass().Debug_LogCommon_MethodRef);
+ //}
+
+
+ ///
+ /// Inserts instructions at the beginning.
+ ///
+ ///
+ ///
+ public static void InsertAt(this ILProcessor processor, int target, List instructions)
+ {
+ for (int i = 0; i < instructions.Count; i++)
+ processor.Body.Instructions.Insert(i + target, instructions[i]);
+ }
+
+
+ ///
+ /// Inserts instructions at the beginning.
+ ///
+ ///
+ ///
+ public static void InsertFirst(this ILProcessor processor, List instructions)
+ {
+ for (int i = 0; i < instructions.Count; i++)
+ processor.Body.Instructions.Insert(i, instructions[i]);
+ }
+
+ ///
+ /// Inserts instructions at the end while also moving Ret down.
+ ///
+ ///
+ ///
+ public static void InsertLast(this ILProcessor processor, List instructions)
+ {
+ bool retRemoved = false;
+ int startingCount = processor.Body.Instructions.Count;
+ //Remove ret if it exist and add it back in later.
+ if (startingCount > 0)
+ {
+ if (processor.Body.Instructions[startingCount - 1].OpCode == OpCodes.Ret)
+ {
+ processor.Body.Instructions.RemoveAt(startingCount - 1);
+ retRemoved = true;
+ }
+ }
+
+ foreach (Instruction inst in instructions)
+ processor.Append(inst);
+
+ //Add ret back if it was removed.
+ if (retRemoved)
+ processor.Emit(OpCodes.Ret);
+ }
+
+ ///
+ /// Inserts instructions before target.
+ ///
+ ///
+ ///
+ public static void InsertBefore(this ILProcessor processor, Instruction target, List instructions)
+ {
+ int index = processor.Body.Instructions.IndexOf(target);
+ for (int i = 0; i < instructions.Count; i++)
+ processor.Body.Instructions.Insert(index + i, instructions[i]);
+ }
+
+ ///
+ /// Adds instructions to the end of processor.
+ ///
+ ///
+ ///
+ public static void Add(this ILProcessor processor, List instructions)
+ {
+ for (int i = 0; i < instructions.Count; i++)
+ processor.Body.Instructions.Add(instructions[i]);
+ }
+
+ ///
+ /// Inserts instructions before returns. Only works on void types.
+ ///
+ ///
+ ///
+ public static void InsertBeforeReturns(this ILProcessor processor, CodegenSession session, List instructions)
+ {
+ if (processor.Body.Method.ReturnType.FullName != session.Module.TypeSystem.Void.FullName)
+ {
+ session.LogError($"Cannot insert instructions before returns on {processor.Body.Method.FullName} because it does not return void.");
+ return;
+ }
+
+ /* Insert at the end of the method
+ * and get the first instruction that was inserted.
+ * Any returns or breaks which would exit the method
+ * will jump to this instruction instead. */
+ processor.InsertLast(instructions);
+ Instruction startInst = processor.Body.Instructions[processor.Body.Instructions.Count - instructions.Count];
+
+ //Look for anything that jumps to rets.
+ for (int i = 0; i < processor.Body.Instructions.Count; i++)
+ {
+ Instruction inst = processor.Body.Instructions[i];
+ if (inst.Operand is Instruction operInst)
+ {
+ if (operInst.OpCode == OpCodes.Ret)
+ inst.Operand = startInst;
+ }
+ }
+ }
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs.meta
new file mode 100644
index 0000000..dfed3f0
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/ILProcessorExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 820cf8401d4d71c4196dda444559ef8a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs
new file mode 100644
index 0000000..aefd42c
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs
@@ -0,0 +1,12 @@
+using MonoFN.Cecil;
+using MonoFN.Cecil.Cil;
+using System;
+using System.Collections.Generic;
+
+namespace FishNet.CodeGenerating.Helping
+{
+ public static class Instructions
+ {
+ }
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs.meta
new file mode 100644
index 0000000..ba87cbb
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/InstructionExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 360667149f16b6c4aba61fd05427cbfb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs
new file mode 100644
index 0000000..373321a
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs
@@ -0,0 +1,55 @@
+using MonoFN.Cecil;
+using MonoFN.Cecil.Cil;
+
+namespace FishNet.CodeGenerating.Helping.Extension
+{
+
+ internal static class MethodDefinitionExtensions
+ {
+ ///
+ /// Clears the method content and returns ret.
+ ///
+ internal static void ClearMethodWithRet(this MethodDefinition md, CodegenSession session, ModuleDefinition importReturnModule = null)
+ {
+ md.Body.Instructions.Clear();
+ ILProcessor processor = md.Body.GetILProcessor();
+ processor.Add(session.GetClass().CreateRetDefault(md, importReturnModule));
+ }
+
+ ///
+ /// Returns the ParameterDefinition index from end of parameters.
+ ///
+ ///
+ ///
+ ///
+ internal static ParameterDefinition GetEndParameter(this MethodDefinition md, int index)
+ {
+ //Not enough parameters.
+ if (md.Parameters.Count < (index + 1))
+ return null;
+
+ return md.Parameters[md.Parameters.Count - (index + 1)];
+ }
+
+
+ ///
+ /// Creates a variable type within the body and returns it's VariableDef.
+ ///
+ internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, TypeReference variableTypeRef)
+ {
+ VariableDefinition variableDef = new VariableDefinition(variableTypeRef);
+ methodDef.Body.Variables.Add(variableDef);
+ return variableDef;
+ }
+
+ ///
+ /// Creates a variable type within the body and returns it's VariableDef.
+ ///
+ internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, CodegenSession session, System.Type variableType)
+ {
+ return CreateVariable(methodDef, session.GetClass().GetTypeReference(variableType));
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs.meta
new file mode 100644
index 0000000..a64ef0a
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodDefinitionExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 999d4ae4862274f4ba50569c221976dd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs
new file mode 100644
index 0000000..c55390c
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs
@@ -0,0 +1,155 @@
+using MonoFN.Cecil;
+using MonoFN.Cecil.Rocks;
+using System;
+
+namespace FishNet.CodeGenerating.Helping.Extension
+{
+
+ internal static class MethodReferenceExtensions
+ {
+ ///
+ /// Makes a generic method with specified arguments.
+ ///
+ ///
+ ///
+ ///
+ public static GenericInstanceMethod MakeGenericMethod(this MethodReference method, params TypeReference[] genericArguments)
+ {
+ GenericInstanceMethod result = new GenericInstanceMethod(method);
+ foreach (TypeReference argument in genericArguments)
+ result.GenericArguments.Add(argument);
+ return result;
+ }
+
+ ///
+ /// Makes a generic method with the same arguments as the original.
+ ///
+ ///
+ ///
+ public static GenericInstanceMethod MakeGenericMethod(this MethodReference method)
+ {
+ GenericInstanceMethod result = new GenericInstanceMethod(method);
+ foreach (ParameterDefinition pd in method.Parameters)
+ result.GenericArguments.Add(pd.ParameterType);
+
+ return result;
+ }
+
+ ///
+ /// Returns a method reference for a generic method.
+ ///
+ public static MethodReference GetMethodReference(this MethodReference mr, CodegenSession session, TypeReference typeReference)
+ {
+ return mr.GetMethodReference(session, new TypeReference[] { typeReference });
+ }
+
+ ///
+ /// Returns a method reference for a generic method.
+ ///
+ public static MethodReference GetMethodReference(this MethodReference mr, CodegenSession session, TypeReference[] typeReferences)
+ {
+ if (mr.HasGenericParameters)
+ {
+ if (typeReferences == null || typeReferences.Length == 0)
+ {
+ session.LogError($"Method {mr.Name} has generic parameters but TypeReferences are null or 0 length.");
+ return null;
+ }
+ else
+ {
+ GenericInstanceMethod gim = mr.MakeGenericMethod(typeReferences);
+ return gim;
+ }
+ }
+ else
+ {
+ return mr;
+ }
+ }
+
+
+ ///
+ /// Gets a Resolve favoring cached results first.
+ ///
+ internal static MethodDefinition CachedResolve(this MethodReference methodRef, CodegenSession session)
+ {
+ return session.GetClass().GetMethodReferenceResolve(methodRef);
+ }
+
+ ///
+ /// Given a method of a generic class such as ArraySegment`T.get_Count,
+ /// and a generic instance such as ArraySegment`int
+ /// Creates a reference to the specialized method ArraySegment`int`.get_Count
+ /// Note that calling ArraySegment`T.get_Count directly gives an invalid IL error
+ ///
+ ///
+ ///
+ ///
+ public static MethodReference MakeHostInstanceGeneric(this MethodReference self, CodegenSession session, GenericInstanceType instanceType)
+ {
+ MethodReference reference = new MethodReference(self.Name, self.ReturnType, instanceType)
+ {
+ CallingConvention = self.CallingConvention,
+ HasThis = self.HasThis,
+ ExplicitThis = self.ExplicitThis
+ };
+
+ foreach (ParameterDefinition parameter in self.Parameters)
+ reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
+
+ foreach (GenericParameter generic_parameter in self.GenericParameters)
+ reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));
+
+ return session.ImportReference(reference);
+ }
+ ///
+ /// Given a method of a generic class such as ArraySegment`T.get_Count,
+ /// and a generic instance such as ArraySegment`int
+ /// Creates a reference to the specialized method ArraySegment`int`.get_Count
+ /// Note that calling ArraySegment`T.get_Count directly gives an invalid IL error
+ ///
+ ///
+ ///
+ ///
+ public static MethodReference MakeHostInstanceGeneric(this MethodReference self, TypeReference typeRef, params TypeReference[] args)
+ {
+ GenericInstanceType git = typeRef.MakeGenericInstanceType(args);
+ MethodReference reference = new MethodReference(self.Name, self.ReturnType, git)
+ {
+ CallingConvention = self.CallingConvention,
+ HasThis = self.HasThis,
+ ExplicitThis = self.ExplicitThis
+ };
+
+ foreach (ParameterDefinition parameter in self.Parameters)
+ reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
+
+ foreach (GenericParameter generic_parameter in self.GenericParameters)
+ reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));
+
+ return reference;
+ }
+ public static bool Is(this MethodReference method, string name)
+ {
+ return method.DeclaringType.Is() && method.Name == name;
+ }
+ public static bool Is(this TypeReference td)
+ {
+ return Is(td, typeof(T));
+ }
+
+ public static bool Is(this TypeReference td, Type t)
+ {
+ if (t.IsGenericType)
+ {
+ return td.GetElementType().FullName == t.FullName;
+ }
+ return td.FullName == t.FullName;
+ }
+
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs.meta b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs.meta
new file mode 100644
index 0000000..1a5c3a8
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/MethodReferenceExtensions.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ee1c15a06ab386e439ec5aa41e3496f7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs b/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs
new file mode 100644
index 0000000..e52e04b
--- /dev/null
+++ b/Assets/FishNet/CodeGenerating/Helpers/Extension/ModuleDefinitionExtensions.cs
@@ -0,0 +1,63 @@
+using FishNet.CodeGenerating.ILCore;
+using MonoFN.Cecil;
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace FishNet.CodeGenerating.Helping.Extension
+{
+
+ public static class ModuleDefinitionExtensions
+ {
+ ///
+ /// Gets a class within a module.
+ ///
+ ///
+ ///
+ public static TypeDefinition GetClass(this ModuleDefinition moduleDef, string className, string namespaceName = "")
+ {
+ if (namespaceName.Length == 0)
+ namespaceName = FishNetILPP.RUNTIME_ASSEMBLY_NAME;
+
+ return moduleDef.GetType(namespaceName, className);
+ }
+
+ public static MethodReference ImportReference(this ModuleDefinition moduleDef, Expression expression)
+ {
+ return ImportReference(moduleDef, (LambdaExpression)expression);
+ }
+ public static MethodReference ImportReference(this ModuleDefinition module, Expression> expression)
+ {
+ return ImportReference(module, (LambdaExpression)expression);
+ }
+
+ public static MethodReference ImportReference(this ModuleDefinition module, LambdaExpression expression)
+ {
+ if (expression.Body is MethodCallExpression outermostExpression)
+ {
+ MethodInfo methodInfo = outermostExpression.Method;
+ return module.ImportReference(methodInfo);
+ }
+
+ if (expression.Body is NewExpression newExpression)
+ {
+ ConstructorInfo methodInfo = newExpression.Constructor;
+ // constructor is null when creating an ArraySegment