fishnet installed

This commit is contained in:
sebastianhampel1 2023-05-31 11:32:21 -04:00
parent 47b25269f1
commit a001fe1b04
1291 changed files with 126631 additions and 1 deletions

View 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}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e6b71f999cc8fc647a3f73f7088802e0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

8
Assets/FishNet.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1c10e8242689baa4795de57f9ef42ec3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bbb4974b4302f435b9f4663c64d8f803
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 206db668838ebc34b90ae36be24ce3be
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 127d8312da53b3e49ba9e3e4c6348857
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 866ed457fe28c3e4b9698d87b9abd709
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c9f00cf3dc8b90b469c3c9cb8b87fc88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 239b1b10db80c594d93b7ba4ee2c1ec5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9133eb285bd7f3c4f89f4d7a2a079c6b
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: efeca2428bd9fe64d872a626b93ff0cf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d32f3dc23b55598429c5cfe6156e6243
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e8416eee3308f54fa942003de975420
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 935ec97b96b35b94f8c6880c6908304c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: df90983b61081f84b990ac494ac8bdb6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a66d771ab331fae408142a5c04abd74e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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}"
});
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb7b65b572b01444cbe3c9d830cd3587
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d983ebd0c9e1b745902030c2f7a8e99
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a7e03137ca78704e999f3a3dc68b953
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 820cf8401d4d71c4196dda444559ef8a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 360667149f16b6c4aba61fd05427cbfb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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));
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 999d4ae4862274f4ba50569c221976dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ee1c15a06ab386e439ec5aa41e3496f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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()}");
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 42648785493390646898f5fa13e1dfd6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 31071055a2e388141b8f11e1ba4e147e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 645e49fe7eeff3a4e9eb65d77fc6e2ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2344f5ab0fda07b498c03fbe0e082c14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6139ff104f3c24442b26dbc4e40d5ce5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
//Remove on 2024/01/01

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8bc93cce5d44d604c805976e696dd7da
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
//Remove on 2024/01/01

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dcb8399b7678ff1429b6e211e6f26d10
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c42e06349d6890459a155a2afe17d41
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
//Remove on 2023/06/01

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bcbcb288008d6da4eab7a5279dd6b4f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d061dda8ed87ed48a08020942ad63f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 033da35314653aa4689b4582e7929295
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28ae27f7bc8e89547a606262508fdd36
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e9a06c812bf785a44a38a5852ff866d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
//Remove on 2024/01/01

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a8afc0f62ceeaee45aa496ba5650d010
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
//Remove on 2024/01/01

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 07c42037569e53b4aa6701adefd3e063
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 350861dcbcbabc447acd37e4310b0697
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 11dbcc0798e079e4a85fe98dfc9fe23a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ced44bfdb3068f4cb7513c9be85729a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 192c16e1ad7eca84cbcc19073c945ca9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b30600f0fdb27c4fb86c310b08f43b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0cae698c9bc732641892caabf04365dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b1882eac63e3d94aad8f41915bc1ab8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,12 @@
namespace FishNet.CodeGenerating.Helping
{
internal enum QolAttributeType
{
None,
Server,
Client
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 357a22940018b8e49976e13272c5b2ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
namespace FishNet.CodeGenerating.Helping
{
internal enum SerializerType
{
Invalid,
Enum,
Array,
List,
ListCache,
NetworkBehaviour,
ClassOrStruct,
Nullable,
Dictionary,
Null,
ByReference,
MultiDimensionalArray
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e7f1bbf5c398c3e4e92e53ec3e49d5e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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>();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55f2e751e4788464b8394f6b8bdb548a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
namespace FishNet.CodeGenerating.Helping
{
public enum SyncType
{
Unset,
Variable,
List,
Dictionary,
HashSet,
Custom
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 44c753d6ac0c7864c9962d91703b2afe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
//Remove on 2024/01/01

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4ff3023050c3ee41b59523def204ac8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
//Remove on 2024/01/01

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2bbdbcfc675aaff469cadbee89f49c12
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 425638e29bab6f1488e8865c9e3f8b57
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: abe522a1ad3df3a43a5c3389e3b8ee89
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f03d76b376c1d5b4591039af6fd4c9e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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