private static MethodDefinition BootstrapMethodTo(AssemblyDefinition whichAssToReplaceIn, MethodDefinition definitionOldMethod, TypeDefinition definitionTypeReturn, MethodDefinition delegateToMethod) { ModuleDefinition main = whichAssToReplaceIn.MainModule; definitionOldMethod.Name = $"{definitionOldMethod.Name}BackupCall"; //Create new method and use it instead var definitionNewMethod = new MethodDefinition( "CreateNew", MethodAttributes.Public | MethodAttributes.Static, definitionOldMethod.ReturnType); definitionNewMethod.Parameters.Add( definitionOldMethod.Parameters[0]); definitionTypeReturn.Methods.Add(definitionNewMethod); { var processor = definitionNewMethod.Body.GetILProcessor(); processor.Body.Instructions.Clear(); processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, main.ImportReference(delegateToMethod)); processor.Emit(OpCodes.Ret); } CallHelper.ReplaceCall(definitionOldMethod, definitionNewMethod, whichAssToReplaceIn); return(definitionNewMethod); }
public override void Instrument(AnankeContext ananke, AssemblyDefinition ass) { var main = ass.MainModule; AssemblyDefinition attachment = AssemblyDefinition.ReadAssembly("Ananke.Attachment.Core.dll"); //TODO: Deduplicate code //SoLInventoryItemHandlerBypass { var bootstrapMethod = attachment.MainModule.Types.First(t => t.Name == "SoLInventoryItemHandlerBypass") .Methods .First(m => m.IsStatic && m.Name == "GetNewItemByItemType"); var inventoryItemHandlerTypedef = main.Types.First(t => t.Name == "InventoryItemHandler"); var getNewItemByItemTypeMethoddef = inventoryItemHandlerTypedef.Methods.First(m => m.Name == "GetNewItemByItemType"); getNewItemByItemTypeMethoddef.Name = "GetNewItemByItemTypeAnankeBackupCall"; var getNewItemByItemTypeMethoddefExternationProbe = new MethodDefinition( "GetNewItemByItemType", MethodAttributes.Public | MethodAttributes.Static, getNewItemByItemTypeMethoddef.ReturnType); getNewItemByItemTypeMethoddefExternationProbe.Parameters.Add( getNewItemByItemTypeMethoddef.Parameters[0]); inventoryItemHandlerTypedef.Methods.Add(getNewItemByItemTypeMethoddefExternationProbe); { var processor = getNewItemByItemTypeMethoddefExternationProbe.Body.GetILProcessor(); processor.Body.Instructions.Clear(); processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, main.ImportReference(bootstrapMethod)); processor.Emit(OpCodes.Ret); } CallHelper.ReplaceCall(getNewItemByItemTypeMethoddef, getNewItemByItemTypeMethoddefExternationProbe, ass); } //SoLStaticLivingEntityInlineRegistryBypass { var bootstrapMethod = attachment.MainModule.Types .First(t => t.Name == "SoLStaticLivingEntityInlineRegistryBypass").Methods.First(m => m.IsStatic && m.Name == "GetNewLivingEntityByStaticPrefabType"); var definitionTypeReturn = main.Types.First(t => t.Name == "LivingEntity"); var definitionTypeEnumerator = main.Types.First(t => t.Name == "LivingEntityType"); var definitionOldMethod = definitionTypeReturn.Methods.First(m => m.Name == "CreateNew" && m.Parameters[0].ParameterType == definitionTypeEnumerator); BootstrapMethodTo(ass, definitionOldMethod, definitionTypeReturn, bootstrapMethod); var bootstrapNameToTypeMethod = attachment.MainModule.Types .First(t => t.Name == "SoLStaticLivingEntityInlineRegistryBypass").Methods.First(m => m.IsStatic && m.Name == "GetNewLivingEntityTypeByName"); var definitionNameToTypeOldMethod = definitionTypeReturn.Methods.First(m => m.Name == "GetLivingEntityTypeByName"); BootstrapMethodTo(ass, definitionNameToTypeOldMethod, definitionTypeReturn, bootstrapNameToTypeMethod); } /* * TODO PRODUCTION CRITICAL: * OVERRIDE GetNewStaticPrefabByName as well otherwise * Workshop(yes, it is at least partially is in the game) support * and multiplayer will break. */ //SoLStaticPrefabBypass { var bootstrapMethod = attachment.MainModule.Types.First(t => t.Name == "SoLStaticPrefabInlineRegistryBypass") .Methods .First(m => m.IsStatic && m.Name == "GetNewStaticPrefabByStaticPrefabType"); var inventoryItemHandlerTypedef = main.Types.First(t => t.Name == "StaticPrefab"); var getNewItemByItemTypeMethoddef = inventoryItemHandlerTypedef.Methods.First(m => m.Name == "GetNewStaticPrefabByStaticPrefabType"); getNewItemByItemTypeMethoddef.Name = "GetNewStaticPrefabByStaticPrefabTypeAnankeBackupCall"; var getNewItemByItemTypeMethoddefExternationProbe = new MethodDefinition( "GetNewStaticPrefabByStaticPrefabType", MethodAttributes.Public | MethodAttributes.Static, getNewItemByItemTypeMethoddef.ReturnType); getNewItemByItemTypeMethoddefExternationProbe.Parameters.Add( getNewItemByItemTypeMethoddef.Parameters[0]); inventoryItemHandlerTypedef.Methods.Add(getNewItemByItemTypeMethoddefExternationProbe); { var processor = getNewItemByItemTypeMethoddefExternationProbe.Body.GetILProcessor(); processor.Body.Instructions.Clear(); processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, main.ImportReference(bootstrapMethod)); processor.Emit(OpCodes.Ret); } CallHelper.ReplaceCall(getNewItemByItemTypeMethoddef, getNewItemByItemTypeMethoddefExternationProbe, ass); } //Phase hook OnAfterInitialRecipesWereLoaded { var delegatorMethod = attachment.MainModule.Types.First(t => t.Name == "SoLPhaseDelegator").Methods .First(m => m.IsStatic && m.Name == "OnAfterInitialRecipesWereLoaded"); var solClass = main.Types.FirstOrDefault(t => t.Name == "SpaceGame"); var solClassLoadContentMethod = solClass.Methods.FirstOrDefault(m => m.Name == "LoadContent"); var solClassLoadContentMethodIL = solClassLoadContentMethod.Body.GetILProcessor(); var ilcodeCall = solClassLoadContentMethodIL.Create(OpCodes.Call, main.ImportReference(delegatorMethod)); solClassLoadContentMethodIL.InsertAfter( solClassLoadContentMethodIL.Body.Instructions.First(i => i.OpCode == OpCodes.Call && ((MethodReference)i.Operand).Name.Contains("GetRecipes")).Next,//We pick a call and step after result assignment ilcodeCall ); } }