| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293 |
- #if ENABLE_LUA_INJECTION
- using System;
- using System.IO;
- using System.Xml;
- using System.Text;
- using System.Linq;
- using UnityEngine;
- using UnityEditor;
- using Mono.Cecil;
- using Mono.Cecil.Cil;
- using Unity.CecilTools;
- using Unity.CecilTools.Extensions;
- using CustomCecilRocks;
- using System.Reflection;
- using LuaInterface;
- using UnityEditor.Callbacks;
- using System.Collections.Generic;
- using MethodBody = Mono.Cecil.Cil.MethodBody;
- class InjectedMethodInfo
- {
- public string methodFullSignature;
- public string methodOverloadSignature;
- public string methodPublishedName;
- public string methodName;
- public int methodIndex;
- }
- [InitializeOnLoad]
- public static class ToLuaInjection
- {
- static int offset = 0;
- static int methodCounter = 0;
- static bool EnableSymbols = true;
- static Instruction cursor;
- static VariableDefinition flagDef;
- static VariableDefinition funcDef;
- static TypeReference intTypeRef;
- static TypeReference injectFlagTypeRef;
- static TypeReference noToLuaAttrTypeRef;
- static TypeDefinition injectStationTypeDef;
- static TypeDefinition luaFunctionTypeDef;
- static TypeDefinition luaTableTypeDef;
- static MethodReference injectFlagGetter;
- static MethodReference injectedFuncGetter;
- static HashSet<string> dropTypeGroup = new HashSet<string>();
- static HashSet<string> injectableTypeGroup = new HashSet<string>();
- static Dictionary<MethodDefinition, VariableDefinition> resultTableGroup = new Dictionary<MethodDefinition, VariableDefinition>();
- static SortedDictionary<string, List<InjectedMethodInfo>> bridgeInfo = new SortedDictionary<string, List<InjectedMethodInfo>>();
- static OpCode[] ldargs = new OpCode[] { OpCodes.Ldarg_0, OpCodes.Ldarg_1, OpCodes.Ldarg_2, OpCodes.Ldarg_3 };
- static OpCode[] ldcI4s = new OpCode[] { OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_8 };
- const string assemblyPath = "./Library/ScriptAssemblies/Assembly-CSharp.dll";
- const InjectType injectType = InjectType.After | InjectType.Before | InjectType.Replace | InjectType.ReplaceWithPreInvokeBase | InjectType.ReplaceWithPostInvokeBase;
- const InjectFilter injectIgnoring = InjectFilter.IgnoreGeneric | InjectFilter.IgnoreConstructor;// | InjectFilter.IgnoreNoToLuaAttr | InjectFilter.IgnoreProperty;
- static HashSet<string> dropGenericNameGroup = new HashSet<string>
- {
- };
- static HashSet<string> dropNamespaceGroup = new HashSet<string>
- {
- "LuaInterface",
- };
- static HashSet<string> forceInjectTypeGroup = new HashSet<string>
- {
- };
- static ToLuaInjection()
- {
- LoadAndCheckAssembly(true);
- InjectAll();
- }
- static void InjectAll()
- {
- var injectionStatus = EditorPrefs.GetInt(Application.dataPath + "WaitForInjection", 0);
- if (Application.isPlaying || EditorApplication.isCompiling || injectionStatus == 0)
- {
- return;
- }
- bool bInjectInterupted = !LoadBlackList() || ToLuaMenu.UpdateMonoCecil(ref EnableSymbols) != 0 || !LoadBridgeEditorInfo();
- if (!bInjectInterupted)
- {
- CacheInjectableTypeGroup();
- Inject();
- AssetDatabase.Refresh();
- }
- }
- [PostProcessBuildAttribute()]
- static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
- {
- var injectionStatus = EditorPrefs.GetInt(Application.dataPath + "WaitForInjection", 0);
- if (injectionStatus == 0)
- {
- Debug.LogError("Inject Failed!!!");
- }
- EditorPrefs.SetInt(Application.dataPath + "WaitForInjection", 0);
- }
- [PostProcessScene]
- static void OnPostProcessScene()
- {
- if (BuildPipeline.isBuildingPlayer)
- {
- EditorPrefs.SetInt(Application.dataPath + "WaitForInjection", 1);
- }
- InjectAll();
- }
- [DidReloadScripts]
- static void OnDidReloadScripts()
- {
- if (!BuildPipeline.isBuildingPlayer)
- {
- EditorPrefs.SetInt(Application.dataPath + "WaitForInjection", 0);
- }
- }
-
- [MenuItem("Lua/Inject All &i", false, 5)]
- static void InjectByMenu()
- {
- if (Application.isPlaying)
- {
- EditorUtility.DisplayDialog("警告", "游戏运行过程中无法操作", "确定");
- return;
- }
- EditorPrefs.SetInt(Application.dataPath + "WaitForInjection", 1);
- if (EditorApplication.isCompiling)
- {
- EditorUtility.DisplayDialog("警告", "请等待编辑器编译完成", "确定");
- return;
- }
- InjectAll();
- }
- static AssemblyDefinition LoadAndCheckAssembly(bool bPulse)
- {
- var assemblyReader = new ReaderParameters
- {
- ReadSymbols = EnableSymbols,
- AssemblyResolver = GetAssemblyResolver()
- };
- AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyPath, assemblyReader);
- var alreadyInjected = assembly.CustomAttributes.Any((attr) =>
- {
- return attr.AttributeType.FullName == "LuaInterface.UseDefinedAttribute";
- });
- EditorPrefs.SetInt(Application.dataPath + "InjectStatus", alreadyInjected ? 1 : 0);
- if (bPulse)
- {
- Clean(assembly);
- }
- return assembly;
- }
- static void Inject()
- {
- AssemblyDefinition assembly = null;
- try
- {
- assembly = LoadAndCheckAssembly(false);
- if (InjectPrepare(assembly))
- {
- foreach (var module in assembly.Modules)
- {
- int cursor = 0;
- int typesCount = module.Types.Count;
- foreach (var type in module.Types)
- {
- ++cursor;
- EditorUtility.DisplayProgressBar("Injecting:" + module.FullyQualifiedName, type.FullName, (float)cursor / typesCount);
- if (!InjectProcess(assembly, type))
- {
- EditorUtility.ClearProgressBar();
- return;
- }
- }
- }
- EditorUtility.ClearProgressBar();
- UpdateInjectionCacheSize();
- ExportInjectionBridgeInfo();
- WriteInjectedAssembly(assembly, assemblyPath);
- resultTableGroup.Clear();
- EditorApplication.Beep();
- Debug.Log("Lua Injection Finished!");
- EditorPrefs.SetInt(Application.dataPath + "InjectStatus", 1);
- }
- }
- catch (Exception e)
- {
- Debug.LogError(e.ToString());
- }
- finally
- {
- if (assembly != null)
- {
- Clean(assembly);
- }
- }
- }
- static bool InjectPrepare(AssemblyDefinition assembly)
- {
- bool alreadyInjected = EditorPrefs.GetInt(Application.dataPath + "InjectStatus") == 1;
- if (alreadyInjected)
- {
- Debug.Log("Already Injected!");
- return false;
- }
- resultTableGroup.Clear();
- var injectAttrType = assembly.MainModule.Types.Single(type => type.FullName == "LuaInterface.UseDefinedAttribute");
- var attrCtorInfo = injectAttrType.Methods.Single(method => method.IsConstructor);
- assembly.CustomAttributes.Add(new CustomAttribute(attrCtorInfo));
- intTypeRef = assembly.MainModule.TypeSystem.Int32;
- injectFlagTypeRef = assembly.MainModule.TypeSystem.Byte;
- noToLuaAttrTypeRef = assembly.MainModule.Types.Single(type => type.FullName == "LuaInterface.NoToLuaAttribute");
- injectStationTypeDef = assembly.MainModule.Types.Single(type => type.FullName == "LuaInterface.LuaInjectionStation");
- luaFunctionTypeDef = assembly.MainModule.Types.Single(method => method.FullName == "LuaInterface.LuaFunction");
- luaTableTypeDef = assembly.MainModule.Types.Single(method => method.FullName == "LuaInterface.LuaTable");
- injectFlagGetter = injectStationTypeDef.Methods.Single(method => method.Name == "GetInjectFlag");
- injectedFuncGetter = injectStationTypeDef.Methods.Single(method => method.Name == "GetInjectionFunction");
- return true;
- }
- static BaseAssemblyResolver GetAssemblyResolver()
- {
- DefaultAssemblyResolver resolver = new DefaultAssemblyResolver();
- AppDomain.CurrentDomain
- .GetAssemblies()
- .Select(assem => Path.GetDirectoryName(assem.ManifestModule.FullyQualifiedName))
- .Distinct()
- .Foreach(dir => resolver.AddSearchDirectory(dir));
- return resolver;
- }
- static bool InjectProcess(AssemblyDefinition assembly, TypeDefinition type)
- {
- if (!DoesTypeInjectable(type))
- {
- return true;
- }
- foreach (var nestedType in type.NestedTypes)
- {
- if (!InjectProcess(assembly, nestedType))
- {
- return false;
- }
- }
- foreach (var target in type.Methods)
- {
- if (target.IsGenericMethodDefinition())
- {
- continue;
- }
- if (!DoesMethodInjectable(target))
- {
- continue;
- }
- int methodIndex = AppendMethod(target);
- if (methodIndex == -1)
- {
- return false;
- }
- if (target.IsEnumerator())
- {
- InjectCoroutine(assembly, target, methodIndex);
- }
- else
- {
- InjectMethod(assembly, target, methodIndex);
- }
- }
- return true;
- }
- static void FillBegin(MethodDefinition target, int methodIndex)
- {
- MethodBody targetBody = target.Body;
- ILProcessor il = targetBody.GetILProcessor();
- targetBody.InitLocals = true;
- flagDef = new VariableDefinition(injectFlagTypeRef);
- funcDef = new VariableDefinition(luaFunctionTypeDef);
- targetBody.Variables.Add(flagDef);
- targetBody.Variables.Add(funcDef);
- Instruction startInsertPos = targetBody.Instructions[0];
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Ldc_I4, methodIndex));
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Call, injectFlagGetter));
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Stloc, flagDef));
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Ldloc, flagDef));
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Brfalse, startInsertPos));
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Ldc_I4, methodIndex));
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Call, injectedFuncGetter));
- il.InsertBefore(startInsertPos, il.Create(OpCodes.Stloc, funcDef));
- offset = targetBody.Instructions.IndexOf(startInsertPos);
- }
- #region GenericMethod
- static void InjectGenericMethod(AssemblyDefinition assembly, MethodDefinition target, int methodIndex)
- {
- }
- #endregion GenericMethod
- #region Coroutine
- static void InjectCoroutine(AssemblyDefinition assembly, MethodDefinition target, int methodIndex)
- {
- InjectType runtimeInjectType = GetMethodRuntimeInjectType(target);
- if (runtimeInjectType == InjectType.None)
- {
- return;
- }
- target.Body.SimplifyMacros();
- FillBegin(target, methodIndex);
- FillReplaceCoroutine(target, runtimeInjectType & InjectType.Replace);
- FillCoroutineMonitor(target, runtimeInjectType & (~InjectType.Replace), methodIndex);
- target.Body.OptimizeMacros();
- }
- static void FillReplaceCoroutine(MethodDefinition target, InjectType runtimeInjectType)
- {
- if (runtimeInjectType == InjectType.None)
- {
- return;
- }
- MethodBody targetBody = target.Body;
- ILProcessor il = targetBody.GetILProcessor();
- cursor = GetMethodNextInsertPosition(target, null, false);
- if (cursor != null)
- {
- il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, flagDef));
- il.InsertBefore(cursor, il.Create(ldcI4s[(int)InjectType.Replace / 2]));
- il.InsertBefore(cursor, il.Create(OpCodes.Bne_Un, cursor));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, funcDef));
- FillArgs(target, cursor, null);
- il.InsertBefore(cursor, il.Create(OpCodes.Call, GetLuaMethodInvoker(target, false, false)));
- il.InsertBefore(cursor, il.Create(OpCodes.Ret));
- }
- }
- static void FillCoroutineMonitor(MethodDefinition target, InjectType runtimeInjectType, int methodIndex)
- {
- if (runtimeInjectType == InjectType.None)
- {
- return;
- }
- MethodBody targetBody = target.Body;
- FieldDefinition hostField = null;
- var coroutineEntity = targetBody.Variables[0].VariableType.Resolve();
- if (!target.DeclaringType.NestedTypes.Any(type => coroutineEntity == type))
- {
- return;
- }
- cursor = GetMethodNextInsertPosition(target, cursor, true);
- CopyCoroutineCreatorReference(target, coroutineEntity, ref hostField);
- var coroutineCarrier = coroutineEntity.Methods.Single(method => method.Name == "MoveNext");
- CopyCreatorArgsToCarrier(target, coroutineCarrier);
- FillBegin(coroutineCarrier, methodIndex);
- var fillInjectInfoFunc = GetCoroutineInjectInfoFiller(target, hostField);
- FillInjectMethod(coroutineCarrier, fillInjectInfoFunc, runtimeInjectType & InjectType.After);
- FillInjectMethod(coroutineCarrier, fillInjectInfoFunc, runtimeInjectType & InjectType.Before);
- }
- static Action<MethodDefinition, InjectType> GetCoroutineInjectInfoFiller(MethodDefinition coroutineCreator, FieldDefinition hostRef)
- {
- return (coroutineCarrier, runtimeInjectType) =>
- {
- MethodBody targetBody = coroutineCarrier.Body;
- ILProcessor il = targetBody.GetILProcessor();
- il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, funcDef));
- if (coroutineCreator.HasThis)
- {
- il.InsertBefore(cursor, il.Create(OpCodes.Ldarg_0));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldfld, hostRef));
- }
- CopyCarrierFieldsToArg(coroutineCreator, coroutineCarrier);
- FillCoroutineState(coroutineCarrier);
- il.InsertBefore(cursor, il.Create(OpCodes.Call, GetLuaMethodInvoker(coroutineCreator, true, true)));
- };
- }
- static void CopyCoroutineCreatorReference(MethodDefinition coroutineCreator, TypeDefinition coroutineCarrier, ref FieldDefinition hostField)
- {
- if (coroutineCreator.HasThis)
- {
- ILProcessor il = coroutineCreator.Body.GetILProcessor();
- hostField = new FieldDefinition("__iHost", Mono.Cecil.FieldAttributes.Public, coroutineCreator.DeclaringType);
- coroutineCarrier.Fields.Add(hostField);
- il.InsertBefore(cursor, il.Create(OpCodes.Ldloc_0));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldarg_0));
- il.InsertBefore(cursor, il.Create(OpCodes.Stfld, hostField));
- }
- }
- static void CopyCreatorArgsToCarrier(MethodDefinition coroutineCreator, MethodDefinition coroutineCarrier)
- {
- ILProcessor il = coroutineCreator.Body.GetILProcessor();
- var carrierFields = coroutineCarrier.DeclaringType.Fields;
- coroutineCreator
- .Parameters
- .Foreach(param =>
- {
- var name = "<$>" + param.Name;
- if (!carrierFields.Any(field => field.Name == name))
- {
- var hostArg = new FieldDefinition(name, Mono.Cecil.FieldAttributes.Public, param.ParameterType);
- carrierFields.Add(hostArg);
- il.InsertBefore(cursor, il.Create(OpCodes.Ldloc_0));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldarg, param));
- il.InsertBefore(cursor, il.Create(OpCodes.Stfld, hostArg));
- }
- });
- }
- static void CopyCarrierFieldsToArg(MethodDefinition coroutineCreator, MethodDefinition coroutineCarrier)
- {
- ILProcessor il = coroutineCarrier.Body.GetILProcessor();
- var carrierFields = coroutineCarrier.DeclaringType.Fields;
- coroutineCreator
- .Parameters
- .Select(param => "<$>" + param.Name)
- .Foreach(name =>
- {
- var arg = carrierFields.Single(field => field.Name == name);
- il.InsertBefore(cursor, il.Create(OpCodes.Ldarg_0));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldfld, arg));
- });
- }
- static void FillCoroutineState(MethodDefinition coroutineCarrier)
- {
- MethodBody targetBody = coroutineCarrier.Body;
- ILProcessor il = targetBody.GetILProcessor();
- il.InsertBefore(cursor, il.Create(OpCodes.Ldarg_0));
- var stateField = coroutineCarrier.DeclaringType.Fields.Single(field => field.Name == "$PC");
- il.InsertBefore(cursor, il.Create(OpCodes.Ldfld, stateField));
- }
- #endregion Coroutine
- #region NormalMethod
- static void InjectMethod(AssemblyDefinition assembly, MethodDefinition target, int methodIndex)
- {
- target.Body.SimplifyMacros();
- FillBegin(target, methodIndex);
- InjectType runtimeInjectType = GetMethodRuntimeInjectType(target);
- FillInjectMethod(target, FillInjectInfo, runtimeInjectType & InjectType.After);
- FillInjectMethod(target, FillInjectInfo, runtimeInjectType & (~InjectType.After));
- target.Body.OptimizeMacros();
- }
- static void FillInjectMethod(MethodDefinition target, Action<MethodDefinition, InjectType> fillInjectInfo, InjectType runtimeInjectType)
- {
- if (runtimeInjectType == InjectType.None)
- {
- return;
- }
- MethodBody targetBody = target.Body;
- ILProcessor il = targetBody.GetILProcessor();
- cursor = GetMethodNextInsertPosition(target, null, runtimeInjectType.HasFlag(InjectType.After));
- while (cursor != null)
- {
- bool bAfterInject = runtimeInjectType == InjectType.After;
- Instruction startPos = il.Create(OpCodes.Ldloc, flagDef);
- if (bAfterInject)
- {
- /// Replace instruction with references reserved
- Instruction endPos = il.Create(OpCodes.Ret);
- int replaceIndex = targetBody.Instructions.IndexOf(cursor);
- cursor.OpCode = startPos.OpCode;
- cursor.Operand = startPos.Operand;
- il.InsertAfter(targetBody.Instructions[replaceIndex], endPos);
- cursor = targetBody.Instructions[replaceIndex + 1];
- }
- else il.InsertBefore(cursor, startPos);
- il.InsertBefore(cursor, il.Create(ldcI4s[(int)InjectType.After / 2]));
- il.InsertBefore(cursor, il.Create(bAfterInject ? OpCodes.Bne_Un : OpCodes.Ble_Un, cursor));
- fillInjectInfo(target, runtimeInjectType);
- cursor = GetMethodNextInsertPosition(target, cursor, runtimeInjectType.HasFlag(InjectType.After));
- }
- }
- static void FillInjectInfo(MethodDefinition target, InjectType runtimeInjectType)
- {
- FillBaseCall(target, runtimeInjectType, true);
- FillLuaMethodCall(target, runtimeInjectType == InjectType.After);
- FillBaseCall(target, runtimeInjectType, false);
- FillJumpInfo(target, runtimeInjectType == InjectType.After);
- }
- static void FillBaseCall(MethodDefinition target, InjectType runtimeInjectType, bool preCall)
- {
- MethodBody targetBody = target.Body;
- ILProcessor il = targetBody.GetILProcessor();
- InjectType curBaseInjectType = preCall ? InjectType.ReplaceWithPreInvokeBase : InjectType.ReplaceWithPostInvokeBase;
- if (runtimeInjectType.HasFlag(curBaseInjectType))
- {
- Instruction end = il.Create(OpCodes.Nop);
- il.InsertBefore(cursor, end);
- il.InsertBefore(end, il.Create(OpCodes.Ldloc, flagDef));
- il.InsertBefore(end, il.Create(OpCodes.Ldc_I4, (int)curBaseInjectType));
- il.InsertBefore(end, il.Create(OpCodes.Bne_Un, end));
- FillArgs(target, end, PostProcessBaseMethodArg);
- il.InsertBefore(end, il.Create(OpCodes.Call, target.GetBaseMethodInstance()));
- if (!target.ReturnVoid())
- {
- il.InsertBefore(end, il.Create(OpCodes.Pop));
- }
- }
- }
- static void FillLuaMethodCall(MethodDefinition target, bool bConfirmPopReturnValue)
- {
- ILProcessor il = target.Body.GetILProcessor();
- Instruction start = il.Create(OpCodes.Ldloc, funcDef);
- if (cursor.Previous.OpCode == OpCodes.Nop)
- {
- cursor.Previous.OpCode = start.OpCode;
- cursor.Previous.Operand = start.Operand;
- }
- else
- {
- il.InsertBefore(cursor, start);
- }
- FillArgs(target, cursor, ParseArgumentReference);
- il.InsertBefore(cursor, il.Create(OpCodes.Call, GetLuaMethodInvoker(target, bConfirmPopReturnValue, false)));
- CacheResultTable(target, bConfirmPopReturnValue);
- UpdatePassedByReferenceParams(target, bConfirmPopReturnValue);
- }
- static void CacheResultTable(MethodDefinition target, bool bConfirmPopReturnValue)
- {
- ILProcessor il = target.Body.GetILProcessor();
- if (target.GotPassedByReferenceParam())
- {
- il.InsertBefore(cursor, il.Create(OpCodes.Stloc, GetResultTable(target)));
- }
- }
- static VariableDefinition GetResultTable(MethodDefinition target)
- {
- VariableDefinition luaTable = null;
- resultTableGroup.TryGetValue(target, out luaTable);
- if (luaTable == null)
- {
- luaTable = new VariableDefinition(luaTableTypeDef);
- target.Body.Variables.Add(luaTable);
- resultTableGroup.Add(target, luaTable);
- }
- return luaTable;
- }
- static void UpdatePassedByReferenceParams(MethodDefinition target, bool bConfirmPopReturnValue)
- {
- if (!target.GotPassedByReferenceParam())
- {
- return;
- }
- int updateCount = 0;
- ILProcessor il = target.Body.GetILProcessor();
- VariableDefinition luaTable = GetResultTable(target);
- var rawGetGenericMethod = luaTableTypeDef.Methods.Single(method => method.Name == "RawGetIndex");
- foreach (var param in target.Parameters)
- {
- if (!param.ParameterType.IsByReference)
- {
- continue;
- }
- var paramType = ElementType.For(param.ParameterType);
- il.InsertBefore(cursor, il.Create(OpCodes.Ldarg, param));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, luaTable));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldc_I4, ++updateCount));
- il.InsertBefore(cursor, il.Create(OpCodes.Call, rawGetGenericMethod.MakeGenericMethod(paramType)));
- if (paramType.IsValueType)
- {
- il.InsertBefore(cursor, il.Create(OpCodes.Stobj, paramType));
- }
- else
- {
- il.InsertBefore(cursor, il.Create(OpCodes.Stind_Ref));
- }
- }
- if (!bConfirmPopReturnValue && !target.ReturnVoid())
- {
- il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, luaTable));
- il.InsertBefore(cursor, il.Create(OpCodes.Ldc_I4, ++updateCount));
- il.InsertBefore(cursor, il.Create(OpCodes.Call, rawGetGenericMethod.MakeGenericMethod(target.ReturnType)));
- }
- }
- static void FillJumpInfo(MethodDefinition target, bool bConfirmPopReturnValue)
- {
- MethodBody targetBody = target.Body;
- ILProcessor il = targetBody.GetILProcessor();
- if (!bConfirmPopReturnValue)
- {
- Instruction retIns = il.Create(OpCodes.Ret);
- if (!injectType.HasFlag(InjectType.Before))
- {
- if (cursor.Previous.OpCode == OpCodes.Nop)
- {
- cursor.Previous.OpCode = retIns.OpCode;
- cursor.Previous.Operand = retIns.Operand;
- retIns = cursor.Previous;
- }
- else
- {
- il.InsertBefore(cursor, retIns);
- }
- }
- else
- {
- Instruction start = il.Create(OpCodes.Ldloc, flagDef);
- if (cursor.Previous.OpCode == OpCodes.Nop)
- {
- cursor.Previous.OpCode = start.OpCode;
- cursor.Previous.Operand = start.Operand;
- il.InsertAfter(cursor.Previous, retIns);
- }
- else
- {
- il.InsertBefore(cursor, retIns);
- il.InsertBefore(retIns, start);
- }
- Instruction popIns = il.Create(OpCodes.Pop);
- bool bGotReturnValue = !target.ReturnVoid();
- if (bGotReturnValue)
- {
- il.InsertBefore(cursor, popIns);
- }
- il.InsertBefore(retIns, il.Create(ldcI4s[(int)InjectType.Before / 2]));
- il.InsertBefore(retIns, il.Create(OpCodes.Ble_Un, bGotReturnValue ? popIns : cursor));
- }
- }
- else if (cursor.Previous.OpCode == OpCodes.Nop)
- {
- targetBody.Instructions.Remove(cursor.Previous);
- }
- }
- #endregion NormalMethod
- static void FillArgs(MethodDefinition target, Instruction endPoint, Action<MethodDefinition, Instruction, int> parseReferenceProcess)
- {
- MethodBody targetBody = target.Body;
- ILProcessor il = targetBody.GetILProcessor();
- int paramCount = target.Parameters.Count + (target.HasThis ? 1 : 0);
- for (int i = 0; i < paramCount; ++i)
- {
- if (i < ldargs.Length)
- {
- il.InsertBefore(endPoint, il.Create(ldargs[i]));
- }
- else if (i <= byte.MaxValue)
- {
- il.InsertBefore(endPoint, il.Create(OpCodes.Ldarg_S, (byte)i));
- }
- else
- {
- il.InsertBefore(endPoint, il.Create(OpCodes.Ldarg, (short)i));
- }
- if (parseReferenceProcess != null)
- {
- parseReferenceProcess(target, endPoint, i);
- }
- }
- }
- static void PostProcessBaseMethodArg(MethodDefinition target, Instruction endPoint, int paramIndex)
- {
- var declaringType = target.DeclaringType;
- ILProcessor il = target.Body.GetILProcessor();
- if (paramIndex == 0 && declaringType.IsValueType)
- {
- il.InsertBefore(endPoint, il.Create(OpCodes.Ldobj, declaringType));
- il.InsertBefore(endPoint, il.Create(OpCodes.Box, declaringType));
- }
- }
- static void ParseArgumentReference(MethodDefinition target, Instruction endPoint, int paramIndex)
- {
- ParameterDefinition param = null;
- ILProcessor il = target.Body.GetILProcessor();
- if (target.HasThis)
- {
- if (paramIndex > 0)
- {
- param = target.Parameters[paramIndex - 1];
- }
- else if (target.DeclaringType.IsValueType)
- {
- il.InsertBefore(endPoint, il.Create(OpCodes.Ldobj, target.DeclaringType));
- }
- }
- else if (!target.HasThis)
- {
- param = target.Parameters[paramIndex];
- }
- if (param != null && param.ParameterType.IsByReference)
- {
- TypeReference paramType = ElementType.For(param.ParameterType);
- if (paramType.IsValueType)
- {
- il.InsertBefore(endPoint, il.Create(OpCodes.Ldobj, paramType));
- }
- else
- {
- il.InsertBefore(endPoint, il.Create(OpCodes.Ldind_Ref));
- }
- }
- }
- static Instruction GetMethodNextInsertPosition(MethodDefinition target, Instruction curPoint, bool bInsertBeforeRet)
- {
- MethodBody targetBody = target.Body;
- if (target.IsConstructor || bInsertBeforeRet)
- {
- if (curPoint != null)
- {
- return targetBody.Instructions
- .SkipWhile(ins => ins != curPoint)
- .FirstOrDefault(ins => ins != curPoint && ins.OpCode == OpCodes.Ret);
- }
- else
- {
- return targetBody.Instructions
- .FirstOrDefault(ins => ins.OpCode == OpCodes.Ret);
- }
- }
- else
- {
- if (curPoint != null) return null;
- else return targetBody.Instructions[offset];
- }
- }
- static InjectType GetMethodRuntimeInjectType(MethodDefinition target)
- {
- InjectType type = injectType;
- //bool bOverrideParantMethodFlag = target.IsVirtual && target.IsReuseSlot;
- var parantMethod = target.GetBaseMethodInstance();
- if (target.IsConstructor)
- {
- type &= ~InjectType.Before;
- type &= ~InjectType.Replace;
- type &= ~InjectType.ReplaceWithPostInvokeBase;
- type &= ~InjectType.ReplaceWithPreInvokeBase;
- }
- else if (parantMethod == null || target.IsEnumerator())
- {
- type &= ~InjectType.ReplaceWithPostInvokeBase;
- type &= ~InjectType.ReplaceWithPreInvokeBase;
- }
- else if (!target.HasBody)
- {
- type &= ~InjectType.After;
- type &= ~InjectType.Before;
- }
- return type;
- }
- static MethodReference GetLuaMethodInvoker(MethodDefinition prototypeMethod, bool bIgnoreReturnValue, bool bAppendCoroutineState)
- {
- MethodReference injectMethod = null;
- GetLuaInvoker(prototypeMethod, bIgnoreReturnValue, bAppendCoroutineState, ref injectMethod);
- FillLuaInvokerGenericArguments(prototypeMethod, bIgnoreReturnValue, bAppendCoroutineState, ref injectMethod);
- return injectMethod;
- }
- static void GetLuaInvoker(MethodDefinition prototypeMethod, bool bIgnoreReturnValue, bool bAppendCoroutineState, ref MethodReference invoker)
- {
- bool bRequireResult = prototypeMethod.GotPassedByReferenceParam()
- || (!bIgnoreReturnValue && !prototypeMethod.ReturnVoid());
- string methodName = bRequireResult ? "Invoke" : "Call";
- int paramCount = prototypeMethod.Parameters.Count;
- int paramExtraCount = prototypeMethod.HasThis ? 1 : 0;
- paramExtraCount = bAppendCoroutineState ? paramExtraCount + 1 : paramExtraCount;
- paramCount += paramExtraCount;
- invoker = luaFunctionTypeDef.Methods.FirstOrDefault(method =>
- {
- return method.Name == methodName && method.Parameters.Count == paramCount && bRequireResult == !method.ReturnVoid();
- });
- if (invoker == null)
- {
- Debug.Log(prototypeMethod.FullName + " Got too many parameters!!!Skipped!!!");
- }
- }
- static void FillLuaInvokerGenericArguments(MethodDefinition prototypeMethod, bool bIgnoreReturnValue, bool bAppendCoroutineState, ref MethodReference invoker)
- {
- if (invoker.HasGenericParameters)
- {
- GenericInstanceMethod genericInjectMethod = new GenericInstanceMethod(invoker.CloneMethod());
- if (prototypeMethod.HasThis)
- {
- genericInjectMethod.GenericArguments.Add(prototypeMethod.DeclaringType);
- }
- foreach (ParameterDefinition parameter in prototypeMethod.Parameters)
- {
- var paramType = parameter.ParameterType.IsByReference ? ElementType.For(parameter.ParameterType) : parameter.ParameterType;
- genericInjectMethod.GenericArguments.Add(paramType);
- }
- if (bAppendCoroutineState)
- {
- genericInjectMethod.GenericArguments.Add(intTypeRef);
- }
- if (prototypeMethod.GotPassedByReferenceParam())
- {
- genericInjectMethod.GenericArguments.Add(luaTableTypeDef);
- }
- else if (!bIgnoreReturnValue && !prototypeMethod.ReturnVoid())
- {
- genericInjectMethod.GenericArguments.Add(prototypeMethod.ReturnType);
- }
- invoker = genericInjectMethod;
- }
- }
- static void UpdateInjectionCacheSize()
- {
- var staticConstructor = injectStationTypeDef.Methods.Single((method) =>
- {
- return method.Name == ".cctor";
- });
- var il = staticConstructor.Body.GetILProcessor();
- Instruction loadStaticFieldIns = null;
- loadStaticFieldIns = staticConstructor
- .Body
- .Instructions
- .FirstOrDefault(ins =>
- {
- return ins.OpCode == OpCodes.Ldsfld
- && (ins.Operand as FieldReference).Name == "cacheSize";
- });
- var loadCacheSizeIns = il.Create(OpCodes.Ldc_I4, methodCounter + 1);
- il.InsertBefore(loadStaticFieldIns, loadCacheSizeIns);
- il.InsertBefore(loadStaticFieldIns, il.Create(OpCodes.Stsfld, (loadStaticFieldIns.Operand as FieldReference)));
- }
- static void WriteInjectedAssembly(AssemblyDefinition assembly, string assemblyPath)
- {
- var writerParameters = new WriterParameters { WriteSymbols = EnableSymbols };
- assembly.Write(assemblyPath, writerParameters);
- }
- static void ExportInjectionBridgeInfo()
- {
- ExportInjectionPublishInfo(bridgeInfo);
- ExportInjectionEditorInfo(bridgeInfo);
- }
- static void ExportInjectionPublishInfo(SortedDictionary<string, List<InjectedMethodInfo>> data)
- {
- var temp = data.ToDictionary(
- typeInfo => typeInfo.Key,
- typeinfo =>
- {
- return typeinfo.Value
- .OrderBy(methodInfo => methodInfo.methodPublishedName)
- .ToDictionary(
- methodInfo => methodInfo.methodPublishedName,
- methodInfo => methodInfo.methodIndex
- );
- }
- );
- StringBuilder sb = StringBuilderCache.Acquire();
- sb.Append("return ");
- ToLuaText.TransferDic(temp, sb);
- sb.Remove(sb.Length - 1, 1);
- File.WriteAllText(CustomSettings.baseLuaDir + "System/Injection/InjectionBridgeInfo.lua", StringBuilderCache.GetStringAndRelease(sb));
- }
- static int AppendMethod(MethodDefinition method)
- {
- string methodSignature = GetMethodSignature(method);
- string methodFullSignature = method.FullName;
- InjectedMethodInfo newInfo = new InjectedMethodInfo();
- string typeName = ToLuaInjectionHelper.GetTypeName(method.DeclaringType, true);
- List<InjectedMethodInfo> typeMethodIndexGroup = null;
- bridgeInfo.TryGetValue(typeName, out typeMethodIndexGroup);
- if (typeMethodIndexGroup == null)
- {
- typeMethodIndexGroup = new List<InjectedMethodInfo>();
- newInfo.methodPublishedName = method.Name;
- bridgeInfo.Add(typeName, typeMethodIndexGroup);
- }
- else
- {
- InjectedMethodInfo existInfo = typeMethodIndexGroup.Find(info => info.methodOverloadSignature == methodSignature);
- if (existInfo == null)
- {
- existInfo = typeMethodIndexGroup.Find(info => info.methodName == method.Name);
- if (existInfo != null)
- {
- newInfo.methodPublishedName = methodSignature;
- existInfo.methodPublishedName = existInfo.methodOverloadSignature;
- }
- else
- {
- newInfo.methodPublishedName = method.Name;
- }
- }
- else
- {
- if (existInfo.methodFullSignature != methodFullSignature)
- {
- Debug.LogError(typeName + "." + existInfo.methodPublishedName + " 签名跟历史签名不一致,无法增量,Injection中断,请修改函数签名、或者直接删掉InjectionBridgeEditorInfo.xml(该操作会导致无法兼容线上版的包体,需要强制换包)!");
- EditorPrefs.SetInt(Application.dataPath + "WaitForInjection", 0);
- return -1;
- }
- return existInfo.methodIndex;
- }
- }
- newInfo.methodName = method.Name;
- newInfo.methodOverloadSignature = methodSignature;
- newInfo.methodFullSignature = methodFullSignature;
- newInfo.methodIndex = ++methodCounter;
- typeMethodIndexGroup.Add(newInfo);
- return methodCounter;
- }
- static string GetMethodSignature(MethodDefinition method)
- {
- StringBuilder paramsTypeNameBuilder = StringBuilderCache.Acquire();
- paramsTypeNameBuilder.Append(method.Name);
- foreach (var param in method.Parameters)
- {
- paramsTypeNameBuilder
- .Append("-")
- .Append(ToLuaInjectionHelper.GetTypeName(param.ParameterType));
- }
- return StringBuilderCache.GetStringAndRelease(paramsTypeNameBuilder);
- }
- static void ExportInjectionEditorInfo(SortedDictionary<string, List<InjectedMethodInfo>> data)
- {
- string incrementalFilePath = CustomSettings.injectionFilesPath + "InjectionBridgeEditorInfo.xml";
- if (File.Exists(incrementalFilePath))
- {
- File.Delete(incrementalFilePath);
- }
- var doc = new XmlDocument();
- var fileInforRoot = doc.CreateElement("Root");
- doc.AppendChild(fileInforRoot);
- foreach (var type in data)
- {
- XmlElement typeNode = doc.CreateElement("Type");
- typeNode.SetAttribute("Name", type.Key);
- var sortedMethodsGroup = type.Value.OrderBy(info => info.methodPublishedName);
- foreach (var method in sortedMethodsGroup)
- {
- XmlElement typeMethodNode = doc.CreateElement("Method");
- typeMethodNode.SetAttribute("Name", method.methodName);
- typeMethodNode.SetAttribute("PublishedName", method.methodPublishedName);
- typeMethodNode.SetAttribute("Signature", method.methodOverloadSignature);
- typeMethodNode.SetAttribute("FullSignature", method.methodFullSignature);
- typeMethodNode.SetAttribute("Index", method.methodIndex.ToString());
- typeNode.AppendChild(typeMethodNode);
- }
- fileInforRoot.AppendChild(typeNode);
- }
- doc.Save(incrementalFilePath);
- }
- static bool LoadBridgeEditorInfo()
- {
- bridgeInfo.Clear();
- methodCounter = 0;
- string incrementalFilePath = CustomSettings.injectionFilesPath + "InjectionBridgeEditorInfo.xml";
- if (!File.Exists(incrementalFilePath))
- {
- return true;
- }
- var doc = new XmlDocument();
- doc.Load(incrementalFilePath);
- var fileInfoRoot = doc.FindChildByName("Root");
- if (fileInfoRoot == null)
- {
- return true;
- }
- foreach (XmlNode typeChild in fileInfoRoot.ChildNodes)
- {
- List<InjectedMethodInfo> typeMethodInfo = new List<InjectedMethodInfo>();
- string typeName = typeChild.FindAttributeByName("Name").Value;
- foreach (XmlNode methodChild in typeChild.ChildNodes)
- {
- InjectedMethodInfo info = new InjectedMethodInfo();
- info.methodName = methodChild.FindAttributeByName("Name").Value;
- info.methodPublishedName = methodChild.FindAttributeByName("PublishedName").Value;
- info.methodOverloadSignature = methodChild.FindAttributeByName("Signature").Value;
- info.methodFullSignature = methodChild.FindAttributeByName("FullSignature").Value;
- info.methodIndex = int.Parse(methodChild.FindAttributeByName("Index").Value);
- typeMethodInfo.Add(info);
- methodCounter = Math.Max(methodCounter, info.methodIndex);
- }
- bridgeInfo.Add(typeName, typeMethodInfo);
- }
- return true;
- }
- static void Clean(AssemblyDefinition assembly)
- {
- if (assembly.MainModule.SymbolReader != null)
- {
- assembly.MainModule.SymbolReader.Dispose();
- }
- }
- static void CacheInjectableTypeGroup()
- {
- injectableTypeGroup.Clear();
- Assembly assebly = Assembly.Load("Assembly-CSharp");
- foreach (Type t in assebly.GetTypes())
- {
- if (DoesTypeInjectable(t))
- {
- injectableTypeGroup.Add(t.FullName);
- }
- }
- }
- static bool DoesTypeInjectable(Type type)
- {
- if (dropTypeGroup.Contains(type.FullName) || (type.DeclaringType != null && dropTypeGroup.Contains(type.DeclaringType.FullName)))
- {
- return false;
- }
- if (type.IsGenericType)
- {
- Type genericTypeDefinition = type.GetGenericTypeDefinition();
- if (dropGenericNameGroup.Contains(genericTypeDefinition.FullName))
- {
- return false;
- }
- }
- if (typeof(System.Delegate).IsAssignableFrom(type))
- {
- return false;
- }
- if (type.FullName.Contains("<") || type.IsInterface)
- {
- return false;
- }
- if (!injectIgnoring.HasFlag(InjectFilter.IgnoreNoToLuaAttr))
- {
- foreach (var attr in type.GetCustomAttributes(true))
- {
- Type attrT = attr.GetType();
- if (attrT == typeof(LuaInterface.NoToLuaAttribute))
- {
- return false;
- }
- }
- }
- return true;
- }
- static bool DoesTypeInjectable(TypeDefinition type)
- {
- if (dropNamespaceGroup.Contains(type.SafeNamespace()))
- {
- return false;
- }
- if (!injectableTypeGroup.Contains(type.FullName.Replace("/", "+")))
- {
- return false;
- }
- if (injectIgnoring.HasFlag(InjectFilter.IgnoreConstructor) && type.Methods.Count == 1)
- {
- return false;
- }
- if (!injectIgnoring.HasFlag(InjectFilter.IgnoreNoToLuaAttr))
- {
- if (type.CustomAttributes.Any((attr) => attr.AttributeType == noToLuaAttrTypeRef))
- {
- return false;
- }
- }
- return true;
- }
- static bool DoesMethodInjectable(MethodDefinition method)
- {
- if (method.IsSpecialName)
- {
- if (method.Name == ".cctor")
- {
- return false;
- }
- bool bIgnoreConstructor = injectIgnoring.HasFlag(InjectFilter.IgnoreConstructor)
- || method.DeclaringType.IsAssignableTo("UnityEngine.MonoBehaviour")
- || method.DeclaringType.IsAssignableTo("UnityEngine.ScriptableObject");
- if (method.IsConstructor)
- {
- if (bIgnoreConstructor)
- {
- return false;
- }
- }
- else
- {
- ///Skip add_、remove_、op_、Finalize
- if (!method.IsGetter && !method.IsSetter)
- {
- return false;
- }
- }
- }
- if (method.Name.Contains("<") || method.IsUnmanaged || method.IsAbstract || method.IsPInvokeImpl || !method.HasBody)
- {
- return false;
- }
- /// Skip Unsafe
- if (method.Body.Variables.Any(var => var.VariableType.IsPointer) || method.Parameters.Any(param => param.ParameterType.IsPinned))
- {
- return false;
- }
- /// Hmm... Sometimes method.IsSpecialName Got False
- if (method.Name == "Finalize")
- {
- return false;
- }
- if ((method.IsGetter || method.IsSetter) && injectIgnoring.HasFlag(InjectFilter.IgnoreProperty))
- {
- return false;
- }
- if (!injectIgnoring.HasFlag(InjectFilter.IgnoreNoToLuaAttr))
- {
- if (method.CustomAttributes.Any((attr) => attr.AttributeType == noToLuaAttrTypeRef))
- {
- return false;
- }
- }
- if (method.ReturnType.IsAssignableTo("System.Collections.IEnumerable"))
- {
- return false;
- }
- MethodReference luaInjector = null;
- GetLuaInvoker(method, true, false, ref luaInjector);
- if (luaInjector == null)
- {
- return false;
- }
- return true;
- }
- static bool LoadBlackList()
- {
- if (File.Exists(InjectionBlackListGenerator.blackListFilePath))
- {
- dropTypeGroup.UnionWith(File.ReadAllLines(InjectionBlackListGenerator.blackListFilePath));
- dropTypeGroup.ExceptWith(forceInjectTypeGroup);
- }
- else
- {
- if (EditorUtility.DisplayDialog("警告", "由于Injection会额外增加代码量,故可以先设置一些Injection跳过的代码目录(比如NGUI插件代码目录),减少生成的代码量", "设置黑名单", "全量生成"))
- {
- InjectionBlackListGenerator.Open();
- InjectionBlackListGenerator.onBlackListGenerated += InjectAll;
- return false;
- }
- }
- return true;
- }
- }
- public static class SystemXMLExtension
- {
- public static XmlNode FindChildByName(this XmlNode root, string childName)
- {
- var child = root.FirstChild;
- while (child != null)
- {
- if (child.Name.Equals(childName))
- {
- return child;
- }
- else
- {
- child = child.NextSibling;
- }
- }
- return null;
- }
- public static XmlAttribute FindAttributeByName(this XmlNode node, string attributeName)
- {
- var attributeCollection = node.Attributes;
- for (int i = 0; i < attributeCollection.Count; i++)
- {
- if (attributeCollection[i].Name.Equals(attributeName))
- {
- return attributeCollection[i];
- }
- }
- return null;
- }
- }
- #endif
|