fishnet installed
This commit is contained in:
parent
47b25269f1
commit
a001fe1b04
22
Assets/DefaultPrefabObjects.asset
Normal file
22
Assets/DefaultPrefabObjects.asset
Normal file
@ -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}
|
8
Assets/DefaultPrefabObjects.asset.meta
Normal file
8
Assets/DefaultPrefabObjects.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6b71f999cc8fc647a3f73f7088802e0
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/FishNet.meta
Normal file
8
Assets/FishNet.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c10e8242689baa4795de57f9ef42ec3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/FishNet/CodeGenerating.meta
Normal file
8
Assets/FishNet/CodeGenerating.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbb4974b4302f435b9f4663c64d8f803
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/FishNet/CodeGenerating/Extension.meta
Normal file
8
Assets/FishNet/CodeGenerating/Extension.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 206db668838ebc34b90ae36be24ce3be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,20 @@
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using MonoFN.Cecil.Cil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Extension
|
||||
{
|
||||
|
||||
|
||||
internal static class ILProcessorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a variable type within the body and returns it's VariableDef.
|
||||
/// </summary>
|
||||
internal static VariableDefinition CreateVariable(this ILProcessor processor, CodegenSession session, System.Type variableType)
|
||||
{
|
||||
return processor.Body.Method.CreateVariable(session, variableType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 127d8312da53b3e49ba9e3e4c6348857
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the proper OpCode to use for call methods.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the proper OpCode to use for call methods.
|
||||
/// </summary>
|
||||
public static MonoFN.Cecil.Cil.OpCode GetCallOpCode(this MethodReference mr, CodegenSession session)
|
||||
{
|
||||
return mr.CachedResolve(session).GetCallOpCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds otherMd parameters to thisMR and returns added parameters.
|
||||
/// </summary>
|
||||
public static List<ParameterDefinition> CreateParameters(this MethodReference thisMr, CodegenSession session, MethodDefinition otherMd)
|
||||
{
|
||||
return thisMr.CachedResolve(session).CreateParameters(session, otherMd);
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds otherMr parameters to thisMR and returns added parameters.
|
||||
/// </summary>
|
||||
public static List<ParameterDefinition> CreateParameters(this MethodReference thisMr, CodegenSession session, MethodReference otherMr)
|
||||
{
|
||||
return thisMr.CachedResolve(session).CreateParameters(session, otherMr.CachedResolve(session));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds otherMd parameters to thisMd and returns added parameters.
|
||||
/// </summary>
|
||||
public static List<ParameterDefinition> CreateParameters(this MethodDefinition thisMd, CodegenSession session, MethodDefinition otherMd)
|
||||
{
|
||||
List<ParameterDefinition> results = new List<ParameterDefinition>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method reference while considering if declaring type is generic.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method reference for a generic method.
|
||||
/// </summary>
|
||||
public static MethodReference GetMethodReference(this MethodDefinition md, CodegenSession session, TypeReference typeReference)
|
||||
{
|
||||
MethodReference methodRef = session.ImportReference(md);
|
||||
return methodRef.GetMethodReference(session, typeReference);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method reference for a generic method.
|
||||
/// </summary>
|
||||
public static MethodReference GetMethodReference(this MethodDefinition md, CodegenSession session, TypeReference[] typeReferences)
|
||||
{
|
||||
MethodReference methodRef = session.ImportReference(md);
|
||||
return methodRef.GetMethodReference(session, typeReferences);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 866ed457fe28c3e4b9698d87b9abd709
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,254 @@
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using MonoFN.Cecil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Extension
|
||||
{
|
||||
|
||||
|
||||
internal static class TypeDefinitionExtensions
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a TypeDefinition is nullable.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a method in the next base class.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method in the next base class.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a MethodReference or creates one if missing.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a MethodDefinition or creates one if missing.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a MethodDefinition or creates one if missing.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method in any inherited classes. The first found method is returned.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the next base type.
|
||||
/// </summary>
|
||||
public static TypeDefinition GetNextBaseTypeDefinition(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
return (typeDef.BaseType == null) ? null : typeDef.BaseType.CachedResolve(session);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a FieldReference.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a FieldReference or creates it if missing.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a FieldReference.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9f00cf3dc8b90b469c3c9cb8b87fc88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a TypeReference is nullable.
|
||||
/// </summary>
|
||||
public static bool IsNullable(this TypeReference tr, CodegenSession session)
|
||||
{
|
||||
TypeDefinition td = tr.CachedResolve(session);
|
||||
return td.IsNullable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the fullname of a TypeReference without <>.
|
||||
/// </summary>
|
||||
/// <param name="tr"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetFullnameWithoutBrackets(this TypeReference tr)
|
||||
{
|
||||
string str = tr.FullName;
|
||||
str = str.Replace("<", "");
|
||||
str = str.Replace(">", "");
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method in the next base class.
|
||||
/// </summary>
|
||||
public static MethodReference GetMethodInBase(this TypeReference tr, CodegenSession session, string methodName)
|
||||
{
|
||||
return tr.CachedResolve(session).GetMethodInBase(session, methodName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes a GenericInstanceType.
|
||||
/// </summary>
|
||||
public static GenericInstanceType MakeGenericInstanceType(this TypeReference self)
|
||||
{
|
||||
GenericInstanceType instance = new GenericInstanceType(self);
|
||||
foreach (GenericParameter argument in self.GenericParameters)
|
||||
instance.GenericArguments.Add(argument);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 239b1b10db80c594d93b7ba4ee2c1ec5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/FishNet/CodeGenerating/FN_README.txt
Normal file
9
Assets/FishNet/CodeGenerating/FN_README.txt
Normal file
@ -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.
|
7
Assets/FishNet/CodeGenerating/FN_README.txt.meta
Normal file
7
Assets/FishNet/CodeGenerating/FN_README.txt.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9133eb285bd7f3c4f89f4d7a2a079c6b
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/FishNet/CodeGenerating/Helpers.meta
Normal file
8
Assets/FishNet/CodeGenerating/Helpers.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efeca2428bd9fe64d872a626b93ff0cf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
94
Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs
Normal file
94
Assets/FishNet/CodeGenerating/Helpers/AttributeHelper.cs
Normal file
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns type of Rpc attributeFullName is for.
|
||||
/// </summary>
|
||||
/// <param name="attributeFullName"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns type of Rpc attributeFullName is for.
|
||||
/// </summary>
|
||||
/// <param name="attributeFullName"></param>
|
||||
/// <returns></returns>
|
||||
internal QolAttributeType GetQolAttributeType(string attributeFullName)
|
||||
{
|
||||
if (attributeFullName == ServerAttribute_FullName)
|
||||
return QolAttributeType.Server;
|
||||
else if (attributeFullName == ClientAttribute_FullName)
|
||||
return QolAttributeType.Client;
|
||||
else
|
||||
return QolAttributeType.None;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if attribute if a SyncVarAttribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeFullName"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsSyncVarAttribute(string attributeFullName)
|
||||
{
|
||||
return (attributeFullName == SyncVarAttribute_FullName);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns if attribute if a SyncObjectAttribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeFullName"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsSyncObjectAttribute(string attributeFullName)
|
||||
{
|
||||
return (attributeFullName == SyncObjectAttribute_FullName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d32f3dc23b55598429c5cfe6156e6243
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
194
Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs
Normal file
194
Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Current module for this session.
|
||||
/// </summary>
|
||||
internal ModuleDefinition Module;
|
||||
/// <summary>
|
||||
/// Outputs errors when codegen fails.
|
||||
/// </summary>
|
||||
internal List<DiagnosticMessage> Diagnostics;
|
||||
/// <summary>
|
||||
/// SyncVars that are being accessed from an assembly other than the currently being processed one.
|
||||
/// </summary>
|
||||
internal List<FieldDefinition> DifferentAssemblySyncVars = new List<FieldDefinition>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// CodegenBase classes for processing a module.
|
||||
/// </summary>
|
||||
private List<CodegenBase> _bases;
|
||||
/// <summary>
|
||||
/// Quick lookup of base classes.
|
||||
/// </summary>
|
||||
private Dictionary<string, CodegenBase> _basesCache = new Dictionary<string, CodegenBase>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns class of type if found within CodegenBase classes.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
internal T GetClass<T>() where T : CodegenBase
|
||||
{
|
||||
string tName = typeof(T).Name;
|
||||
return (T)_basesCache[tName];
|
||||
}
|
||||
/// <summary>
|
||||
/// Resets all helpers while importing any information needed by them.
|
||||
/// </summary>
|
||||
/// <param name="module"></param>
|
||||
/// <returns></returns>
|
||||
internal bool Initialize(ModuleDefinition module)
|
||||
{
|
||||
Module = module;
|
||||
Diagnostics = new List<DiagnosticMessage>();
|
||||
|
||||
_bases = new List<CodegenBase>()
|
||||
{
|
||||
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.
|
||||
/// <summary>
|
||||
/// Logs a warning.
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
internal void LogWarning(string msg)
|
||||
{
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
Diagnostics.AddWarning(msg);
|
||||
#else
|
||||
Debug.LogWarning(msg);
|
||||
#endif
|
||||
}
|
||||
/// <summary>
|
||||
/// Logs an error.
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
11
Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/CodegenSession.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e8416eee3308f54fa942003de975420
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
121
Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs
Normal file
121
Assets/FishNet/CodeGenerating/Helpers/CreatedSyncVarGenerator.cs
Normal file
@ -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<string, CreatedSyncVar> _createdSyncVars = new Dictionary<string, CreatedSyncVar>();
|
||||
|
||||
#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. */
|
||||
|
||||
/// <summary>
|
||||
/// Imports references needed by this helper.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and optionally creates data for SyncVar<typeOfField>
|
||||
/// </summary>
|
||||
/// <param name="dataTr"></param>
|
||||
/// <returns></returns>
|
||||
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<GeneralHelper>().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<NetworkBehaviourSyncProcessor>().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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 935ec97b96b35b94f8c6880c6908304c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/FishNet/CodeGenerating/Helpers/Extension.meta
Normal file
8
Assets/FishNet/CodeGenerating/Helpers/Extension.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df90983b61081f84b990ac494ac8bdb6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,54 @@
|
||||
using MonoFN.Cecil;
|
||||
using System.Linq;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class CustomAttributeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds a field within an attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="customAttr"></param>
|
||||
/// <param name="field"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
internal static T GetField<T>(this CustomAttribute customAttr, string field, T defaultValue)
|
||||
{
|
||||
foreach (CustomAttributeNamedArgument customField in customAttr.Fields)
|
||||
{
|
||||
if (customField.Name == field)
|
||||
{
|
||||
return (T)customField.Argument.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if any of the attributes match IAtrribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="attributeProvider"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool HasCustomAttribute<TAttribute>(this ICustomAttributeProvider attributeProvider)
|
||||
{
|
||||
return attributeProvider.CustomAttributes.Any(attr => attr.AttributeType.Is<TAttribute>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if ca is of type target.
|
||||
/// </summary>
|
||||
/// <param name="ca"></param>
|
||||
/// <param name="targetFullName"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool Is(this CustomAttribute ca, string targetFullName)
|
||||
{
|
||||
return ca.AttributeType.FullName == targetFullName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a66d771ab331fae408142a5c04abd74e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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<DiagnosticMessage> diagnostics, string message)
|
||||
{
|
||||
diagnostics.AddMessage(DiagnosticType.Error, (SequencePoint)null, message);
|
||||
}
|
||||
|
||||
internal static void AddWarning(this List<DiagnosticMessage> diagnostics, string message)
|
||||
{
|
||||
diagnostics.AddMessage(DiagnosticType.Warning, (SequencePoint)null, message);
|
||||
}
|
||||
|
||||
internal static void AddError(this List<DiagnosticMessage> diagnostics, MethodDefinition methodDef, string message)
|
||||
{
|
||||
diagnostics.AddMessage(DiagnosticType.Error, methodDef.DebugInformation.SequencePoints.FirstOrDefault(), message);
|
||||
}
|
||||
|
||||
internal static void AddMessage(this List<DiagnosticMessage> 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}"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb7b65b572b01444cbe3c9d830cd3587
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,38 @@
|
||||
using FishNet.CodeGenerating.Extension;
|
||||
using MonoFN.Cecil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class FieldReferenceExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Resolve favoring cached results first.
|
||||
/// </summary>
|
||||
internal static FieldDefinition CachedResolve(this FieldReference fieldRef, CodegenSession session)
|
||||
{
|
||||
return session.GetClass<GeneralHelper>().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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d983ebd0c9e1b745902030c2f7a8e99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first constructor that optionally has, or doesn't have parameters.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetFirstConstructor(this TypeReference typeRef, CodegenSession session, bool requireParameters)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetFirstConstructor(requireParameters);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the first constructor that optionally has, or doesn't have parameters.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first public constructor with no parameters.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the first public constructor with no parameters.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all constructors on typeDef.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<MethodDefinition> GetConstructors(this TypeDefinition typeDef)
|
||||
{
|
||||
List<MethodDefinition> lst = new List<MethodDefinition>();
|
||||
foreach (MethodDefinition methodDef in typeDef.Methods)
|
||||
{
|
||||
if (methodDef.IsConstructor)
|
||||
lst.Add(methodDef);
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, Type[] arguments)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor(arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, TypeReference[] arguments)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor(arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the constructor with parameterCount for typeRef.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, int parameterCount)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor(parameterCount);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the constructor with parameterCount for typeRef.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a7e03137ca78704e999f3a3dc68b953
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,169 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class ILProcessorExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates a debug log for text without any conditions.
|
||||
/// </summary>
|
||||
public static void DebugLog(this ILProcessor processor, CodegenSession session, string txt)
|
||||
{
|
||||
processor.Emit(OpCodes.Ldstr, txt);
|
||||
processor.Emit(OpCodes.Call, session.GetClass<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a debug log for vd without any conditions.
|
||||
/// </summary>
|
||||
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<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a debug log for vd without any conditions.
|
||||
/// </summary>
|
||||
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<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a debug log for pd without any conditions.
|
||||
/// </summary>
|
||||
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<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Creates a debug log for mr without any conditions.
|
||||
///// </summary>
|
||||
//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<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions at the beginning.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertAt(this ILProcessor processor, int target, List<Instruction> instructions)
|
||||
{
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Insert(i + target, instructions[i]);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions at the beginning.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertFirst(this ILProcessor processor, List<Instruction> instructions)
|
||||
{
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Insert(i, instructions[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions at the end while also moving Ret down.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertLast(this ILProcessor processor, List<Instruction> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions before target.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertBefore(this ILProcessor processor, Instruction target, List<Instruction> instructions)
|
||||
{
|
||||
int index = processor.Body.Instructions.IndexOf(target);
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Insert(index + i, instructions[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds instructions to the end of processor.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void Add(this ILProcessor processor, List<Instruction> instructions)
|
||||
{
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Add(instructions[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions before returns. Only works on void types.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertBeforeReturns(this ILProcessor processor, CodegenSession session, List<Instruction> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 820cf8401d4d71c4196dda444559ef8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
{
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 360667149f16b6c4aba61fd05427cbfb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,55 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class MethodDefinitionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Clears the method content and returns ret.
|
||||
/// </summary>
|
||||
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<GeneralHelper>().CreateRetDefault(md, importReturnModule));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ParameterDefinition index from end of parameters.
|
||||
/// </summary>
|
||||
/// <param name="md"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
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)];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a variable type within the body and returns it's VariableDef.
|
||||
/// </summary>
|
||||
internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, TypeReference variableTypeRef)
|
||||
{
|
||||
VariableDefinition variableDef = new VariableDefinition(variableTypeRef);
|
||||
methodDef.Body.Variables.Add(variableDef);
|
||||
return variableDef;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a variable type within the body and returns it's VariableDef.
|
||||
/// </summary>
|
||||
internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, CodegenSession session, System.Type variableType)
|
||||
{
|
||||
return CreateVariable(methodDef, session.GetClass<GeneralHelper>().GetTypeReference(variableType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 999d4ae4862274f4ba50569c221976dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,155 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Rocks;
|
||||
using System;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class MethodReferenceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes a generic method with specified arguments.
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <param name="genericArguments"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes a generic method with the same arguments as the original.
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method reference for a generic method.
|
||||
/// </summary>
|
||||
public static MethodReference GetMethodReference(this MethodReference mr, CodegenSession session, TypeReference typeReference)
|
||||
{
|
||||
return mr.GetMethodReference(session, new TypeReference[] { typeReference });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a method reference for a generic method.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Resolve favoring cached results first.
|
||||
/// </summary>
|
||||
internal static MethodDefinition CachedResolve(this MethodReference methodRef, CodegenSession session)
|
||||
{
|
||||
return session.GetClass<GeneralHelper>().GetMethodReferenceResolve(methodRef);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <para> Note that calling ArraySegment`T.get_Count directly gives an invalid IL error </para>
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="instanceType"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <para> Note that calling ArraySegment`T.get_Count directly gives an invalid IL error </para>
|
||||
/// </summary>
|
||||
/// <param name="self"></param>
|
||||
/// <param name="instanceType"></param>
|
||||
/// <returns></returns>
|
||||
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<T>(this MethodReference method, string name)
|
||||
{
|
||||
return method.DeclaringType.Is<T>() && method.Name == name;
|
||||
}
|
||||
public static bool Is<T>(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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee1c15a06ab386e439ec5aa41e3496f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a class within a module.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <returns></returns>
|
||||
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<Action> expression)
|
||||
{
|
||||
return ImportReference(moduleDef, (LambdaExpression)expression);
|
||||
}
|
||||
public static MethodReference ImportReference<T>(this ModuleDefinition module, Expression<Action<T>> 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<object>
|
||||
methodInfo = methodInfo ?? newExpression.Type.GetConstructors()[0];
|
||||
return module.ImportReference(methodInfo);
|
||||
}
|
||||
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
var property = memberExpression.Member as PropertyInfo;
|
||||
return module.ImportReference(property.GetMethod);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid Expression {expression.Body.GetType()}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42648785493390646898f5fa13e1dfd6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,24 @@
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class ParameterDefinitionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns if parameterDef is Type.
|
||||
/// </summary>
|
||||
/// <param name="parameterDef"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Is(this ParameterDefinition parameterDef, Type type)
|
||||
{
|
||||
return parameterDef.ParameterType.FullName == type.FullName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31071055a2e388141b8f11e1ba4e147e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,521 @@
|
||||
using FishNet.CodeGenerating.Extension;
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
|
||||
internal static class TypeDefinitionExtensionsOld
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates a GenericInstanceType and adds parameters.
|
||||
/// </summary>
|
||||
internal static GenericInstanceType CreateGenericInstanceType(this TypeDefinition type, Collection<GenericParameter> parameters)
|
||||
{
|
||||
GenericInstanceType git = new GenericInstanceType(type);
|
||||
foreach (GenericParameter gp in parameters)
|
||||
git.GenericArguments.Add(gp);
|
||||
|
||||
return git;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds public fields in type and base type
|
||||
/// </summary>
|
||||
/// <param name="variable"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<FieldDefinition> FindAllPublicFields(this TypeDefinition typeDef, CodegenSession session
|
||||
, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
|
||||
GeneralHelper gh = session.GetClass<GeneralHelper>();
|
||||
while (typeDef != null)
|
||||
{
|
||||
if (IsExcluded(typeDef, excludedBaseTypes, excludedAssemblyPrefixes))
|
||||
break;
|
||||
|
||||
foreach (FieldDefinition fd in typeDef.Fields)
|
||||
{
|
||||
if (fd.IsStatic)
|
||||
continue;
|
||||
if (fd.IsNotSerialized)
|
||||
continue;
|
||||
if (gh.CodegenExclude(fd))
|
||||
continue;
|
||||
if (fd.IsPrivate)
|
||||
continue;
|
||||
|
||||
yield return fd;
|
||||
}
|
||||
|
||||
try { typeDef = typeDef.BaseType?.CachedResolve(session); }
|
||||
catch { break; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds public properties on typeDef and all base types which have a public get/set accessor.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyDefinition> FindAllPublicProperties(this TypeDefinition typeDef, CodegenSession session
|
||||
, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
GeneralHelper gh = session.GetClass<GeneralHelper>();
|
||||
while (typeDef != null)
|
||||
{
|
||||
if (IsExcluded(typeDef, excludedBaseTypes, excludedAssemblyPrefixes))
|
||||
break;
|
||||
|
||||
foreach (PropertyDefinition pd in typeDef.Properties)
|
||||
{
|
||||
//Missing get or set method.
|
||||
if (pd.GetMethod == null || pd.SetMethod == null)
|
||||
continue;
|
||||
if (gh.CodegenExclude(pd))
|
||||
continue;
|
||||
if (pd.GetMethod.IsPrivate)
|
||||
continue;
|
||||
if (pd.SetMethod.IsPrivate)
|
||||
continue;
|
||||
if (pd.GetMethod.ReturnType.IsGenericParameter)
|
||||
continue;
|
||||
|
||||
yield return pd;
|
||||
}
|
||||
|
||||
try { typeDef = typeDef.BaseType?.CachedResolve(session); }
|
||||
catch { break; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is excluded.
|
||||
/// </summary>
|
||||
private static bool IsExcluded(TypeDefinition typeDef, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
if (excludedBaseTypes != null)
|
||||
{
|
||||
foreach (System.Type t in excludedBaseTypes)
|
||||
{
|
||||
if (typeDef.FullName == t.FullName)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (excludedAssemblyPrefixes != null)
|
||||
{
|
||||
foreach (string s in excludedAssemblyPrefixes)
|
||||
{
|
||||
int len = s.Length;
|
||||
string tdAsmName = typeDef.Module.Assembly.FullName;
|
||||
if (tdAsmName.Length >= len && tdAsmName.Substring(0, len).ToLower() == s.ToLower())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Fall through, not excluded.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is excluded.
|
||||
/// </summary>
|
||||
public static bool IsExcluded(this TypeDefinition typeDef, string excludedAssemblyPrefix)
|
||||
{
|
||||
|
||||
int len = excludedAssemblyPrefix.Length;
|
||||
string tdAsmName = typeDef.Module.Assembly.FullName;
|
||||
if (tdAsmName.Length >= len && tdAsmName.Substring(0, len).ToLower() == excludedAssemblyPrefix.ToLower())
|
||||
return true;
|
||||
|
||||
//Fall through, not excluded.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef or any of it's parents inherit from NetworkBehaviour.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool InheritsNetworkBehaviour(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
string nbFullName = session.GetClass<NetworkBehaviourHelper>().FullName;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
while (copyTd != null)
|
||||
{
|
||||
if (copyTd.FullName == nbFullName)
|
||||
return true;
|
||||
|
||||
copyTd = copyTd.GetNextBaseTypeDefinition(session);
|
||||
}
|
||||
|
||||
//Fall through, network behaviour not found.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a nested TypeDefinition of name.
|
||||
/// </summary>
|
||||
internal static TypeDefinition GetNestedType(this TypeDefinition typeDef, string name)
|
||||
{
|
||||
foreach (TypeDefinition nestedTd in typeDef.NestedTypes)
|
||||
{
|
||||
if (nestedTd.Name == name)
|
||||
return nestedTd;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the BaseType for TypeDef exist and is not NetworkBehaviour,
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool CanProcessBaseType(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
return (typeDef != null && typeDef.BaseType != null && typeDef.BaseType.FullName != session.GetClass<NetworkBehaviourHelper>().FullName);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns if the BaseType for TypeDef exist and is not NetworkBehaviour,
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static TypeDefinition GetNextBaseClassToProcess(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
if (typeDef.BaseType != null && typeDef.BaseType.FullName != session.GetClass<NetworkBehaviourHelper>().FullName)
|
||||
return typeDef.BaseType.CachedResolve(session);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static TypeDefinition GetLastBaseClass(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
TypeDefinition copyTd = typeDef;
|
||||
while (copyTd.BaseType != null)
|
||||
copyTd = copyTd.BaseType.CachedResolve(session);
|
||||
|
||||
return copyTd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a type in current and inherited types.
|
||||
/// </summary>
|
||||
internal static TypeDefinition GetClassInInheritance(this TypeDefinition typeDef, CodegenSession session, string typeFullName)
|
||||
{
|
||||
TypeDefinition copyTd = typeDef;
|
||||
do
|
||||
{
|
||||
if (copyTd.FullName == typeFullName)
|
||||
return copyTd;
|
||||
|
||||
if (copyTd.BaseType != null)
|
||||
copyTd = copyTd.BaseType.CachedResolve(session);
|
||||
else
|
||||
copyTd = null;
|
||||
|
||||
} while (copyTd != null);
|
||||
|
||||
//Not found.
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a type in current and inherited types.
|
||||
/// </summary>
|
||||
internal static TypeDefinition GetClassInInheritance(this TypeDefinition typeDef, CodegenSession session, TypeDefinition targetTypeDef)
|
||||
{
|
||||
if (typeDef == null)
|
||||
return null;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
do
|
||||
{
|
||||
if (copyTd == targetTypeDef)
|
||||
return copyTd;
|
||||
|
||||
if (copyTd.BaseType != null)
|
||||
copyTd = copyTd.BaseType.CachedResolve(session);
|
||||
else
|
||||
copyTd = null;
|
||||
|
||||
} while (copyTd != null);
|
||||
|
||||
//Not found.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is static (abstract, sealed).
|
||||
/// </summary>
|
||||
internal static bool IsStatic(this TypeDefinition typeDef)
|
||||
{
|
||||
//Combining flags in a single check some reason doesn't work right with HasFlag.
|
||||
return (typeDef.Attributes.HasFlag(TypeAttributes.Abstract) && typeDef.Attributes.HasFlag(TypeAttributes.Sealed));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enum underlying type for typeDef.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static TypeReference GetEnumUnderlyingTypeReference(this TypeDefinition typeDef)
|
||||
{
|
||||
foreach (FieldDefinition field in typeDef.Fields)
|
||||
{
|
||||
if (!field.IsStatic)
|
||||
return field.FieldType;
|
||||
}
|
||||
throw new ArgumentException($"Invalid enum {typeDef.FullName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is derived from type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool InheritsFrom<T>(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
return typeDef.InheritsFrom(session, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is derived from type.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool InheritsFrom(this TypeDefinition typeDef, CodegenSession session, Type type)
|
||||
{
|
||||
if (!typeDef.IsClass)
|
||||
return false;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
while (copyTd.BaseType != null)
|
||||
{
|
||||
if (copyTd.BaseType.IsType(type))
|
||||
return true;
|
||||
|
||||
copyTd = copyTd.GetNextBaseTypeDefinition(session);
|
||||
}
|
||||
|
||||
//Fall through.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a method to typeDef.
|
||||
/// </summary>
|
||||
/// <param name="typDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="attributes"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition AddMethod(this TypeDefinition typDef, string methodName, MethodAttributes attributes)
|
||||
{
|
||||
return AddMethod(typDef, methodName, attributes, typDef.Module.ImportReference(typeof(void)));
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a method to typeDef.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="attributes"></param>
|
||||
/// <param name="typeReference"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition AddMethod(this TypeDefinition typeDef, string methodName, MethodAttributes attributes, TypeReference typeReference)
|
||||
{
|
||||
var method = new MethodDefinition(methodName, attributes, typeReference);
|
||||
typeDef.Methods.Add(method);
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds the first method by a given name.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition GetMethod(this TypeDefinition typeDef, string methodName)
|
||||
{
|
||||
return typeDef.Methods.FirstOrDefault(method => method.Name == methodName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the first method by a given name.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition GetMethod(this TypeDefinition typeDef, string methodName, Type[] types)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a type is a subclass of another.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="ClassTypeFullName"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool IsSubclassOf(this TypeDefinition typeDef,CodegenSession session, string ClassTypeFullName)
|
||||
{
|
||||
if (!typeDef.IsClass) return false;
|
||||
|
||||
TypeReference baseTypeRef = typeDef.BaseType;
|
||||
while (baseTypeRef != null)
|
||||
{
|
||||
if (baseTypeRef.FullName == ClassTypeFullName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
baseTypeRef = baseTypeRef.CachedResolve(session).BaseType;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a field reference by name.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public static FieldReference GetFieldReference(this TypeDefinition typeDef, string fieldName, CodegenSession session)
|
||||
{
|
||||
if (typeDef.HasFields)
|
||||
{
|
||||
for (int i = 0; i < typeDef.Fields.Count; i++)
|
||||
{
|
||||
if (typeDef.Fields[i].Name == fieldName)
|
||||
return session.ImportReference(typeDef.Fields[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterface<TInterface>(this TypeDefinition typeDef)
|
||||
{
|
||||
for (int i = 0; i < typeDef.Interfaces.Count; i++)
|
||||
{
|
||||
if (typeDef.Interfaces[i].InterfaceType.Is<TInterface>())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterface(this TypeDefinition typeDef, string interfaceName)
|
||||
{
|
||||
for (int i = 0; i < typeDef.Interfaces.Count; i++)
|
||||
{
|
||||
if (typeDef.Interfaces[i].InterfaceType.FullName == interfaceName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterfaceRecursive<T>(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
TypeDefinition climbTypeDef = typeDef;
|
||||
|
||||
while (climbTypeDef != null)
|
||||
{
|
||||
if (climbTypeDef.Interfaces.Any(i => i.InterfaceType.Is<T>()))
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
if (climbTypeDef.BaseType != null)
|
||||
climbTypeDef = climbTypeDef.BaseType.CachedResolve(session);
|
||||
else
|
||||
climbTypeDef = null;
|
||||
}
|
||||
//Could not resolve assembly; can happen for assemblies being checked outside FishNet/csharp.
|
||||
catch (AssemblyResolutionException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterfaceRecursive(this TypeDefinition typeDef, CodegenSession session, string interfaceName)
|
||||
{
|
||||
TypeDefinition climbTypeDef = typeDef;
|
||||
|
||||
while (climbTypeDef != null)
|
||||
{
|
||||
if (climbTypeDef.Interfaces.Any(i => i.InterfaceType.FullName == interfaceName))
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
if (climbTypeDef.BaseType != null)
|
||||
climbTypeDef = climbTypeDef.BaseType.CachedResolve(session);
|
||||
else
|
||||
climbTypeDef = null;
|
||||
}
|
||||
//Could not resolve assembly; can happen for assemblies being checked outside FishNet/csharp.
|
||||
catch (AssemblyResolutionException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 645e49fe7eeff3a4e9eb65d77fc6e2ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,138 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Rocks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class TypeReferenceExtensionsOld
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Resolve favoring cached results first.
|
||||
/// </summary>
|
||||
internal static TypeDefinition CachedResolve(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
return session.GetClass<GeneralHelper>().GetTypeReferenceResolve(typeRef);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeRef is a class or struct.
|
||||
/// </summary>
|
||||
internal static bool IsClassOrStruct(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
TypeDefinition typeDef = typeRef.CachedResolve(session);
|
||||
return (!typeDef.IsPrimitive && !typeDef.IsEnum && (typeDef.IsClass || typeDef.IsValueType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all properties on typeRef and all base types which have a public get/set accessor.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyDefinition> FindAllSerializableProperties(this TypeReference typeRef, CodegenSession session, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
return typeRef.CachedResolve(session).FindAllPublicProperties(session, excludedBaseTypes, excludedAssemblyPrefixes);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all public fields in typeRef and base type.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<FieldDefinition> FindAllSerializableFields(this TypeReference typeRef, CodegenSession session,
|
||||
System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
return typeRef.Resolve().FindAllPublicFields(session, excludedBaseTypes, excludedAssemblyPrefixes);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a typeRef is type.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsType(this TypeReference typeRef, Type type)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
return typeRef.GetElementType().FullName == type.FullName;
|
||||
else
|
||||
return typeRef.FullName == type.FullName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeRef is a multidimensional array.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsMultidimensionalArray(this TypeReference typeRef)
|
||||
{
|
||||
return typeRef is ArrayType arrayType && arrayType.Rank > 1;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeRef can be resolved.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool CanBeResolved(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
while (typeRef != null)
|
||||
{
|
||||
if (typeRef.Scope.Name == "Windows")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeRef.Scope.Name == "mscorlib")
|
||||
{
|
||||
TypeDefinition resolved = typeRef.CachedResolve(session);
|
||||
return resolved != null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
typeRef = typeRef.CachedResolve(session).BaseType;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a generic type out of another type, if needed.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static TypeReference ConvertToGenericIfNeeded(this TypeDefinition type)
|
||||
{
|
||||
if (type.HasGenericParameters)
|
||||
{
|
||||
// get all the generic parameters and make a generic instance out of it
|
||||
TypeReference[] genericTypes = new TypeReference[type.GenericParameters.Count];
|
||||
for (int i = 0; i < type.GenericParameters.Count; i++)
|
||||
{
|
||||
genericTypes[i] = type.GenericParameters[i].GetElementType();
|
||||
}
|
||||
|
||||
return type.MakeGenericInstanceType(genericTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2344f5ab0fda07b498c03fbe0e082c14
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1412
Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs
Normal file
1412
Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6139ff104f3c24442b26dbc4e40d5ce5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1 @@
|
||||
//Remove on 2024/01/01
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8bc93cce5d44d604c805976e696dd7da
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1 @@
|
||||
//Remove on 2024/01/01
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcb8399b7678ff1429b6e211e6f26d10
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
443
Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs
Normal file
443
Assets/FishNet/CodeGenerating/Helpers/NetworkBehaviourHelper.cs
Normal file
@ -0,0 +1,443 @@
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using FishNet.CodeGenerating.Processing;
|
||||
using FishNet.Configuring;
|
||||
using FishNet.Managing.Logging;
|
||||
using FishNet.Object;
|
||||
using FishNet.Object.Delegating;
|
||||
using FishNet.Object.Helping;
|
||||
using FishNet.Object.Prediction.Delegating;
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class NetworkBehaviourHelper : CodegenBase
|
||||
{
|
||||
#region Reflection references.
|
||||
//Names.
|
||||
internal string FullName;
|
||||
//Prediction.
|
||||
public string ClearReplicateCache_Method_Name = nameof(NetworkBehaviour.ClearReplicateCache_Internal);
|
||||
public MethodReference Replicate_Server_MethodRef;
|
||||
public MethodReference Replicate_Client_MethodRef;
|
||||
public MethodReference Replicate_Reader_MethodRef;
|
||||
public MethodReference Replicate_ExitEarly_A_MethodRef;
|
||||
public MethodReference Reconcile_ExitEarly_A_MethodRef;
|
||||
public MethodReference Reconcile_Server_MethodRef;
|
||||
public MethodReference Reconcile_Client_MethodRef;
|
||||
public MethodReference Reconcile_Reader_MethodRef;
|
||||
public MethodReference RegisterReplicateRpc_MethodRef;
|
||||
public MethodReference RegisterReconcileRpc_MethodRef;
|
||||
public MethodReference ReplicateRpcDelegateConstructor_MethodRef;
|
||||
public MethodReference ReconcileRpcDelegateConstructor_MethodRef;
|
||||
//RPCs.
|
||||
public MethodReference SendServerRpc_MethodRef;
|
||||
public MethodReference SendObserversRpc_MethodRef;
|
||||
public MethodReference SendTargetRpc_MethodRef;
|
||||
public MethodReference DirtySyncType_MethodRef;
|
||||
public MethodReference RegisterServerRpc_MethodRef;
|
||||
public MethodReference RegisterObserversRpc_MethodRef;
|
||||
public MethodReference RegisterTargetRpc_MethodRef;
|
||||
public MethodReference ServerRpcDelegateConstructor_MethodRef;
|
||||
public MethodReference ClientRpcDelegateConstructor_MethodRef;
|
||||
//Is checks.
|
||||
public MethodReference IsClient_MethodRef;
|
||||
public MethodReference IsOwner_MethodRef;
|
||||
public MethodReference IsServer_MethodRef;
|
||||
public MethodReference IsHost_MethodRef;
|
||||
//Misc.
|
||||
public TypeReference TypeRef;
|
||||
public MethodReference OwnerMatches_MethodRef;
|
||||
public MethodReference LocalConnection_MethodRef;
|
||||
public MethodReference Owner_MethodRef;
|
||||
public MethodReference ReadSyncVar_MethodRef;
|
||||
public MethodReference NetworkInitializeIfDisabled_MethodRef;
|
||||
//TimeManager.
|
||||
public MethodReference TimeManager_MethodRef;
|
||||
#endregion
|
||||
|
||||
#region Const.
|
||||
internal const uint MAX_RPC_ALLOWANCE = ushort.MaxValue;
|
||||
internal const string AWAKE_METHOD_NAME = "Awake";
|
||||
internal const string DISABLE_LOGGING_TEXT = "This message may be disabled by setting the Logging field in your attribute to LoggingType.Off";
|
||||
#endregion
|
||||
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
Type networkBehaviourType = typeof(NetworkBehaviour);
|
||||
TypeRef = base.ImportReference(networkBehaviourType);
|
||||
FullName = networkBehaviourType.FullName;
|
||||
base.ImportReference(networkBehaviourType);
|
||||
|
||||
//ServerRpcDelegate and ClientRpcDelegate constructors.
|
||||
ServerRpcDelegateConstructor_MethodRef = base.ImportReference(typeof(ServerRpcDelegate).GetConstructors().First());
|
||||
ClientRpcDelegateConstructor_MethodRef = base.ImportReference(typeof(ClientRpcDelegate).GetConstructors().First());
|
||||
//Prediction Rpc delegate constructors.
|
||||
ReplicateRpcDelegateConstructor_MethodRef = base.ImportReference(typeof(ReplicateRpcDelegate).GetConstructors().First());
|
||||
ReconcileRpcDelegateConstructor_MethodRef = base.ImportReference(typeof(ReconcileRpcDelegate).GetConstructors().First());
|
||||
|
||||
foreach (MethodInfo mi in networkBehaviourType.GetMethods((BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)))
|
||||
{
|
||||
//CreateDelegates.
|
||||
if (mi.Name == nameof(NetworkBehaviour.RegisterServerRpc_Internal))
|
||||
RegisterServerRpc_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.RegisterObserversRpc_Internal))
|
||||
RegisterObserversRpc_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.RegisterTargetRpc_Internal))
|
||||
RegisterTargetRpc_MethodRef = base.ImportReference(mi);
|
||||
//SendPredictions.
|
||||
else if (mi.Name == nameof(NetworkBehaviour.RegisterReplicateRpc_Internal))
|
||||
RegisterReplicateRpc_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.RegisterReconcileRpc_Internal))
|
||||
RegisterReconcileRpc_MethodRef = base.ImportReference(mi);
|
||||
//SendRpcs.
|
||||
else if (mi.Name == nameof(NetworkBehaviour.SendServerRpc_Internal))
|
||||
SendServerRpc_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.SendObserversRpc_Internal))
|
||||
SendObserversRpc_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.SendTargetRpc_Internal))
|
||||
SendTargetRpc_MethodRef = base.ImportReference(mi);
|
||||
//Prediction.
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Replicate_ExitEarly_A_Internal))
|
||||
Replicate_ExitEarly_A_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Replicate_Server_Internal))
|
||||
Replicate_Server_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Replicate_Reader_Internal))
|
||||
Replicate_Reader_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Reconcile_Reader_Internal))
|
||||
Reconcile_Reader_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Reconcile_ExitEarly_A_Internal))
|
||||
Reconcile_ExitEarly_A_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Reconcile_Server_Internal))
|
||||
Reconcile_Server_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Replicate_Client_Internal))
|
||||
Replicate_Client_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.Reconcile_Client_Internal))
|
||||
Reconcile_Client_MethodRef = base.ImportReference(mi);
|
||||
//Misc.
|
||||
else if (mi.Name == nameof(NetworkBehaviour.OwnerMatches))
|
||||
OwnerMatches_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.ReadSyncVar))
|
||||
ReadSyncVar_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.DirtySyncType))
|
||||
DirtySyncType_MethodRef = base.ImportReference(mi);
|
||||
else if (mi.Name == nameof(NetworkBehaviour.NetworkInitializeIfDisabled))
|
||||
NetworkInitializeIfDisabled_MethodRef = base.ImportReference(mi);
|
||||
}
|
||||
|
||||
foreach (PropertyInfo pi in networkBehaviourType.GetProperties((BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)))
|
||||
{
|
||||
//Server/Client states.
|
||||
if (pi.Name == nameof(NetworkBehaviour.IsClient))
|
||||
IsClient_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
else if (pi.Name == nameof(NetworkBehaviour.IsServer))
|
||||
IsServer_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
else if (pi.Name == nameof(NetworkBehaviour.IsHost))
|
||||
IsHost_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
else if (pi.Name == nameof(NetworkBehaviour.IsOwner))
|
||||
IsOwner_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
//Owner.
|
||||
else if (pi.Name == nameof(NetworkBehaviour.Owner))
|
||||
Owner_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
else if (pi.Name == nameof(NetworkBehaviour.LocalConnection))
|
||||
LocalConnection_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
//Misc.
|
||||
else if (pi.Name == nameof(NetworkBehaviour.TimeManager))
|
||||
TimeManager_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returnsthe child most Awake by iterating up childMostTypeDef.
|
||||
/// </summary>
|
||||
/// <param name="childMostTypeDef"></param>
|
||||
/// <param name="created"></param>
|
||||
/// <returns></returns>
|
||||
internal MethodDefinition GetAwakeMethodDefinition(TypeDefinition typeDef)
|
||||
{
|
||||
return typeDef.GetMethod(AWAKE_METHOD_NAME);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a replicate delegate.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="originalMethodDef"></param>
|
||||
/// <param name="readerMethodDef"></param>
|
||||
/// <param name="rpcType"></param>
|
||||
internal void CreateReplicateDelegate(MethodDefinition originalMethodDef, MethodDefinition readerMethodDef, uint methodHash)
|
||||
{
|
||||
MethodDefinition methodDef = originalMethodDef.DeclaringType.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME);
|
||||
ILProcessor processor = methodDef.Body.GetILProcessor();
|
||||
|
||||
List<Instruction> insts = new List<Instruction>();
|
||||
insts.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
|
||||
insts.Add(processor.Create(OpCodes.Ldc_I4, (int)methodHash));
|
||||
|
||||
/* Create delegate and call NetworkBehaviour method. */
|
||||
insts.Add(processor.Create(OpCodes.Ldnull));
|
||||
insts.Add(processor.Create(OpCodes.Ldftn, readerMethodDef));
|
||||
|
||||
/* Has to be done last. This allows the NetworkBehaviour to
|
||||
* initialize it's fields first. */
|
||||
processor.InsertLast(insts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a RPC delegate for rpcType.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="originalMethodDef"></param>
|
||||
/// <param name="readerMethodDef"></param>
|
||||
/// <param name="rpcType"></param>
|
||||
internal void CreateRpcDelegate(bool runLocally, TypeDefinition typeDef, MethodDefinition readerMethodDef, RpcType rpcType, uint methodHash, CustomAttribute rpcAttribute)
|
||||
{
|
||||
|
||||
|
||||
MethodDefinition methodDef = typeDef.GetMethod(NetworkBehaviourProcessor.NETWORKINITIALIZE_EARLY_INTERNAL_NAME);
|
||||
ILProcessor processor = methodDef.Body.GetILProcessor();
|
||||
|
||||
List<Instruction> insts = new List<Instruction>();
|
||||
insts.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
insts.Add(processor.Create(OpCodes.Ldc_I4, (int)methodHash));
|
||||
|
||||
/* Create delegate and call NetworkBehaviour method. */
|
||||
insts.Add(processor.Create(OpCodes.Ldarg_0));
|
||||
insts.Add(processor.Create(OpCodes.Ldftn, readerMethodDef));
|
||||
//Server.
|
||||
if (rpcType == RpcType.Server)
|
||||
{
|
||||
insts.Add(processor.Create(OpCodes.Newobj, ServerRpcDelegateConstructor_MethodRef));
|
||||
insts.Add(processor.Create(OpCodes.Call, RegisterServerRpc_MethodRef));
|
||||
}
|
||||
//Observers.
|
||||
else if (rpcType == RpcType.Observers)
|
||||
{
|
||||
insts.Add(processor.Create(OpCodes.Newobj, ClientRpcDelegateConstructor_MethodRef));
|
||||
insts.Add(processor.Create(OpCodes.Call, RegisterObserversRpc_MethodRef));
|
||||
}
|
||||
//Target
|
||||
else if (rpcType == RpcType.Target)
|
||||
{
|
||||
insts.Add(processor.Create(OpCodes.Newobj, ClientRpcDelegateConstructor_MethodRef));
|
||||
insts.Add(processor.Create(OpCodes.Call, RegisterTargetRpc_MethodRef));
|
||||
}
|
||||
|
||||
/* Has to be done last. This allows the NetworkBehaviour to
|
||||
* initialize it's fields first. */
|
||||
processor.InsertLast(insts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates exit method condition if local client is not owner.
|
||||
/// </summary>
|
||||
/// <param name="retIfOwner">True if to ret when owner, false to ret when not owner.</param>
|
||||
/// <returns>Returns Ret instruction.</returns>
|
||||
internal Instruction CreateLocalClientIsOwnerCheck(MethodDefinition methodDef, LoggingType loggingType, bool notifyMessageCanBeDisabled, bool retIfOwner, bool insertFirst)
|
||||
{
|
||||
List<Instruction> instructions = new List<Instruction>();
|
||||
/* This is placed after the if check.
|
||||
* Should the if check pass then code
|
||||
* jumps to this instruction. */
|
||||
ILProcessor processor = methodDef.Body.GetILProcessor();
|
||||
Instruction endIf = processor.Create(OpCodes.Nop);
|
||||
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0)); //argument: this
|
||||
//If !base.IsOwner endIf.
|
||||
instructions.Add(processor.Create(OpCodes.Call, IsOwner_MethodRef));
|
||||
if (retIfOwner)
|
||||
instructions.Add(processor.Create(OpCodes.Brfalse, endIf));
|
||||
else
|
||||
instructions.Add(processor.Create(OpCodes.Brtrue, endIf));
|
||||
//If logging is not disabled.
|
||||
if (loggingType != LoggingType.Off)
|
||||
{
|
||||
string disableLoggingText = (notifyMessageCanBeDisabled) ? DISABLE_LOGGING_TEXT : string.Empty;
|
||||
string msg = (retIfOwner) ?
|
||||
$"Cannot complete action because you are the owner of this object. {disableLoggingText}." :
|
||||
$"Cannot complete action because you are not the owner of this object. {disableLoggingText}.";
|
||||
|
||||
instructions.AddRange(base.GetClass<GeneralHelper>().LogMessage(methodDef, msg, loggingType));
|
||||
}
|
||||
//Return block.
|
||||
Instruction retInst = processor.Create(OpCodes.Ret);
|
||||
instructions.Add(retInst);
|
||||
//After if statement, jumped to when successful check.
|
||||
instructions.Add(endIf);
|
||||
|
||||
if (insertFirst)
|
||||
{
|
||||
processor.InsertFirst(instructions);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Instruction inst in instructions)
|
||||
processor.Append(inst);
|
||||
}
|
||||
|
||||
return retInst;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates exit method condition if remote client is not owner.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
internal Instruction CreateRemoteClientIsOwnerCheck(ILProcessor processor, ParameterDefinition connectionParameterDef)
|
||||
{
|
||||
/* This is placed after the if check.
|
||||
* Should the if check pass then code
|
||||
* jumps to this instruction. */
|
||||
Instruction endIf = processor.Create(OpCodes.Nop);
|
||||
|
||||
processor.Emit(OpCodes.Ldarg_0); //argument: this
|
||||
//If !base.IsOwner endIf.
|
||||
processor.Emit(OpCodes.Ldarg, connectionParameterDef);
|
||||
processor.Emit(OpCodes.Call, OwnerMatches_MethodRef);
|
||||
processor.Emit(OpCodes.Brtrue, endIf);
|
||||
//Return block.
|
||||
Instruction retInst = processor.Create(OpCodes.Ret);
|
||||
processor.Append(retInst);
|
||||
|
||||
//After if statement, jumped to when successful check.
|
||||
processor.Append(endIf);
|
||||
|
||||
return retInst;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates exit method condition if not client.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="retInstruction"></param>
|
||||
/// <param name="warn"></param>
|
||||
internal void CreateIsClientCheck(MethodDefinition methodDef, LoggingType loggingType, bool useStatic, bool insertFirst)
|
||||
{
|
||||
/* This is placed after the if check.
|
||||
* Should the if check pass then code
|
||||
* jumps to this instruction. */
|
||||
ILProcessor processor = methodDef.Body.GetILProcessor();
|
||||
Instruction endIf = processor.Create(OpCodes.Nop);
|
||||
|
||||
List<Instruction> instructions = new List<Instruction>();
|
||||
//Checking against the NetworkObject.
|
||||
if (!useStatic)
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0)); //argument: this
|
||||
//If (!base.IsClient)
|
||||
instructions.Add(processor.Create(OpCodes.Call, IsClient_MethodRef));
|
||||
}
|
||||
//Checking instanceFinder.
|
||||
else
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Call, base.GetClass<ObjectHelper>().InstanceFinder_IsClient_MethodRef));
|
||||
}
|
||||
instructions.Add(processor.Create(OpCodes.Brtrue, endIf));
|
||||
//If warning then also append warning text.
|
||||
if (loggingType != LoggingType.Off)
|
||||
{
|
||||
string msg = $"Cannot complete action because client is not active. This may also occur if the object is not yet initialized or if it does not contain a NetworkObject component. {DISABLE_LOGGING_TEXT}.";
|
||||
instructions.AddRange(base.GetClass<GeneralHelper>().LogMessage(methodDef, msg, loggingType));
|
||||
}
|
||||
//Add return.
|
||||
instructions.AddRange(CreateRetDefault(methodDef));
|
||||
//After if statement, jumped to when successful check.
|
||||
instructions.Add(endIf);
|
||||
|
||||
if (insertFirst)
|
||||
{
|
||||
processor.InsertFirst(instructions);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Instruction inst in instructions)
|
||||
processor.Append(inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates exit method condition if not server.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="warn"></param>
|
||||
internal void CreateIsServerCheck(MethodDefinition methodDef, LoggingType loggingType, bool useStatic, bool insertFirst)
|
||||
{
|
||||
/* This is placed after the if check.
|
||||
* Should the if check pass then code
|
||||
* jumps to this instruction. */
|
||||
ILProcessor processor = methodDef.Body.GetILProcessor();
|
||||
Instruction endIf = processor.Create(OpCodes.Nop);
|
||||
|
||||
List<Instruction> instructions = new List<Instruction>();
|
||||
if (!useStatic)
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Ldarg_0)); //argument: this
|
||||
//If (!base.IsServer)
|
||||
instructions.Add(processor.Create(OpCodes.Call, IsServer_MethodRef));
|
||||
}
|
||||
//Checking instanceFinder.
|
||||
else
|
||||
{
|
||||
instructions.Add(processor.Create(OpCodes.Call, base.GetClass<ObjectHelper>().InstanceFinder_IsServer_MethodRef));
|
||||
}
|
||||
instructions.Add(processor.Create(OpCodes.Brtrue, endIf));
|
||||
//If warning then also append warning text.
|
||||
if (loggingType != LoggingType.Off)
|
||||
{
|
||||
string msg = $"Cannot complete action because server is not active. This may also occur if the object is not yet initialized or if it does not contain a NetworkObject component. {DISABLE_LOGGING_TEXT}";
|
||||
instructions.AddRange(base.GetClass<GeneralHelper>().LogMessage(methodDef, msg, loggingType));
|
||||
}
|
||||
//Add return.
|
||||
instructions.AddRange(CreateRetDefault(methodDef));
|
||||
//After if statement, jumped to when successful check.
|
||||
instructions.Add(endIf);
|
||||
|
||||
if (insertFirst)
|
||||
{
|
||||
processor.InsertFirst(instructions);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Instruction inst in instructions)
|
||||
processor.Append(inst);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a return using the ReturnType for methodDef.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="methodDef"></param>
|
||||
/// <returns></returns>
|
||||
public List<Instruction> CreateRetDefault(MethodDefinition methodDef, ModuleDefinition importReturnModule = null)
|
||||
{
|
||||
ILProcessor processor = methodDef.Body.GetILProcessor();
|
||||
List<Instruction> instructions = new List<Instruction>();
|
||||
//If requires a value return.
|
||||
if (methodDef.ReturnType != methodDef.Module.TypeSystem.Void)
|
||||
{
|
||||
//Import type first.
|
||||
methodDef.Module.ImportReference(methodDef.ReturnType);
|
||||
if (importReturnModule != null)
|
||||
importReturnModule.ImportReference(methodDef.ReturnType);
|
||||
VariableDefinition vd = base.GetClass<GeneralHelper>().CreateVariable(methodDef, methodDef.ReturnType);
|
||||
instructions.Add(processor.Create(OpCodes.Ldloca_S, vd));
|
||||
instructions.Add(processor.Create(OpCodes.Initobj, vd.VariableType));
|
||||
instructions.Add(processor.Create(OpCodes.Ldloc, vd));
|
||||
}
|
||||
instructions.Add(processor.Create(OpCodes.Ret));
|
||||
|
||||
return instructions;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c42e06349d6890459a155a2afe17d41
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1 @@
|
||||
//Remove on 2023/06/01
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bcbcb288008d6da4eab7a5279dd6b4f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,42 @@
|
||||
using FishNet.Connection;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class NetworkConnectionImports : CodegenBase
|
||||
{
|
||||
#region Reflection references.
|
||||
//Names.
|
||||
internal string FullName;
|
||||
public MethodReference IsLocalClient_Get_MethodRef;
|
||||
#endregion
|
||||
|
||||
#region Const.
|
||||
internal const uint MAX_RPC_ALLOWANCE = ushort.MaxValue;
|
||||
internal const string AWAKE_METHOD_NAME = "Awake";
|
||||
internal const string DISABLE_LOGGING_TEXT = "This message may be disabled by setting the Logging field in your attribute to LoggingType.Off";
|
||||
#endregion
|
||||
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
Type type = typeof(NetworkConnection);
|
||||
base.ImportReference(type);
|
||||
|
||||
FullName = type.FullName;
|
||||
|
||||
foreach (PropertyInfo pi in type.GetProperties())
|
||||
{
|
||||
if (pi.Name == nameof(NetworkConnection.IsLocalClient))
|
||||
{
|
||||
IsLocalClient_Get_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d061dda8ed87ed48a08020942ad63f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
94
Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs
Normal file
94
Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using FishNet.Connection;
|
||||
using FishNet.Object;
|
||||
using FishNet.Object.Synchronizing;
|
||||
using FishNet.Object.Synchronizing.Internal;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class ObjectHelper : CodegenBase
|
||||
{
|
||||
#region Reflection references.
|
||||
//Fullnames.
|
||||
public string SyncList_Name;
|
||||
public string SyncDictionary_Name;
|
||||
public string SyncHashSet_Name;
|
||||
//Is checks.
|
||||
public MethodReference InstanceFinder_IsServer_MethodRef;
|
||||
public MethodReference InstanceFinder_IsClient_MethodRef;
|
||||
//Misc.
|
||||
public TypeReference NetworkBehaviour_TypeRef;
|
||||
public MethodReference NetworkConnection_IsValid_MethodRef;
|
||||
public MethodReference NetworkConnection_IsActive_MethodRef;
|
||||
public MethodReference Dictionary_Add_UShort_SyncBase_MethodRef;
|
||||
public MethodReference NetworkConnection_GetIsLocalClient_MethodRef;
|
||||
#endregion
|
||||
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
Type tmpType;
|
||||
/* SyncObject names. */
|
||||
//SyncList.
|
||||
tmpType = typeof(SyncList<>);
|
||||
base.ImportReference(tmpType);
|
||||
SyncList_Name = tmpType.Name;
|
||||
//SyncDictionary.
|
||||
tmpType = typeof(SyncDictionary<,>);
|
||||
base.ImportReference(tmpType);
|
||||
SyncDictionary_Name = tmpType.Name;
|
||||
//SyncHashSet.
|
||||
tmpType = typeof(SyncHashSet<>);
|
||||
base.ImportReference(tmpType);
|
||||
SyncHashSet_Name = tmpType.Name;
|
||||
|
||||
NetworkBehaviour_TypeRef = base.ImportReference(typeof(NetworkBehaviour));
|
||||
|
||||
tmpType = typeof(NetworkConnection);
|
||||
TypeReference networkConnectionTr = base.ImportReference(tmpType);
|
||||
foreach (PropertyDefinition item in networkConnectionTr.CachedResolve(base.Session).Properties)
|
||||
{
|
||||
if (item.Name == nameof(NetworkConnection.IsLocalClient))
|
||||
NetworkConnection_GetIsLocalClient_MethodRef = base.ImportReference(item.GetMethod);
|
||||
}
|
||||
|
||||
//Dictionary.Add(ushort, SyncBase).
|
||||
Type dictType = typeof(Dictionary<ushort, SyncBase>);
|
||||
TypeReference dictTypeRef = base.ImportReference(dictType);
|
||||
//Dictionary_Add_UShort_SyncBase_MethodRef = dictTypeRef.CachedResolve(base.Session).GetMethod("add_Item", )
|
||||
foreach (MethodDefinition item in dictTypeRef.CachedResolve(base.Session).Methods)
|
||||
{
|
||||
if (item.Name == nameof(Dictionary<ushort, SyncBase>.Add))
|
||||
{
|
||||
Dictionary_Add_UShort_SyncBase_MethodRef = base.ImportReference(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//InstanceFinder infos.
|
||||
Type instanceFinderType = typeof(InstanceFinder);
|
||||
foreach (PropertyInfo pi in instanceFinderType.GetProperties())
|
||||
{
|
||||
if (pi.Name == nameof(InstanceFinder.IsClient))
|
||||
InstanceFinder_IsClient_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
else if (pi.Name == nameof(InstanceFinder.IsServer))
|
||||
InstanceFinder_IsServer_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
}
|
||||
|
||||
//NetworkConnection.
|
||||
foreach (PropertyInfo pi in typeof(NetworkConnection).GetProperties((BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)))
|
||||
{
|
||||
if (pi.Name == nameof(NetworkConnection.IsValid))
|
||||
NetworkConnection_IsValid_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
else if (pi.Name == nameof(NetworkConnection.IsActive))
|
||||
NetworkConnection_IsActive_MethodRef = base.ImportReference(pi.GetMethod);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
11
Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/ObjectHelper.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 033da35314653aa4689b4582e7929295
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
117
Assets/FishNet/CodeGenerating/Helpers/PhysicsHelper.cs
Normal file
117
Assets/FishNet/CodeGenerating/Helpers/PhysicsHelper.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using FishNet.CodeGenerating.Extension;
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using FishNet.Connection;
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using SR = System.Reflection;
|
||||
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class PhysicsHelper : CodegenBase
|
||||
{
|
||||
#region Reflection references.
|
||||
public MethodReference GetScene_MethodRef;
|
||||
public MethodReference GetPhysicsScene2D_MethodRef;
|
||||
public MethodReference GetPhysicsScene3D_MethodRef;
|
||||
public MethodReference Physics3D_Simulate_MethodRef;
|
||||
public MethodReference Physics2D_Simulate_MethodRef;
|
||||
public MethodReference Physics3D_SyncTransforms_MethodRef;
|
||||
public MethodReference Physics2D_SyncTransforms_MethodRef;
|
||||
#endregion
|
||||
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
SR.MethodInfo locMi;
|
||||
//GetScene.
|
||||
locMi = typeof(GameObject).GetMethod("get_scene");
|
||||
GetScene_MethodRef = base.ImportReference(locMi);
|
||||
|
||||
//Physics.SyncTransform.
|
||||
foreach (SR.MethodInfo mi in typeof(Physics).GetMethods())
|
||||
{
|
||||
if (mi.Name == nameof(Physics.SyncTransforms))
|
||||
{
|
||||
Physics3D_SyncTransforms_MethodRef = base.ImportReference(mi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (SR.MethodInfo mi in typeof(Physics2D).GetMethods())
|
||||
{
|
||||
if (mi.Name == nameof(Physics2D.SyncTransforms))
|
||||
{
|
||||
Physics2D_SyncTransforms_MethodRef = base.ImportReference(mi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//PhysicsScene.Simulate.
|
||||
foreach (SR.MethodInfo mi in typeof(PhysicsScene).GetMethods())
|
||||
{
|
||||
if (mi.Name == nameof(PhysicsScene.Simulate))
|
||||
{
|
||||
Physics3D_Simulate_MethodRef = base.ImportReference(mi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (SR.MethodInfo mi in typeof(PhysicsScene2D).GetMethods())
|
||||
{
|
||||
if (mi.Name == nameof(PhysicsScene2D.Simulate))
|
||||
{
|
||||
Physics2D_Simulate_MethodRef = base.ImportReference(mi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//GetPhysicsScene.
|
||||
foreach (SR.MethodInfo mi in typeof(PhysicsSceneExtensions).GetMethods())
|
||||
{
|
||||
if (mi.Name == nameof(PhysicsSceneExtensions.GetPhysicsScene))
|
||||
{
|
||||
GetPhysicsScene3D_MethodRef = base.ImportReference(mi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (SR.MethodInfo mi in typeof(PhysicsSceneExtensions2D).GetMethods())
|
||||
{
|
||||
if (mi.Name == nameof(PhysicsSceneExtensions2D.GetPhysicsScene2D))
|
||||
{
|
||||
GetPhysicsScene2D_MethodRef = base.ImportReference(mi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns instructions to get a physics scene from a gameObject.
|
||||
/// </summary>
|
||||
public List<Instruction> GetPhysicsScene(MethodDefinition md, VariableDefinition gameObjectVd, bool threeDimensional)
|
||||
{
|
||||
ILProcessor processor = md.Body.GetILProcessor();
|
||||
return GetPhysicsScene(processor, gameObjectVd, threeDimensional);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns instructions to get a physics scene from a gameObject.
|
||||
/// </summary>
|
||||
public List<Instruction> GetPhysicsScene(ILProcessor processor, VariableDefinition gameObjectVd, bool threeDimensional)
|
||||
{
|
||||
List<Instruction> insts = new List<Instruction>();
|
||||
|
||||
//gameObject.scene.GetPhysics...
|
||||
insts.Add(processor.Create(OpCodes.Ldloc, gameObjectVd));
|
||||
insts.Add(processor.Create(GetScene_MethodRef.GetCallOpCode(base.Session), GetScene_MethodRef));
|
||||
if (threeDimensional)
|
||||
insts.Add(processor.Create(OpCodes.Call, GetPhysicsScene3D_MethodRef));
|
||||
else
|
||||
insts.Add(processor.Create(OpCodes.Call, GetPhysicsScene2D_MethodRef));
|
||||
|
||||
return insts;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/FishNet/CodeGenerating/Helpers/PhysicsHelper.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/PhysicsHelper.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28ae27f7bc8e89547a606262508fdd36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,15 @@
|
||||
using FishNet.Component.Prediction;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class PredictedObjectHelper : CodegenBase
|
||||
{
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9a06c812bf785a44a38a5852ff866d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1
Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs
Normal file
1
Assets/FishNet/CodeGenerating/Helpers/ReaderGenerator.cs
Normal file
@ -0,0 +1 @@
|
||||
//Remove on 2024/01/01
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8afc0f62ceeaee45aa496ba5650d010
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1
Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs
Normal file
1
Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs
Normal file
@ -0,0 +1 @@
|
||||
//Remove on 2024/01/01
|
11
Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/ReaderHelper.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07c42037569e53b4aa6701adefd3e063
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
71
Assets/FishNet/CodeGenerating/Helpers/ReaderImports.cs
Normal file
71
Assets/FishNet/CodeGenerating/Helpers/ReaderImports.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using FishNet.Connection;
|
||||
using FishNet.Serializing;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class ReaderImports : CodegenBase
|
||||
{
|
||||
#region Reflection references.
|
||||
public TypeReference PooledReader_TypeRef;
|
||||
public TypeReference Reader_TypeRef;
|
||||
public TypeReference NetworkConnection_TypeRef;
|
||||
public MethodReference PooledReader_ReadNetworkBehaviour_MethodRef;
|
||||
public MethodReference Reader_ReadPackedWhole_MethodRef;
|
||||
public MethodReference Reader_ReadDictionary_MethodRef;
|
||||
public MethodReference Reader_ReadList_MethodRef;
|
||||
public MethodReference Reader_ReadListCache_MethodRef;
|
||||
public MethodReference Reader_ReadArray_MethodRef;
|
||||
public TypeReference GenericReaderTypeRef;
|
||||
public TypeReference ReaderTypeRef;
|
||||
public MethodReference ReadSetMethodRef;
|
||||
public MethodReference ReadAutoPackSetMethodRef;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Imports references needed by this helper.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <returns></returns>
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
ReaderProcessor rp = base.GetClass<ReaderProcessor>();
|
||||
|
||||
PooledReader_TypeRef = base.ImportReference(typeof(PooledReader));
|
||||
Reader_TypeRef = base.ImportReference(typeof(Reader));
|
||||
NetworkConnection_TypeRef = base.ImportReference(typeof(NetworkConnection));
|
||||
|
||||
GenericReaderTypeRef = base.ImportReference(typeof(GenericReader<>));
|
||||
ReaderTypeRef = base.ImportReference(typeof(Reader));
|
||||
|
||||
System.Reflection.PropertyInfo readPropertyInfo;
|
||||
readPropertyInfo = typeof(GenericReader<>).GetProperty(nameof(GenericReader<int>.Read));
|
||||
ReadSetMethodRef = base.ImportReference(readPropertyInfo.GetSetMethod());
|
||||
readPropertyInfo = typeof(GenericReader<>).GetProperty(nameof(GenericReader<int>.ReadAutoPack));
|
||||
ReadAutoPackSetMethodRef = base.ImportReference(readPropertyInfo.GetSetMethod());
|
||||
|
||||
|
||||
Type pooledReaderType = typeof(PooledReader);
|
||||
foreach (MethodInfo methodInfo in pooledReaderType.GetMethods())
|
||||
{
|
||||
int parameterCount = methodInfo.GetParameters().Length;
|
||||
/* Special methods. */
|
||||
if (methodInfo.Name == nameof(PooledReader.ReadPackedWhole))
|
||||
Reader_ReadPackedWhole_MethodRef = base.ImportReference(methodInfo);
|
||||
//Relay readers.
|
||||
else if (parameterCount == 0 && methodInfo.Name == nameof(PooledReader.ReadDictionary))
|
||||
Reader_ReadDictionary_MethodRef = base.ImportReference(methodInfo);
|
||||
else if (parameterCount == 0 && methodInfo.Name == nameof(PooledReader.ReadListAllocated))
|
||||
Reader_ReadList_MethodRef = base.ImportReference(methodInfo);
|
||||
else if (parameterCount == 0 && methodInfo.Name == nameof(PooledReader.ReadListCacheAllocated))
|
||||
Reader_ReadListCache_MethodRef = base.ImportReference(methodInfo);
|
||||
else if (parameterCount == 0 && methodInfo.Name == nameof(PooledReader.ReadArrayAllocated))
|
||||
Reader_ReadArray_MethodRef = base.ImportReference(methodInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/FishNet/CodeGenerating/Helpers/ReaderImports.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/ReaderImports.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 350861dcbcbabc447acd37e4310b0697
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
22
Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs
Normal file
22
Assets/FishNet/CodeGenerating/Helpers/TimeManagerHelper.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using FishNet.Managing.Timing;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
|
||||
internal class TimeManagerHelper : CodegenBase
|
||||
{
|
||||
|
||||
#region Reflection references.
|
||||
#endregion
|
||||
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11dbcc0798e079e4a85fe98dfc9fe23a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
36
Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs
Normal file
36
Assets/FishNet/CodeGenerating/Helpers/TransportHelper.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using FishNet.Transporting;
|
||||
using MonoFN.Cecil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class TransportHelper : CodegenBase
|
||||
{
|
||||
#region Reflection references.
|
||||
internal TypeReference Channel_TypeRef;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Resets cached values.
|
||||
/// </summary>
|
||||
private void ResetValues()
|
||||
{
|
||||
Channel_TypeRef = null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Imports references needed by this helper.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <returns></returns>
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
ResetValues();
|
||||
|
||||
Channel_TypeRef = base.ImportReference(typeof(Channel));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ced44bfdb3068f4cb7513c9be85729a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/FishNet/CodeGenerating/Helpers/Typed.meta
Normal file
8
Assets/FishNet/CodeGenerating/Helpers/Typed.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 192c16e1ad7eca84cbcc19073c945ca9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
34
Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs
Normal file
34
Assets/FishNet/CodeGenerating/Helpers/Typed/Comparers.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using MonoFN.Cecil;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class TypeDefinitionComparer : IEqualityComparer<TypeDefinition>
|
||||
{
|
||||
public bool Equals(TypeDefinition a, TypeDefinition b)
|
||||
{
|
||||
return a.FullName == b.FullName;
|
||||
}
|
||||
|
||||
public int GetHashCode(TypeDefinition obj)
|
||||
{
|
||||
return obj.FullName.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class TypeReferenceComparer : IEqualityComparer<TypeReference>
|
||||
{
|
||||
public bool Equals(TypeReference a, TypeReference b)
|
||||
{
|
||||
return a.FullName == b.FullName;
|
||||
}
|
||||
|
||||
public int GetHashCode(TypeReference obj)
|
||||
{
|
||||
return obj.FullName.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b30600f0fdb27c4fb86c310b08f43b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,49 @@
|
||||
using MonoFN.Cecil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
|
||||
|
||||
|
||||
internal class CreatedSyncVar
|
||||
{
|
||||
public readonly TypeDefinition VariableTd;
|
||||
public readonly MethodReference GetValueMr;
|
||||
public readonly MethodReference SetValueMr;
|
||||
public readonly MethodReference SetSyncIndexMr;
|
||||
public readonly MethodReference ConstructorMr;
|
||||
public readonly GenericInstanceType SyncVarGit;
|
||||
public MethodReference HookMr;
|
||||
public CreatedSyncVar(GenericInstanceType syncVarGit, TypeDefinition variableTd, MethodReference getValueMr, MethodReference setValueMr, MethodReference setSyncIndexMr,MethodReference hookMr, MethodReference constructorMr)
|
||||
{
|
||||
SyncVarGit = syncVarGit;
|
||||
VariableTd = variableTd;
|
||||
GetValueMr = getValueMr;
|
||||
SetValueMr = setValueMr;
|
||||
SetSyncIndexMr = setSyncIndexMr;
|
||||
HookMr = hookMr;
|
||||
ConstructorMr = constructorMr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class CreatedSyncType
|
||||
{
|
||||
public TypeDefinition StubClassTypeDefinition;
|
||||
public MethodReference GetValueMethodReference;
|
||||
public MethodReference SetValueMethodReference;
|
||||
public MethodReference GetPreviousClientValueMethodReference;
|
||||
public MethodReference ReadMethodReference;
|
||||
public MethodReference ConstructorMethodReference;
|
||||
public CreatedSyncType(TypeDefinition stubClassTypeDef, MethodReference getMethodRef, MethodReference setMethodRef, MethodReference getPreviousMethodRef, MethodReference readMethodRef, MethodReference constructorMethodRef)
|
||||
{
|
||||
StubClassTypeDefinition = stubClassTypeDef;
|
||||
GetValueMethodReference = getMethodRef;
|
||||
SetValueMethodReference = setMethodRef;
|
||||
GetPreviousClientValueMethodReference = getPreviousMethodRef;
|
||||
ReadMethodReference = readMethodRef;
|
||||
ConstructorMethodReference = constructorMethodRef;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cae698c9bc732641892caabf04365dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
190
Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs
Normal file
190
Assets/FishNet/CodeGenerating/Helpers/Typed/GeneratorHelper.cs
Normal file
@ -0,0 +1,190 @@
|
||||
using FishNet.CodeGenerating.Extension;
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using FishNet.Object;
|
||||
using FishNet.Serializing.Helping;
|
||||
using FishNet.Utility.Performance;
|
||||
using MonoFN.Cecil;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
|
||||
|
||||
internal class GeneratorHelper : CodegenBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets what objectTypeRef will be serialized as.
|
||||
/// </summary>
|
||||
public SerializerType GetSerializerType(TypeReference objectTr, bool writer, out TypeDefinition objectTd)
|
||||
{
|
||||
string errorPrefix = (writer) ? "CreateWrite: " : "CreateRead: ";
|
||||
objectTd = null;
|
||||
|
||||
/* Check if already has a serializer. */
|
||||
if (writer)
|
||||
{
|
||||
if (base.GetClass<WriterProcessor>().GetWriteMethodReference(objectTr) != null)
|
||||
{
|
||||
base.LogError($"Writer already exist for {objectTr.FullName}.");
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (base.GetClass<ReaderProcessor>().GetReadMethodReference(objectTr) != null)
|
||||
{
|
||||
base.LogError($"Reader already exist for {objectTr.FullName}.");
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
objectTd = objectTr.CachedResolve(base.Session);
|
||||
//Invalid typeDef.
|
||||
if (objectTd == null)
|
||||
{
|
||||
base.LogError($"{errorPrefix}{objectTd.FullName} could not be resolved.");
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
//Intentionally excluded.
|
||||
if (objectTd.CustomAttributes.Count > 0)
|
||||
{
|
||||
foreach (CustomAttribute item in objectTd.CustomAttributes)
|
||||
{
|
||||
if (item.AttributeType.Is(typeof(CodegenExcludeAttribute)))
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
//By reference.
|
||||
if (objectTr.IsByReference)
|
||||
{
|
||||
base.LogError($"{errorPrefix}Cannot pass {objectTr.Name} by reference");
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
/* Arrays have to be processed first because it's possible for them to meet other conditions
|
||||
* below and be processed wrong. */
|
||||
else if (objectTr.IsArray)
|
||||
{
|
||||
if (objectTr.IsMultidimensionalArray())
|
||||
{
|
||||
base.LogError($"{errorPrefix}{objectTr.Name} is an unsupported type. Multidimensional arrays are not supported");
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SerializerType.Array;
|
||||
}
|
||||
}
|
||||
//Enum.
|
||||
else if (objectTd.IsEnum)
|
||||
{
|
||||
return SerializerType.Enum;
|
||||
}
|
||||
else if (objectTd.Is(typeof(Dictionary<,>)))
|
||||
{
|
||||
return SerializerType.Dictionary;
|
||||
}
|
||||
else if (objectTd.Is(typeof(List<>)))
|
||||
{
|
||||
return SerializerType.List;
|
||||
}
|
||||
else if (objectTd.Is(typeof(ListCache<>)))
|
||||
{
|
||||
return SerializerType.ListCache;
|
||||
}
|
||||
else if (objectTd.InheritsFrom<NetworkBehaviour>(base.Session))
|
||||
{
|
||||
return SerializerType.NetworkBehaviour;
|
||||
}
|
||||
else if (objectTr.IsNullable(base.Session))
|
||||
{
|
||||
GenericInstanceType git = objectTr as GenericInstanceType;
|
||||
if (git == null || git.GenericArguments.Count != 1)
|
||||
return SerializerType.Invalid;
|
||||
else
|
||||
return SerializerType.Nullable;
|
||||
}
|
||||
//Invalid type. This must be called after trying to generate everything but class.
|
||||
else if (!CanGenerateSerializer(objectTd))
|
||||
{
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
//If here then the only type left is struct or class.
|
||||
else if (objectTr.IsClassOrStruct(base.Session))
|
||||
{
|
||||
return SerializerType.ClassOrStruct;
|
||||
}
|
||||
//Unknown type.
|
||||
else
|
||||
{
|
||||
base.LogError($"{errorPrefix}{objectTr.Name} is an unsupported type. Mostly because we don't know what the heck it is. Please let us know so we can fix this.");
|
||||
return SerializerType.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if objectTd can have a serializer generated for it.
|
||||
/// </summary>
|
||||
private bool CanGenerateSerializer(TypeDefinition objectTd)
|
||||
{
|
||||
string errorText = $"{objectTd.Name} is not a supported type. Use a supported type or provide a custom serializer";
|
||||
|
||||
System.Type unityObjectType = typeof(UnityEngine.Object);
|
||||
//Unable to determine type, cannot generate for.
|
||||
if (objectTd == null)
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
//Component.
|
||||
if (objectTd.InheritsFrom<UnityEngine.Component>(base.Session))
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
//Unity Object.
|
||||
if (objectTd.Is(unityObjectType))
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
//ScriptableObject.
|
||||
if (objectTd.Is(typeof(UnityEngine.ScriptableObject)))
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
//Has generic parameters.
|
||||
if (objectTd.HasGenericParameters)
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
//Is an interface.
|
||||
if (objectTd.IsInterface)
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
//Is abstract.
|
||||
if (objectTd.IsAbstract)
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
if (objectTd.InheritsFrom(base.Session, unityObjectType) && objectTd.IsExcluded(GeneralHelper.UNITYENGINE_ASSEMBLY_PREFIX))
|
||||
{
|
||||
base.LogError(errorText);
|
||||
return false;
|
||||
}
|
||||
|
||||
//If here type is valid.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b1882eac63e3d94aad8f41915bc1ab8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,12 @@
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
|
||||
internal enum QolAttributeType
|
||||
{
|
||||
None,
|
||||
Server,
|
||||
Client
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 357a22940018b8e49976e13272c5b2ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,20 @@
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
|
||||
internal enum SerializerType
|
||||
{
|
||||
Invalid,
|
||||
Enum,
|
||||
Array,
|
||||
List,
|
||||
ListCache,
|
||||
NetworkBehaviour,
|
||||
ClassOrStruct,
|
||||
Nullable,
|
||||
Dictionary,
|
||||
Null,
|
||||
ByReference,
|
||||
MultiDimensionalArray
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7f1bbf5c398c3e4e92e53ec3e49d5e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs
Normal file
17
Assets/FishNet/CodeGenerating/Helpers/Typed/SyncIndexData.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Data used to modify an RpcIndex should the class have to be rebuilt.
|
||||
/// </summary>
|
||||
internal class SyncIndexData
|
||||
{
|
||||
public uint SyncCount = 0;
|
||||
public List<Instruction> DelegateInstructions = new List<Instruction>();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55f2e751e4788464b8394f6b8bdb548a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
14
Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs
Normal file
14
Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
|
||||
public enum SyncType
|
||||
{
|
||||
Unset,
|
||||
Variable,
|
||||
List,
|
||||
Dictionary,
|
||||
HashSet,
|
||||
Custom
|
||||
}
|
||||
|
||||
}
|
11
Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/Typed/SyncType.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44c753d6ac0c7864c9962d91703b2afe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1
Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs
Normal file
1
Assets/FishNet/CodeGenerating/Helpers/WriterGenerator.cs
Normal file
@ -0,0 +1 @@
|
||||
//Remove on 2024/01/01
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4ff3023050c3ee41b59523def204ac8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1
Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs
Normal file
1
Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs
Normal file
@ -0,0 +1 @@
|
||||
//Remove on 2024/01/01
|
11
Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/WriterHelper.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2bbdbcfc675aaff469cadbee89f49c12
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
100
Assets/FishNet/CodeGenerating/Helpers/WriterImports.cs
Normal file
100
Assets/FishNet/CodeGenerating/Helpers/WriterImports.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using FishNet.Object;
|
||||
using FishNet.Serializing;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal class WriterImports : CodegenBase
|
||||
{
|
||||
#region Reflection references.
|
||||
public MethodReference WriterPool_GetWriter_MethodRef;
|
||||
public MethodReference WriterPool_GetWriterLength_MethodRef;
|
||||
public MethodReference Writer_WritePackedWhole_MethodRef;
|
||||
public TypeReference PooledWriter_TypeRef;
|
||||
public TypeReference Writer_TypeRef;
|
||||
public MethodReference PooledWriter_Dispose_MethodRef;
|
||||
public MethodReference Writer_WriteDictionary_MethodRef;
|
||||
public MethodReference Writer_WriteList_MethodRef;
|
||||
public MethodReference Writer_WriteListCache_MethodRef;
|
||||
public MethodReference Writer_WriteArray_MethodRef;
|
||||
public TypeReference AutoPackTypeRef;
|
||||
|
||||
public TypeReference GenericWriterTypeRef;
|
||||
public TypeReference WriterTypeRef;
|
||||
public MethodReference WriteGetSetMethodRef;
|
||||
public MethodReference WriteAutoPackGetSetMethodRef;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Imports references needed by this helper.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <returns></returns>
|
||||
public override bool ImportReferences()
|
||||
{
|
||||
PooledWriter_TypeRef = base.ImportReference(typeof(PooledWriter));
|
||||
Writer_TypeRef = base.ImportReference(typeof(Writer));
|
||||
AutoPackTypeRef = base.ImportReference(typeof(AutoPackType));
|
||||
|
||||
GenericWriterTypeRef = base.ImportReference(typeof(GenericWriter<>));
|
||||
WriterTypeRef = base.ImportReference(typeof(Writer));
|
||||
|
||||
PropertyInfo writePropertyInfo;
|
||||
writePropertyInfo = typeof(GenericWriter<>).GetProperty(nameof(GenericWriter<int>.Write));
|
||||
WriteGetSetMethodRef = base.ImportReference(writePropertyInfo.GetSetMethod());
|
||||
writePropertyInfo = typeof(GenericWriter<>).GetProperty(nameof(GenericWriter<int>.WriteAutoPack));
|
||||
WriteAutoPackGetSetMethodRef = base.ImportReference(writePropertyInfo.GetSetMethod());
|
||||
|
||||
//WriterPool.GetWriter
|
||||
Type writerPoolType = typeof(WriterPool);
|
||||
base.ImportReference(writerPoolType);
|
||||
foreach (var methodInfo in writerPoolType.GetMethods())
|
||||
{
|
||||
if (methodInfo.Name == nameof(WriterPool.GetWriter))
|
||||
{
|
||||
//GetWriter().
|
||||
if (methodInfo.GetParameters().Length == 0)
|
||||
{
|
||||
WriterPool_GetWriter_MethodRef = base.ImportReference(methodInfo);
|
||||
}
|
||||
//GetWriter(?).
|
||||
else if (methodInfo.GetParameters().Length == 1)
|
||||
{
|
||||
ParameterInfo pi = methodInfo.GetParameters()[0];
|
||||
//GetWriter(int).
|
||||
if (pi.ParameterType == typeof(int))
|
||||
WriterPool_GetWriterLength_MethodRef = base.ImportReference(methodInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriterProcessor gwh = base.GetClass<WriterProcessor>();
|
||||
Type pooledWriterType = typeof(PooledWriter);
|
||||
foreach (MethodInfo methodInfo in pooledWriterType.GetMethods())
|
||||
{
|
||||
int parameterCount = methodInfo.GetParameters().Length;
|
||||
|
||||
if (methodInfo.Name == nameof(PooledWriter.Dispose))
|
||||
PooledWriter_Dispose_MethodRef = base.ImportReference(methodInfo);
|
||||
else if (methodInfo.Name == nameof(PooledWriter.WritePackedWhole))
|
||||
Writer_WritePackedWhole_MethodRef = base.ImportReference(methodInfo);
|
||||
//Relay writers.
|
||||
else if (parameterCount == 1 && methodInfo.Name == nameof(PooledWriter.WriteDictionary))
|
||||
Writer_WriteDictionary_MethodRef = base.ImportReference(methodInfo);
|
||||
else if (parameterCount == 1 && methodInfo.Name == nameof(PooledWriter.WriteList))
|
||||
Writer_WriteList_MethodRef = base.ImportReference(methodInfo);
|
||||
else if (parameterCount == 1 && methodInfo.Name == nameof(PooledWriter.WriteListCache))
|
||||
Writer_WriteListCache_MethodRef = base.ImportReference(methodInfo);
|
||||
else if (parameterCount == 1 && methodInfo.Name == nameof(PooledWriter.WriteArray))
|
||||
Writer_WriteArray_MethodRef = base.ImportReference(methodInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
11
Assets/FishNet/CodeGenerating/Helpers/WriterImports.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/Helpers/WriterImports.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 425638e29bab6f1488e8865c9e3f8b57
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/FishNet/CodeGenerating/ILCore.meta
Normal file
8
Assets/FishNet/CodeGenerating/ILCore.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abe522a1ad3df3a43a5c3389e3b8ee89
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
505
Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs
Normal file
505
Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs
Normal file
@ -0,0 +1,505 @@
|
||||
using FishNet.Broadcast;
|
||||
using FishNet.CodeGenerating.Extension;
|
||||
using FishNet.CodeGenerating.Helping;
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using FishNet.CodeGenerating.Processing;
|
||||
using FishNet.CodeGenerating.Processing.Rpc;
|
||||
using FishNet.Configuring;
|
||||
using FishNet.Serializing.Helping;
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace FishNet.CodeGenerating.ILCore
|
||||
{
|
||||
public class FishNetILPP : ILPostProcessor
|
||||
{
|
||||
#region Const.
|
||||
internal const string RUNTIME_ASSEMBLY_NAME = "FishNet.Runtime";
|
||||
#endregion
|
||||
|
||||
public override bool WillProcess(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
if (compiledAssembly.Name.StartsWith("Unity."))
|
||||
return false;
|
||||
if (compiledAssembly.Name.StartsWith("UnityEngine."))
|
||||
return false;
|
||||
if (compiledAssembly.Name.StartsWith("UnityEditor."))
|
||||
return false;
|
||||
if (compiledAssembly.Name.Contains("Editor"))
|
||||
return false;
|
||||
|
||||
/* This line contradicts the one below where referencesFishNet
|
||||
* becomes true if the assembly is FishNetAssembly. This is here
|
||||
* intentionally to stop codegen from running on the runtime
|
||||
* fishnet assembly, but the option below is for debugging. I would
|
||||
* comment out this check if I wanted to compile fishnet runtime. */
|
||||
//if (CODEGEN_THIS_NAMESPACE.Length == 0)
|
||||
//{
|
||||
// if (compiledAssembly.Name == RUNTIME_ASSEMBLY_NAME)
|
||||
// return false;
|
||||
//}
|
||||
bool referencesFishNet = FishNetILPP.IsFishNetAssembly(compiledAssembly) || compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == RUNTIME_ASSEMBLY_NAME);
|
||||
return referencesFishNet;
|
||||
}
|
||||
public override ILPostProcessor GetInstance() => this;
|
||||
|
||||
public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
AssemblyDefinition assemblyDef = ILCoreHelper.GetAssemblyDefinition(compiledAssembly);
|
||||
if (assemblyDef == null)
|
||||
return null;
|
||||
|
||||
//Check WillProcess again; somehow certain editor scripts skip the WillProcess check.
|
||||
if (!WillProcess(compiledAssembly))
|
||||
return null;
|
||||
|
||||
CodegenSession session = new CodegenSession();
|
||||
if (!session.Initialize(assemblyDef.MainModule))
|
||||
return null;
|
||||
|
||||
bool modified = false;
|
||||
|
||||
bool fnAssembly = IsFishNetAssembly(compiledAssembly);
|
||||
if (fnAssembly)
|
||||
modified |= ModifyMakePublicMethods(session);
|
||||
/* If one or more scripts use RPCs but don't inherit NetworkBehaviours
|
||||
* then don't bother processing the rest. */
|
||||
if (session.GetClass<NetworkBehaviourProcessor>().NonNetworkBehaviourHasInvalidAttributes(session.Module.Types))
|
||||
return new ILPostProcessResult(null, session.Diagnostics);
|
||||
|
||||
modified |= session.GetClass<WriterProcessor>().Process();
|
||||
modified |= session.GetClass<ReaderProcessor>().Process();
|
||||
modified |= CreateDeclaredSerializerDelegates(session);
|
||||
modified |= CreateDeclaredSerializers(session);
|
||||
modified |= CreateDeclaredComparerDelegates(session);
|
||||
modified |= CreateIBroadcast(session);
|
||||
modified |= CreateQOLAttributes(session);
|
||||
modified |= CreateNetworkBehaviours(session);
|
||||
modified |= CreateGenericReadWriteDelegates(session);
|
||||
|
||||
if (fnAssembly)
|
||||
{
|
||||
AssemblyNameReference anr = session.Module.AssemblyReferences.FirstOrDefault<AssemblyNameReference>(x => x.FullName == session.Module.Assembly.FullName);
|
||||
if (anr != null)
|
||||
session.Module.AssemblyReferences.Remove(anr);
|
||||
}
|
||||
|
||||
/* If there are warnings about SyncVars being in different assemblies.
|
||||
* This is awful ... codegen would need to be reworked to save
|
||||
* syncvars across all assemblies so that scripts referencing them from
|
||||
* another assembly can have it's instructions changed. This however is an immense
|
||||
* amount of work so it will have to be put on hold, for... a long.. long while. */
|
||||
if (session.DifferentAssemblySyncVars.Count > 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"Assembly {session.Module.Name} has inherited access to SyncVars in different assemblies. When accessing SyncVars across assemblies be sure to use Get/Set methods withinin the inherited assembly script to change SyncVars. Accessible fields are:");
|
||||
|
||||
foreach (FieldDefinition item in session.DifferentAssemblySyncVars)
|
||||
sb.AppendLine($"Field {item.Name} within {item.DeclaringType.FullName} in assembly {item.Module.Name}.");
|
||||
|
||||
session.LogWarning("v------- IMPORTANT -------v");
|
||||
session.LogWarning(sb.ToString());
|
||||
session.DifferentAssemblySyncVars.Clear();
|
||||
}
|
||||
|
||||
//session.LogWarning($"Assembly {compiledAssembly.Name} took {stopwatch.ElapsedMilliseconds}.");
|
||||
if (!modified)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryStream pe = new MemoryStream();
|
||||
MemoryStream pdb = new MemoryStream();
|
||||
WriterParameters writerParameters = new WriterParameters
|
||||
{
|
||||
SymbolWriterProvider = new PortablePdbWriterProvider(),
|
||||
SymbolStream = pdb,
|
||||
WriteSymbols = true
|
||||
};
|
||||
assemblyDef.Write(pe, writerParameters);
|
||||
return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), session.Diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makees methods public scope which use CodegenMakePublic attribute.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool ModifyMakePublicMethods(CodegenSession session)
|
||||
{
|
||||
string makePublicTypeFullName = typeof(CodegenMakePublicAttribute).FullName;
|
||||
foreach (TypeDefinition td in session.Module.Types)
|
||||
{
|
||||
foreach (MethodDefinition md in td.Methods)
|
||||
{
|
||||
foreach (CustomAttribute ca in md.CustomAttributes)
|
||||
{
|
||||
if (ca.AttributeType.FullName == makePublicTypeFullName)
|
||||
{
|
||||
md.Attributes &= ~MethodAttributes.Assembly;
|
||||
md.Attributes |= MethodAttributes.Public;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//There is always at least one modified.
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates delegates for user declared serializers.
|
||||
/// </summary>
|
||||
internal bool CreateDeclaredSerializerDelegates(CodegenSession session)
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
TypeAttributes readWriteExtensionTypeAttr = (TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract);
|
||||
List<TypeDefinition> allTypeDefs = session.Module.Types.ToList();
|
||||
foreach (TypeDefinition td in allTypeDefs)
|
||||
{
|
||||
if (session.GetClass<GeneralHelper>().IgnoreTypeDefinition(td))
|
||||
continue;
|
||||
|
||||
if (td.Attributes.HasFlag(readWriteExtensionTypeAttr))
|
||||
modified |= session.GetClass<CustomSerializerProcessor>().CreateSerializerDelegates(td, true);
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates serializers for custom types within user declared serializers.
|
||||
/// </summary>
|
||||
private bool CreateDeclaredSerializers(CodegenSession session)
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
TypeAttributes readWriteExtensionTypeAttr = (TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract);
|
||||
List<TypeDefinition> allTypeDefs = session.Module.Types.ToList();
|
||||
foreach (TypeDefinition td in allTypeDefs)
|
||||
{
|
||||
if (session.GetClass<GeneralHelper>().IgnoreTypeDefinition(td))
|
||||
continue;
|
||||
|
||||
if (td.Attributes.HasFlag(readWriteExtensionTypeAttr))
|
||||
modified |= session.GetClass<CustomSerializerProcessor>().CreateSerializers(td);
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates delegates for user declared comparers.
|
||||
/// </summary>
|
||||
internal bool CreateDeclaredComparerDelegates(CodegenSession session)
|
||||
{
|
||||
bool modified = false;
|
||||
List<TypeDefinition> allTypeDefs = session.Module.Types.ToList();
|
||||
foreach (TypeDefinition td in allTypeDefs)
|
||||
{
|
||||
if (session.GetClass<GeneralHelper>().IgnoreTypeDefinition(td))
|
||||
continue;
|
||||
|
||||
modified |= session.GetClass<CustomSerializerProcessor>().CreateComparerDelegates(td);
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creaters serializers and calls for IBroadcast.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <param name="diagnostics"></param>
|
||||
private bool CreateIBroadcast(CodegenSession session)
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
string networkBehaviourFullName = session.GetClass<NetworkBehaviourHelper>().FullName;
|
||||
HashSet<TypeDefinition> typeDefs = new HashSet<TypeDefinition>();
|
||||
foreach (TypeDefinition td in session.Module.Types)
|
||||
{
|
||||
TypeDefinition climbTd = td;
|
||||
do
|
||||
{
|
||||
//Reached NetworkBehaviour class.
|
||||
if (climbTd.FullName == networkBehaviourFullName)
|
||||
break;
|
||||
|
||||
///* Check initial class as well all types within
|
||||
// * the class. Then check all of it's base classes. */
|
||||
if (climbTd.ImplementsInterface<IBroadcast>())
|
||||
typeDefs.Add(climbTd);
|
||||
//7ms
|
||||
|
||||
//Add nested. Only going to go a single layer deep.
|
||||
foreach (TypeDefinition nestedTypeDef in td.NestedTypes)
|
||||
{
|
||||
if (nestedTypeDef.ImplementsInterface<IBroadcast>())
|
||||
typeDefs.Add(nestedTypeDef);
|
||||
}
|
||||
//0ms
|
||||
|
||||
climbTd = climbTd.GetNextBaseTypeDefinition(session);
|
||||
//this + name check 40ms
|
||||
} while (climbTd != null);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Create reader/writers for found typeDefs.
|
||||
foreach (TypeDefinition td in typeDefs)
|
||||
{
|
||||
TypeReference typeRef = session.ImportReference(td);
|
||||
bool canSerialize = session.GetClass<GeneralHelper>().HasSerializerAndDeserializer(typeRef, true);
|
||||
if (!canSerialize)
|
||||
session.LogError($"Broadcast {td.Name} does not support serialization. Use a supported type or create a custom serializer.");
|
||||
else
|
||||
modified = true;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles QOLAttributes such as [Server].
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool CreateQOLAttributes(CodegenSession session)
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
bool codeStripping = false;
|
||||
|
||||
List<TypeDefinition> allTypeDefs = session.Module.Types.ToList();
|
||||
|
||||
/* First pass, potentially only pass.
|
||||
* If code stripping them this will be run again. The first iteration
|
||||
* is to ensure things are removed in the proper order. */
|
||||
foreach (TypeDefinition td in allTypeDefs)
|
||||
{
|
||||
if (session.GetClass<GeneralHelper>().IgnoreTypeDefinition(td))
|
||||
continue;
|
||||
|
||||
modified |= session.GetClass<QolAttributeProcessor>().Process(td, codeStripping);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates NetworkBehaviour changes.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <param name="diagnostics"></param>
|
||||
private bool CreateNetworkBehaviours(CodegenSession session)
|
||||
{
|
||||
bool modified = false;
|
||||
//Get all network behaviours to process.
|
||||
List<TypeDefinition> networkBehaviourTypeDefs = session.Module.Types
|
||||
.Where(td => td.IsSubclassOf(session, session.GetClass<NetworkBehaviourHelper>().FullName))
|
||||
.ToList();
|
||||
|
||||
//Moment a NetworkBehaviour exist the assembly is considered modified.
|
||||
if (networkBehaviourTypeDefs.Count > 0)
|
||||
modified = true;
|
||||
|
||||
/* Remove types which are inherited. This gets the child most networkbehaviours.
|
||||
* Since processing iterates all parent classes there's no reason to include them */
|
||||
RemoveInheritedTypeDefinitions(networkBehaviourTypeDefs);
|
||||
//Set how many rpcs are in children classes for each typedef.
|
||||
Dictionary<TypeDefinition, uint> inheritedRpcCounts = new Dictionary<TypeDefinition, uint>();
|
||||
SetChildRpcCounts(inheritedRpcCounts, networkBehaviourTypeDefs);
|
||||
//Set how many synctypes are in children classes for each typedef.
|
||||
Dictionary<TypeDefinition, uint> inheritedSyncTypeCounts = new Dictionary<TypeDefinition, uint>();
|
||||
SetChildSyncTypeCounts(inheritedSyncTypeCounts, networkBehaviourTypeDefs);
|
||||
|
||||
/* This holds all sync types created, synclist, dictionary, var
|
||||
* and so on. This data is used after all syncvars are made so
|
||||
* other methods can look for references to created synctypes and
|
||||
* replace accessors accordingly. */
|
||||
List<(SyncType, ProcessedSync)> allProcessedSyncs = new List<(SyncType, ProcessedSync)>();
|
||||
HashSet<string> allProcessedCallbacks = new HashSet<string>();
|
||||
List<TypeDefinition> processedClasses = new List<TypeDefinition>();
|
||||
|
||||
foreach (TypeDefinition typeDef in networkBehaviourTypeDefs)
|
||||
{
|
||||
session.ImportReference(typeDef);
|
||||
//Synctypes processed for this nb and it's inherited classes.
|
||||
List<(SyncType, ProcessedSync)> processedSyncs = new List<(SyncType, ProcessedSync)>();
|
||||
session.GetClass<NetworkBehaviourProcessor>().Process(typeDef, processedSyncs,
|
||||
inheritedSyncTypeCounts, inheritedRpcCounts);
|
||||
//Add to all processed.
|
||||
allProcessedSyncs.AddRange(processedSyncs);
|
||||
}
|
||||
|
||||
/* Must run through all scripts should user change syncvar
|
||||
* from outside the networkbehaviour. */
|
||||
if (allProcessedSyncs.Count > 0)
|
||||
{
|
||||
foreach (TypeDefinition td in session.Module.Types)
|
||||
{
|
||||
session.GetClass<NetworkBehaviourSyncProcessor>().ReplaceGetSets(td, allProcessedSyncs);
|
||||
session.GetClass<RpcProcessor>().RedirectBaseCalls();
|
||||
}
|
||||
}
|
||||
|
||||
/* Removes typedefinitions which are inherited by
|
||||
* another within tds. For example, if the collection
|
||||
* td contains A, B, C and our structure is
|
||||
* A : B : C then B and C will be removed from the collection
|
||||
* Since they are both inherited by A. */
|
||||
void RemoveInheritedTypeDefinitions(List<TypeDefinition> tds)
|
||||
{
|
||||
HashSet<TypeDefinition> inheritedTds = new HashSet<TypeDefinition>();
|
||||
/* Remove any networkbehaviour typedefs which are inherited by
|
||||
* another networkbehaviour typedef. When a networkbehaviour typedef
|
||||
* is processed so are all of the inherited types. */
|
||||
for (int i = 0; i < tds.Count; i++)
|
||||
{
|
||||
/* Iterates all base types and
|
||||
* adds them to inheritedTds so long
|
||||
* as the base type is not a NetworkBehaviour. */
|
||||
TypeDefinition copyTd = tds[i].GetNextBaseTypeDefinition(session);
|
||||
while (copyTd != null)
|
||||
{
|
||||
//Class is NB.
|
||||
if (copyTd.FullName == session.GetClass<NetworkBehaviourHelper>().FullName)
|
||||
break;
|
||||
|
||||
inheritedTds.Add(copyTd);
|
||||
copyTd = copyTd.GetNextBaseTypeDefinition(session);
|
||||
}
|
||||
}
|
||||
|
||||
//Remove all inherited types.
|
||||
foreach (TypeDefinition item in inheritedTds)
|
||||
tds.Remove(item);
|
||||
}
|
||||
|
||||
/* Sets how many Rpcs are within the children
|
||||
* of each typedefinition. EG: if our structure is
|
||||
* A : B : C, with the following RPC counts...
|
||||
* A 3
|
||||
* B 1
|
||||
* C 2
|
||||
* then B child rpc counts will be 3, and C will be 4. */
|
||||
void SetChildRpcCounts(Dictionary<TypeDefinition, uint> typeDefCounts, List<TypeDefinition> tds)
|
||||
{
|
||||
foreach (TypeDefinition typeDef in tds)
|
||||
{
|
||||
//Number of RPCs found while climbing typeDef.
|
||||
uint childCount = 0;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
do
|
||||
{
|
||||
//How many RPCs are in copyTd.
|
||||
uint copyCount = session.GetClass<RpcProcessor>().GetRpcCount(copyTd);
|
||||
|
||||
/* If not found it this is the first time being
|
||||
* processed. When this occurs set the value
|
||||
* to 0. It will be overwritten below if baseCount
|
||||
* is higher. */
|
||||
uint previousCopyChildCount = 0;
|
||||
if (!typeDefCounts.TryGetValue(copyTd, out previousCopyChildCount))
|
||||
typeDefCounts[copyTd] = 0;
|
||||
/* If baseCount is higher then replace count for copyTd.
|
||||
* This can occur when a class is inherited by several types
|
||||
* and the first processed type might only have 1 rpc, while
|
||||
* the next has 2. This could be better optimized but to keep
|
||||
* the code easier to read, it will stay like this. */
|
||||
if (childCount > previousCopyChildCount)
|
||||
typeDefCounts[copyTd] = childCount;
|
||||
|
||||
//Increase baseCount with RPCs found here.
|
||||
childCount += copyCount;
|
||||
|
||||
copyTd = copyTd.GetNextBaseClassToProcess(session);
|
||||
} while (copyTd != null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* This performs the same functionality as SetChildRpcCounts
|
||||
* but for SyncTypes. */
|
||||
void SetChildSyncTypeCounts(Dictionary<TypeDefinition, uint> typeDefCounts, List<TypeDefinition> tds)
|
||||
{
|
||||
foreach (TypeDefinition typeDef in tds)
|
||||
{
|
||||
//Number of RPCs found while climbing typeDef.
|
||||
uint childCount = 0;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
/* Iterate up to the parent script and then reverse
|
||||
* the order. This is so that the topmost is 0
|
||||
* and each inerhiting script adds onto that.
|
||||
* Setting child types this way makes it so parent
|
||||
* types don't need to have their synctype/rpc counts
|
||||
* rebuilt when scripts are later to be found
|
||||
* inheriting from them. */
|
||||
List<TypeDefinition> reversedTypeDefs = new List<TypeDefinition>();
|
||||
do
|
||||
{
|
||||
reversedTypeDefs.Add(copyTd);
|
||||
copyTd = copyTd.GetNextBaseClassToProcess(session);
|
||||
} while (copyTd != null);
|
||||
reversedTypeDefs.Reverse();
|
||||
|
||||
foreach (TypeDefinition td in reversedTypeDefs)
|
||||
{
|
||||
//How many RPCs are in copyTd.
|
||||
uint copyCount = session.GetClass<NetworkBehaviourSyncProcessor>().GetSyncTypeCount(td);
|
||||
/* If not found it this is the first time being
|
||||
* processed. When this occurs set the value
|
||||
* to 0. It will be overwritten below if baseCount
|
||||
* is higher. */
|
||||
uint previousCopyChildCount = 0;
|
||||
if (!typeDefCounts.TryGetValue(td, out previousCopyChildCount))
|
||||
typeDefCounts[td] = 0;
|
||||
/* If baseCount is higher then replace count for copyTd.
|
||||
* This can occur when a class is inherited by several types
|
||||
* and the first processed type might only have 1 rpc, while
|
||||
* the next has 2. This could be better optimized but to keep
|
||||
* the code easier to read, it will stay like this. */
|
||||
if (childCount > previousCopyChildCount)
|
||||
typeDefCounts[td] = childCount;
|
||||
//Increase baseCount with RPCs found here.
|
||||
childCount += copyCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates generic delegates for all read and write methods.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <param name="diagnostics"></param>
|
||||
private bool CreateGenericReadWriteDelegates(CodegenSession session)
|
||||
{
|
||||
session.GetClass<WriterProcessor>().CreateStaticMethodDelegates();
|
||||
session.GetClass<ReaderProcessor>().CreateStaticMethodDelegates();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool IsFishNetAssembly(ICompiledAssembly assembly) => (assembly.Name == FishNetILPP.RUNTIME_ASSEMBLY_NAME);
|
||||
internal static bool IsFishNetAssembly(CodegenSession session) => (session.Module.Assembly.Name.Name == FishNetILPP.RUNTIME_ASSEMBLY_NAME);
|
||||
internal static bool IsFishNetAssembly(ModuleDefinition moduleDef) => (moduleDef.Assembly.Name.Name == FishNetILPP.RUNTIME_ASSEMBLY_NAME);
|
||||
|
||||
}
|
||||
}
|
11
Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs.meta
Normal file
11
Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f03d76b376c1d5b4591039af6fd4c9e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
38
Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs
Normal file
38
Assets/FishNet/CodeGenerating/ILCore/ILCoreHelper.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System.IO;
|
||||
using Unity.CompilationPipeline.Common.ILPostProcessing;
|
||||
|
||||
namespace FishNet.CodeGenerating.ILCore
|
||||
{
|
||||
internal static class ILCoreHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns AssembleDefinition for compiledAssembly.
|
||||
/// </summary>
|
||||
/// <param name="compiledAssembly"></param>
|
||||
/// <returns></returns>
|
||||
internal static AssemblyDefinition GetAssemblyDefinition(ICompiledAssembly compiledAssembly)
|
||||
{
|
||||
PostProcessorAssemblyResolver assemblyResolver = new PostProcessorAssemblyResolver(compiledAssembly);
|
||||
ReaderParameters readerParameters = new ReaderParameters
|
||||
{
|
||||
SymbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData),
|
||||
SymbolReaderProvider = new PortablePdbReaderProvider(),
|
||||
AssemblyResolver = assemblyResolver,
|
||||
ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(),
|
||||
ReadingMode = ReadingMode.Immediate
|
||||
};
|
||||
|
||||
AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(new MemoryStream(compiledAssembly.InMemoryAssembly.PeData), readerParameters);
|
||||
//Allows us to resolve inside FishNet assembly, such as for components.
|
||||
assemblyResolver.AddAssemblyDefinitionBeingOperatedOn(assemblyDefinition);
|
||||
|
||||
return assemblyDefinition;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user