public WorkTab(ModContentPack mod) { // Changing priorities var type = AccessTools.TypeByName("WorkTab.PriorityManager"); MP.RegisterSyncMethod(AccessTools.PropertySetter(type, "ShowPriorities")); type = AccessTools.TypeByName("WorkTab.Pawn_Extensions"); MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkTypeDef), typeof(int), typeof(List <int>) })); MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkTypeDef), typeof(int), typeof(int), typeof(bool) })); MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkGiverDef), typeof(int), typeof(List <int>) })); MP.RegisterSyncMethod(AccessTools.Method(type, "SetPriority", new[] { typeof(Pawn), typeof(WorkGiverDef), typeof(int), typeof(int), typeof(bool) })); // This one not needed as it calls SetPriority, but it'll // end up calling it numerous times - let's just do it in one command. MP.RegisterSyncMethod(type, "DisableAll"); // Technically we don't have to do this, as pasting calls SetPriority... // But well, it ends up being called almost 2000 times in vanilla with DLCs alone... // So I felt like it'll be smarter to sync it as a single command instead of potentially // couple thousand with mods. type = AccessTools.TypeByName("WorkTab.PawnColumnWorker_CopyPasteDetailedWorkPriorities"); copyPasteColumnWorkerConstructor = AccessTools.DeclaredConstructor(type); clipboardField = AccessTools.StaticFieldRefAccess <Dictionary <WorkGiverDef, int[]> >(AccessTools.Field(type, "clipboard")); var method = AccessTools.Method(type, "PasteTo"); pasteToMethod = AccessTools.MethodDelegate <PasteTo>(method); MpCompat.harmony.Patch(method, prefix: new HarmonyMethod(typeof(WorkTab), nameof(PrePasteTo))); MP.RegisterSyncMethod(typeof(WorkTab), nameof(SyncedPasteTo)); // We don't really need to sync those, but not doing so will end up with // a bunch of unnecessary synced calls (one per colonists) // Sadly, there isn't a call like that in case of checkbox priorities - only numeric ones var types = new (string typeName, Type parameterType)[]
/********* ** Public methods *********/ public static ConstructorInfo DeclaredConstructor(Type type, Type[] parameters = null) { // Harmony 1.x matched both static and instance constructors return (AccessTools.DeclaredConstructor(type, parameters, searchForStatic: false) ?? AccessTools.DeclaredConstructor(type, parameters, searchForStatic: true)); }
public static void LatePatch() { // Ancient PD turret - toggle aiming at drop pods, enemies, explosive projectiles MpCompat.RegisterLambdaMethod("VFEAncients.Building_TurretPD", "GetGizmos", 1, 3, 5); var type = AccessTools.TypeByName("VFEAncients.CompGeneTailoringPod"); // Start gene tailoring operation (after danger warning confirmation) MP.RegisterSyncMethod(type, "StartOperation"); // Cancel operation (before starting it) MpCompat.RegisterLambdaMethod(type, "CompGetGizmosExtra", 8); // (Dev) instant success/failure MpCompat.RegisterLambdaMethod(type, "CompGetGizmosExtra", 9, 10).SetDebugOnly(); // (Dev) instant finish, random result not synced, as it calls CompleteOperation // would cause a tiny conflict, not worth bothering with it // (I think it would need to be done without SetDebugOnly, or it would cause issues) choosePowerDialogType = AccessTools.TypeByName("VFEAncients.Dialog_ChoosePowers"); var powerDefType = AccessTools.TypeByName("VFEAncients.PowerDef"); var tupleType = typeof(Tuple <,>).MakeGenericType(powerDefType, powerDefType); onChosen = CompileCallOnChosen(powerDefType, tupleType); MP.RegisterSyncMethod(typeof(VanillaFactionsAncients), nameof(SyncedChoosePower)); MP.RegisterSyncWorker <Window>(SyncDialogChoosePower, choosePowerDialogType); MpCompat.harmony.Patch(AccessTools.DeclaredConstructor(choosePowerDialogType, new[] { typeof(List <>).MakeGenericType(tupleType), typeof(Pawn), typeof(Action <>).MakeGenericType(tupleType) }), postfix: new HarmonyMethod(typeof(VanillaFactionsAncients), nameof(PostDialogConstructor))); MpCompat.harmony.Patch(AccessTools.Method(choosePowerDialogType, nameof(Window.DoWindowContents)), transpiler: new HarmonyMethod(typeof(VanillaFactionsAncients), nameof(ReplaceButtons))); }
private static void EmitConvertArgumentToManaged(ILGenerator il, Type managedParamType, out LocalBuilder variable) { variable = null; if (managedParamType.IsValueType) // don't need to convert blittable types { return; } void EmitCreateIl2CppObject() { Label endLabel = il.DefineLabel(); Label notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Br_S, endLabel); il.MarkLabel(notNullLabel); il.Emit(OpCodes.Newobj, AccessTools.DeclaredConstructor(managedParamType, new[] { typeof(IntPtr) })); il.MarkLabel(endLabel); } void HandleTypeConversion(Type originalType) { if (originalType == typeof(string)) { il.Emit(OpCodes.Call, IL2CPPToManagedStringMethodInfo); } else if (originalType.IsSubclassOf(typeof(Il2CppObjectBase))) { EmitCreateIl2CppObject(); } } if (managedParamType.IsByRef) { Type directType = managedParamType.GetElementType(); variable = il.DeclareLocal(directType); il.Emit(OpCodes.Ldind_I); HandleTypeConversion(directType); il.Emit(OpCodes.Stloc, variable); il.Emit(OpCodes.Ldloca, variable); } else { HandleTypeConversion(managedParamType); } }
public MethodBase ParseMethod() { // Parse & retrieve the base type. Type type = ParseType(); expectToken("::"); // Parse the method name string name = getToken("method name"); // Parse parameters, if specified. Type[] parameters = null; if (!end()) { expectToken("("); parameters = ParseTypes(); expectToken(")"); } // Retrieve the method. MethodBase method; if (name == ".ctor") { if (parameters == null) { // If no parameters are specified, assume there is a unique constructor. var array = type.GetConstructors(); if (array.Length != 1) { throw new Exception($"Found {array.Length} matching constructors for \"{sig}\"."); } method = array[0]; } else { method = AccessTools.DeclaredConstructor(type, parameters); } if (method == null) { throw new Exception($"Failed to find constructor \"{sig}\"."); } } else { method = AccessTools.DeclaredMethod(type, name, parameters); if (method == null) { throw new Exception($"Failed to find method \"{sig}\"."); } } return(method); }
public static MethodBase GetOriginalMethod(HarmonyMethod attr) { if (attr.declaringType == null) { return(null); } if (attr.methodType == null) { attr.methodType = MethodType.Normal; } switch (attr.methodType) { case MethodType.Normal: if (attr.methodName == null) { return(null); } return(AccessTools.DeclaredMethod( attr.declaringType, attr.methodName, attr.argumentTypes)); case MethodType.Getter: if (attr.methodName == null) { return(null); } return(AccessTools.DeclaredProperty(attr.declaringType, attr.methodName) .GetGetMethod(true)); case MethodType.Setter: if (attr.methodName == null) { return(null); } return(AccessTools.DeclaredProperty(attr.declaringType, attr.methodName) .GetSetMethod(true)); case MethodType.Constructor: return(AccessTools.DeclaredConstructor(attr.declaringType, attr.argumentTypes)); case MethodType.StaticConstructor: return(AccessTools.GetDeclaredConstructors(attr.declaringType) .FirstOrDefault(c => c.IsStatic)); } return(null); }
private static void AfterMainMenuDraw(ILContext il) { ILCursor c = new ILCursor(il); c.GotoNext(MoveType.AfterLabel, x => x.MatchCallOrCallvirt(typeof(GuiData), nameof(GuiData.endDraw)) ); c.Emit(OpCodes.Ldarg_0); c.Emit(OpCodes.Newobj, AccessTools.DeclaredConstructor(typeof(DrawMainMenuEvent), new Type[] { typeof(MainMenu) })); c.Emit(OpCodes.Call, AccessTools.DeclaredMethod(typeof(EventManager <DrawMainMenuEvent>), nameof(EventManager <DrawMainMenuEvent> .InvokeAll))); }
private static IEnumerable <CodeInstruction> WidgetPrefab_LoadFrom_Transpiler(IEnumerable <CodeInstruction> instructions, MethodBase method) { var instructionsList = instructions.ToList(); IEnumerable <CodeInstruction> ReturnDefault(string place) { Utils.DisplayUserWarning("Failed to patch WidgetPrefab.LoadFrom! {0}", place); return(instructionsList.AsEnumerable()); } var constructor = AccessTools.DeclaredConstructor(typeof(WidgetPrefab)); var locals = method.GetMethodBody()?.LocalVariables; var typeLocal = locals?.FirstOrDefault(x => x.LocalType == typeof(WidgetPrefab)); if (typeLocal == null) { return(ReturnDefault("Local not found")); } var startIndex = -1; for (var i = 0; i < instructionsList.Count - 2; i++) { if (instructionsList[i + 0].opcode != OpCodes.Newobj || !Equals(instructionsList[i + 0].operand, constructor)) { continue; } if (!instructionsList[i + 1].IsStloc()) { continue; } startIndex = i; break; } if (startIndex == -1) { return(ReturnDefault("Pattern not found")); } // PrefabComponent.Load(path, xmlDocument); instructionsList.InsertRange(startIndex + 1, new List <CodeInstruction> { new CodeInstruction(OpCodes.Ldarg_2), new CodeInstruction(OpCodes.Ldloc_0), new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(() => ProcessMovie(null !, null !))) });
/// <summary> /// 启用事务追踪 /// </summary> /// <param name="instance"></param> private static void SetupTransactionScopeDebug(HarmonyInstance instance) { var patchClass = typeof(SQLDebug); if (_debugConfig == null) { return; } if (_debugConfig.IsTraceCustomizeTransaction) { Type ubfTransactionScopeType = typeof(UBFTransactionScope); ConstructorInfo ubfTransactionScopeConstructor = AccessTools.DeclaredConstructor( ubfTransactionScopeType, new[] { typeof(TransactionOption) }); var prefixUBFTransactionScopeConstructorMethod = patchClass.GetMethod("PrefixUBFTransactionScopeConstructor"); var PostfixUBFTransactionScopeConstructorMethod = patchClass.GetMethod("PostfixUBFTransactionScopeConstructor"); var patcherUBFTransactionScopeConstructor = new PatchProcessor(instance, new List <MethodBase> { ubfTransactionScopeConstructor }, new HarmonyMethod(prefixUBFTransactionScopeConstructorMethod), new HarmonyMethod(PostfixUBFTransactionScopeConstructorMethod)); patcherUBFTransactionScopeConstructor.Patch(); } if (_debugConfig.IsTraceBPSVTransaction) { Type transactionAttributeType = typeof(TransactionAttribute); var transactionAttributeProcessMethod = AccessTools.Method(transactionAttributeType, "Process", new[] { typeof(object) }); var prefixTransactionAttributeProcessMethod = patchClass.GetMethod("PrefixTransactionAttributeProcess"); var postfixTransactionAttributeProcessMethod = patchClass.GetMethod("PostfixTransactionAttributeProcess"); var patcherTransactionAttributeProcess = new PatchProcessor(instance, new List <MethodBase> { transactionAttributeProcessMethod }, new HarmonyMethod(prefixTransactionAttributeProcessMethod), new HarmonyMethod(postfixTransactionAttributeProcessMethod)); patcherTransactionAttributeProcess.Patch(); } }
// Copied from Harmony.PatchProcessor public static MethodBase GetMethod(Type type, string methodName, MethodType methodType, Type[] args) { if (type == null) { return(null); } switch (methodType) { case MethodType.Normal: if (methodName == null) { return(null); } return(AccessTools.DeclaredMethod(type, methodName, args)); case MethodType.Getter: if (methodName == null) { return(null); } return(AccessTools.DeclaredProperty(type, methodName).GetGetMethod(true)); case MethodType.Setter: if (methodName == null) { return(null); } return(AccessTools.DeclaredProperty(type, methodName).GetSetMethod(true)); case MethodType.Constructor: return(AccessTools.DeclaredConstructor(type, args)); case MethodType.StaticConstructor: return(AccessTools.GetDeclaredConstructors(type) .Where(c => c.IsStatic) .FirstOrDefault()); } return(null); }
public CorruptionCore(ModContentPack mod) { // ITab_Pawn_Soul - checkboxes to allow praying and show prayers var type = AccessTools.TypeByName("Corruption.Core.Soul.ITab_Pawn_Soul"); pawnSoulITabSoulToShowGetter = MethodInvoker.GetHandler(AccessTools.PropertyGetter(type, "SoulToShow")); MP.RegisterSyncMethod(typeof(CorruptionCore), nameof(SyncFavourValue)); MpCompat.harmony.Patch(AccessTools.Method(type, "FillTab"), prefix: new HarmonyMethod(typeof(CorruptionCore), nameof(PreFillTab)), postfix: new HarmonyMethod(typeof(CorruptionCore), nameof(PostFillTab))); type = AccessTools.TypeByName("Corruption.Core.Soul.CompSoul"); compSoulFavourTrackerField = AccessTools.FieldRefAccess <object>(type, "FavourTracker"); compSoulPrayerTrackerField = AccessTools.FieldRefAccess <object>(type, "PrayerTracker"); type = AccessTools.TypeByName("Corruption.Core.Dialog_SetPawnPantheon"); setPawnPantheonDialogConstructor = AccessTools.DeclaredConstructor(type); setPawnPantheonDialogSoulField = AccessTools.FieldRefAccess <ThingComp>(type, "soul"); MP.RegisterSyncMethod(type, "SelectionChanged"); MP.RegisterSyncWorker <object>(SyncDialogSetPawnPantheon, type); type = AccessTools.TypeByName("Corruption.Core.Soul.Soul_FavourTracker"); soulFavourTrackerFavoursField = AccessTools.FieldRefAccess <IList>(type, "Favours"); type = AccessTools.TypeByName("Corruption.Core.Gods.Pawn_PrayerTracker"); prayerTrackerCompSoulField = AccessTools.FieldRefAccess <ThingComp>(type, "compSoul"); prayerTrackerAllowPrayingSync = MP.RegisterSyncField(type, "AllowPraying"); prayerTrackerShowPrayerSync = MP.RegisterSyncField(type, "ShowPrayer"); MP.RegisterSyncWorker <object>(SyncPawnPrayerTracker, type); MpCompat.harmony.Patch(AccessTools.Method(type, "AdvancePrayer"), prefix: new HarmonyMethod(typeof(CorruptionCore), nameof(PreAdvancePrayer)), postfix: new HarmonyMethod(typeof(CorruptionCore), nameof(PostAdvancePrayer))); type = AccessTools.TypeByName("Corruption.Core.Soul.FavourProgress"); favourProgressFavourValueField = AccessTools.FieldRefAccess <float>(type, "favourValue"); }
internal static void InitializePatch(IPlatoHelper helper) { Plato = helper; if (_patched) { return; } _patched = true; var questionRaised = AccessTools.DeclaredConstructor(typeof(DialogueBox), new Type[] { typeof(string), typeof(List <Response>), typeof(int) }); List <Type> questionLocationTypes = new List <Type>() { typeof(GameLocation), typeof(BusStop), typeof(Desert), typeof(JojaMart) }; var channelSelected = AccessTools.DeclaredMethod(typeof(TV), "selectChannel"); var tvAction = AccessTools.DeclaredMethod(typeof(TV), "checkForAction"); List <MethodInfo> questionAsked = new List <MethodInfo>(questionLocationTypes.Select(t => AccessTools.Method(t, "answerDialogue"))); var performTouchAction = new[] { AccessTools.DeclaredMethod(typeof(GameLocation), "performTouchAction"), AccessTools.DeclaredMethod(typeof(MovieTheater), "performTouchAction"), AccessTools.DeclaredMethod(typeof(Desert), "performTouchAction") }; var performAction = new[] { AccessTools.DeclaredMethod(typeof(GameLocation), "performAction"), AccessTools.DeclaredMethod(typeof(MovieTheater), "performAction"), AccessTools.DeclaredMethod(typeof(CommunityCenter), "performAction"), AccessTools.DeclaredMethod(typeof(FarmHouse), "performAction"), AccessTools.DeclaredMethod(typeof(ManorHouse), "performAction"), AccessTools.DeclaredMethod(typeof(LibraryMuseum), "performAction"), AccessTools.DeclaredMethod(typeof(Town), "performAction"), }; var harmony = new Harmony($"Plato.QuestionPatches"); harmony.Patch(questionRaised, prefix: new HarmonyMethod(AccessTools.Method(typeof(EventPatches), nameof(DialogueBox)))); foreach (var method in questionAsked) { harmony.Patch(method, prefix: new HarmonyMethod( AccessTools.DeclaredMethod(typeof(EventPatches), nameof(QuestionAsked), null, new Type[] { method.DeclaringType }))); } harmony.Patch(channelSelected, prefix: new HarmonyMethod(AccessTools.Method(typeof(EventPatches), nameof(SelectChannel)))); harmony.Patch(tvAction, prefix: new HarmonyMethod(AccessTools.Method(typeof(EventPatches), nameof(SetIsTv)))); harmony.Patch(tvAction, postfix: new HarmonyMethod(AccessTools.Method(typeof(EventPatches), nameof(UnsetIsTV)))); harmony.Patch(AccessTools.Method(typeof(Event), nameof(Event.tryEventCommand)), new HarmonyMethod(typeof(EventPatches), nameof(TryEventCommandPre))); harmony.Patch(AccessTools.Method(typeof(Event), nameof(Event.tryEventCommand)), null, new HarmonyMethod(typeof(EventPatches), nameof(TryEventCommandPost))); foreach (var ta in performTouchAction) { harmony.Patch(ta, prefix: new HarmonyMethod(AccessTools.Method(typeof(EventPatches), nameof(PerformTouchAction)))); } foreach (var a in performAction) { harmony.Patch(a, prefix: new HarmonyMethod(AccessTools.Method(typeof(EventPatches), nameof(PerformAction)))); } var checkEventPreconditions = AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"); harmony.Patch(checkEventPreconditions, prefix: new HarmonyMethod(typeof(EventPatches), nameof(CheckEventConditions))); }
/********* ** Public methods *********/ public static ConstructorInfo DeclaredConstructor(Type type, Type[] parameters = null) { return(AccessTools.DeclaredConstructor(type, parameters, searchForStatic: true)); }
private static ConstructorInfo Il2CppConstuctor(Type type) => AccessTools.DeclaredConstructor(type, new Type[] { typeof(IntPtr) });
// I was allowed to use PokéWorld as class name. // However, it caused issues with auto completion. public PokeWorld(ModContentPack mod) { var type = AccessTools.TypeByName("PokeWorld.CompPokemon"); pokemonFormTrackerField = AccessTools.FieldRefAccess <object>(type, "formTracker"); pokemonLevelTrackerField = AccessTools.FieldRefAccess <object>(type, "levelTracker"); pokemonMoveTrackerField = AccessTools.FieldRefAccess <object>(type, "moveTracker"); type = AccessTools.TypeByName("PokeWorld.CompProperties_Pokemon"); propsFormsListField = AccessTools.FieldRefAccess <IList>(type, "forms"); // Gizmos { type = AccessTools.TypeByName("PokeWorld.PutInBallUtility"); MP.RegisterSyncMethod(type, "UpdatePutInBallDesignation"); // Only called from CompPokemon gizmo type = AccessTools.TypeByName("PokeWorld.PutInPortableComputerUtility"); MP.RegisterSyncMethod(type, "UpdatePutInPortableComputerDesignation"); // Only called from CryptosleepBall gizmo type = AccessTools.TypeByName("PokeWorld.FormTracker"); formTrackerCompField = AccessTools.FieldRefAccess <ThingComp>(type, "comp"); type = AccessTools.Inner(type, "<>c__DisplayClass17_0"); innerClassFormField = AccessTools.FieldRefAccess <object>(type, "form"); innerClassParentField = AccessTools.FieldRefAccess <object>(type, "<>4__this"); MP.RegisterSyncMethod(type, "<ProcessInput>b__0"); MP.RegisterSyncWorker <object>(SyncFormTrackerInnerClass, type, shouldConstruct: true); type = AccessTools.TypeByName("PokeWorld.LevelTracker"); MpCompat.RegisterLambdaMethod(type, "GetGizmos", 1, 2); levelTrackerCompField = AccessTools.FieldRefAccess <ThingComp>(type, "comp"); MP.RegisterSyncWorker <object>(SyncLevelTracker, type); // There's a bunch of gizmos in PokemonAttackGizmoUtility, but they don't seem like they need syncing. // In my testing they seemed fine. The way they're made I believe those should be handled by MP itself. } // ITab { type = AccessTools.TypeByName("PokeWorld.ITab_ContentsPokeball"); MP.RegisterSyncMethod(type, "OnDropThing").SetContext(SyncContext.MapSelected); MP.RegisterSyncWorker <object>(NoSync, type, shouldConstruct: true); type = AccessTools.TypeByName("PokeWorld.ITab_ContentsStorageSystem"); MP.RegisterSyncMethod(type, "InterfaceDrop").SetContext(SyncContext.MapSelected); var method = AccessTools.Method(type, "InterfaceDrop"); storageTabConstructor = AccessTools.DeclaredConstructor(type); interfaceDropMethod = MethodInvoker.GetHandler(method); MpCompat.harmony.Patch(method, prefix: new HarmonyMethod(typeof(PokeWorld), nameof(PreInterfaceDrop))); MP.RegisterSyncMethod(typeof(PokeWorld), nameof(SyncedInterfaceDrop)).SetContext(SyncContext.MapSelected); storageSystemType = AccessTools.TypeByName("PokeWorld.StorageSystem"); type = AccessTools.TypeByName("PokeWorld.MoveTracker"); MP.RegisterSyncMethod(type, "SetWanted"); // Only called from ITab_Pawn_Moves/MoveCardUtility checkbox moveTrackerCompField = AccessTools.FieldRefAccess <ThingComp>(type, "comp"); MP.RegisterSyncWorker <object>(SyncMoveTracker, type); } // RNG { type = AccessTools.TypeByName("PokeWorld.ShinyTracker"); shinyTrackerCompField = AccessTools.FieldRefAccess <ThingComp>(type, "comp"); MpCompat.harmony.Patch(AccessTools.Method(type, "TryMakeShinyMote"), prefix: new HarmonyMethod(typeof(PokeWorld), nameof(PreTryMakeShinyMote)), postfix: new HarmonyMethod(typeof(PokeWorld), nameof(PostTryMakeShinyMote))); } }