static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { var codes = new List <CodeInstruction>(instructions); ConstructorInfo rivermaker = AccessTools.Constructor(typeof(RiverMaker), new Type[] { typeof(Vector3), typeof(float), typeof(RiverDef) }); int riverIndex = -1; int replaceIndex = -1; for (int i = 0; i < codes.Count; i++) { if (codes[i].opcode == OpCodes.Newobj) { if (codes[i].OperandIs(rivermaker)) { riverIndex = i; break; } } if (codes[i].opcode == OpCodes.Ldloc_1) { replaceIndex = i; } } codes.Insert(replaceIndex + 1, new CodeInstruction(opcode: OpCodes.Call, operand: AccessTools.Method(type: typeof(HelperMethods), name: nameof(HelperMethods.GetRiverDirection)))); return(codes.AsEnumerable()); }
private static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { var newInstructions = ListPool <CodeInstruction> .Shared.Rent(instructions); var index = newInstructions.FindLastIndex(op => op.opcode == OpCodes.Blt); newInstructions.InsertRange(++index, new[] { // Player.Get(ConsumableAndWearableItems._hub) new CodeInstruction(OpCodes.Ldloc_2), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ConsumableAndWearableItems), nameof(ConsumableAndWearableItems._hub))), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), // ConsumableAndWearableItems.usableItems[mid].inventoryID new CodeInstruction(OpCodes.Ldloc_2), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ConsumableAndWearableItems), nameof(ConsumableAndWearableItems.usableItems))), new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(type, "mid")), new CodeInstruction(OpCodes.Ldelem, typeof(ConsumableAndWearableItems.UsableItem)), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ConsumableAndWearableItems.UsableItem), nameof(ConsumableAndWearableItems.UsableItem.inventoryID))), // Player.OnMedicalItemDequipped(new UsedMedicalItemEventArgs(arg1, arg2)) new CodeInstruction(OpCodes.Newobj, AccessTools.Constructor(typeof(UsedMedicalItemEventArgs), new[] { typeof(Player), typeof(ItemType) })), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Handlers.Player), nameof(Handlers.Player.OnMedicalItemUsed))), }); for (int z = 0; z < newInstructions.Count; z++) { yield return(newInstructions[z]); } ListPool <CodeInstruction> .Shared.Return(newInstructions); }
/********* ** Private methods *********/ /// <summary>Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialised at this point, so this is a good time to set up mod integrations.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event data.</param> private void OnGameLaunched(object sender, GameLaunchedEventArgs e) { new DataLoader(Helper); var harmony = HarmonyInstance.Create("Digus.CustomCaskMod"); harmony.Patch( original: AccessTools.Method(typeof(Cask), nameof(Cask.performObjectDropInAction)), prefix: new HarmonyMethod(typeof(CaskOverrides), nameof(CaskOverrides.PerformObjectDropInAction)) ); if (!DataLoader.ModConfig.DisableAutomateCompatibility && Helper.ModRegistry.IsLoaded("Pathoschild.Automate")) { ModMonitor.Log("Automated detected, patching it to work with configured items and aging rates.", LogLevel.Info); try { Assembly automateAssembly = AppDomain.CurrentDomain.GetAssemblies().First(a => a.FullName.StartsWith("Automate,")); harmony.Patch( original: AccessTools.Constructor(automateAssembly.GetType("Pathoschild.Stardew.Automate.Framework.Machines.Objects.CaskMachine"), new Type[] { typeof(Cask), typeof(GameLocation), typeof(Vector2) }), postfix: new HarmonyMethod(typeof(CaskOverrides), nameof(CaskOverrides.CaskMachine)) ); } catch (Exception ex) { ModMonitor.Log("Error trying to patch Automate. Configured items and aging rates will not work with Automate.", LogLevel.Warn); ModMonitor.Log(ex.Message, LogLevel.Trace); ModMonitor.Log(ex.StackTrace, LogLevel.Trace); } } }
public static IEnumerable <CodeInstruction> TranspilerPatchFor_OpenMenu(IEnumerable <CodeInstruction> instructions) { var orgCtor = AccessTools.Constructor(typeof(ItemGrabMenu), new Type[] { typeof(IList <StardewValley.Item>), typeof(Boolean), typeof(Boolean), typeof(InventoryMenu.highlightThisItem), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(String), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Int32), typeof(StardewValley.Item), typeof(Int32), typeof(Object) }); var newCtor = AccessTools.Constructor(typeof(Types.CustomTypes.ChestExMenu.MainMenu), new Type[] { typeof(IList <StardewValley.Item>), typeof(Boolean), typeof(Boolean), typeof(InventoryMenu.highlightThisItem), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(String), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Int32), typeof(StardewValley.Item), typeof(Int32), typeof(Object) }); Boolean patched = false; foreach (var instruction in instructions) { if (instruction.opcode == OpCodes.Newobj) { // ItemGrabMenu.ctor[2] if ((ConstructorInfo)instruction.operand == orgCtor) { yield return(new CodeInstruction(OpCodes.Newobj, newCtor)); patched = true; continue; } } yield return(instruction); } if (patched) { GlobalVars.SMAPIMonitor.Log("Successfully patched 'ChestsAnywhere.ChestContainer.OpenMenu'.", LogLevel.Info); } else { GlobalVars.SMAPIMonitor.Log("Could not patch 'ChestsAnywhere.ChestContainer.OpenMenu' to redirect 'ItemGrabMenu.ctor' to 'ChestExMenu.MainMenu.ctor'!", LogLevel.Error); } }
public override void Entry(IModHelper helper) { Instance = this; Config = helper.ReadConfig <ModConfig>(); helper.Events.GameLoop.GameLaunched += OnGameLaunched; var harmony = new Harmony(ModManifest.UniqueID); try { harmony.Patch( original: AccessTools.Constructor(typeof(HoeDirt)), postfix: new HarmonyMethod(typeof(PredictableRetainingSoil), nameof(HoeDirt_ctor_Postfix)) ); harmony.Patch( original: AccessTools.Method(typeof(HoeDirt), nameof(HoeDirt.dayUpdate)), prefix: new HarmonyMethod(typeof(PredictableRetainingSoil), nameof(HoeDirt_dayUpdate_Prefix)), postfix: new HarmonyMethod(typeof(PredictableRetainingSoil), nameof(HoeDirt_dayUpdate_Postfix)) ); harmony.Patch( original: AccessTools.Method(typeof(HoeDirt), nameof(HoeDirt.plant)), postfix: new HarmonyMethod(typeof(PredictableRetainingSoil), nameof(HoeDirt_plant_Postfix)) ); harmony.Patch( original: AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)), postfix: new HarmonyMethod(typeof(PredictableRetainingSoil), nameof(Object_getDescription_postfix)) ); } catch (Exception e) { Monitor.Log($"Could not patch methods - Predictable Retaining Soil probably won't work.\nReason: {e}", LogLevel.Error); } }
/********* ** Private methods *********/ /// <summary>Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialised at this point, so this is a good time to set up mod integrations.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event data.</param> private void OnGameLaunched(object sender, GameLaunchedEventArgs e) { DataLoader = new DataLoader(Helper); var harmony = HarmonyInstance.Create("Digus.InfiniteBaitAndLureMod"); harmony.Patch( original: AccessTools.Method(typeof(FishingRod), "doDoneFishing"), prefix: new HarmonyMethod(typeof(GameOverrides), nameof(GameOverrides.DoDoneFishing)) ); harmony.Patch( original: AccessTools.Method(typeof(CraftingRecipe), nameof(CraftingRecipe.createItem)), prefix: new HarmonyMethod(typeof(GameOverrides), nameof(GameOverrides.CreateItem)) ); harmony.Patch( original: AccessTools.Method(typeof(CraftingPage), "clickCraftingRecipe"), prefix: new HarmonyMethod(typeof(GameOverrides), nameof(GameOverrides.ClickCraftingRecipe)) ); harmony.Patch( original: AccessTools.Method(typeof(NPC), nameof(NPC.tryToReceiveActiveObject)), prefix: new HarmonyMethod(typeof(GameOverrides), nameof(GameOverrides.TryToReceiveActiveObject)) ); if (!DataLoader.ModConfig.DisableIridiumQualityFish) { harmony.Patch( original: AccessTools.Constructor(typeof(BobberBar), new[] { typeof(int), typeof(float), typeof(bool), typeof(int) }), postfix: new HarmonyMethod(typeof(GameOverrides), nameof(GameOverrides.BobberBar)) ); } }
public static void ApplyAll(HarmonyInstance harmony) { // Force skip ItemGrabMenu ctor when called from ChestExMenu harmony.Patch( AccessTools.Constructor(typeof(ItemGrabMenu), new Type[] { typeof(IList <StardewValley.Item>), typeof(Object) }), null, null, new HarmonyMethod(typeof(PatchesFor_ItemGrabMenu).GetMethod("TranspilerPatchFor_ctor"))); }
public static void Postfix(List <KIconToggleMenu.ToggleInfo> ___overlayToggleInfos) { var constructor = AccessTools.Constructor( AccessTools.Inner(typeof(OverlayMenu), "OverlayToggleInfo"), new[] { typeof(string), typeof(string), typeof(HashedString), typeof(string), typeof(Action), typeof(string), typeof(string), } ); var obj = constructor.Invoke( new object[] { "Info Overlay", "overlay_info", InfoOverlay.ID, "", Action.NumActions, "Displays various information about tiles", "Info Overlay", } ); ___overlayToggleInfos.Add((KIconToggleMenu.ToggleInfo)obj); }
/// <inheritdoc/> public override void Apply(HarmonyInstance harmony) { harmony.Patch( original: AccessTools.Constructor(typeof(TemporaryAnimatedSprite), new[] { typeof(int), typeof(float), typeof(int), typeof(int), typeof(Vector2), typeof(bool), typeof(bool), typeof(GameLocation), typeof(Farmer) }), postfix: new HarmonyMethod(GetType(), nameof(TemporaryAnimatedSpriteCtorPostfix)) ); }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { var from = AccessTools.Constructor(typeof(IntVec3), new Type[] { typeof(int), typeof(int), typeof(int) }); var to = AccessTools.Method(typeof(Patch_Game_InitNewGame), nameof(CreateMyCustomVector)); // I could not, for the life of me, figure out how to target the correct Ldloca_S with the operand. // The "correct" way would be to find the one with operand == 1, but that doesn't work. // If you know of the way, feel free to PR/tell me about it! var encounteredFirstLdloca_S = false; var replacedInstructions = instructions.MethodReplacer(from, to); foreach (var instruction in replacedInstructions) { // First Ldloca_S is our vector allocation. // We have replaced the constructor call with a static metho, so we should get rid of this. // We will set it after our static call. if (instruction.opcode == OpCodes.Ldloca_S && !encounteredFirstLdloca_S) { encounteredFirstLdloca_S = true; continue; } yield return(instruction); // If this instruction is our static call, we should set the result to the correct local variable. if (instruction.opcode == OpCodes.Call && (MethodInfo)instruction.operand == to) { yield return(new CodeInstruction(OpCodes.Stloc_1)); } } }
/// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides simplified APIs for writing mods.</param> public override void Entry(IModHelper helper) { instance = this; Log.Monitor = Monitor; helper.Events.Player.Warped += onWarped; helper.Events.Display.RenderedActiveMenu += onRenderedActiveMenu; helper.Events.GameLoop.DayStarted += onDayStarted; helper.Events.GameLoop.DayEnding += onDayEnding; helper.Events.GameLoop.GameLaunched += onGameLaunched; SpaceEvents.ChooseNightlyFarmEvent += changeFarmEvent; try { var harmony = HarmonyInstance.Create(ModManifest.UniqueID); Log.trace("Doing harmony patches..."); harmony.Patch(AccessTools.Method(typeof(Farmer), nameof(Farmer.getProfessionForSkill)), postfix: new HarmonyMethod(AccessTools.Method(typeof(FarmerGetProfessionHook), nameof(LevelUpMenuProfessionNameHook.Postfix)))); harmony.Patch(AccessTools.Method(typeof(Farmer), nameof(Farmer.gainExperience)), prefix: new HarmonyMethod(AccessTools.Method(typeof(OverpoweredGeodeFix), nameof(OverpoweredGeodeFix.Prefix)))); harmony.Patch(AccessTools.Method(typeof(Farmer), nameof(Farmer.gainExperience)), transpiler: new HarmonyMethod(AccessTools.Method(typeof(ExperienceGainFix), nameof(ExperienceGainFix.Transpiler)))); harmony.Patch(AccessTools.Constructor(typeof(LevelUpMenu), new Type[] { typeof(int), typeof(int) }), transpiler: new HarmonyMethod(AccessTools.Method(typeof(LevelUpMenuLuckProfessionConstructorFix), nameof(LevelUpMenuLuckProfessionConstructorFix.Transpiler)))); harmony.Patch(AccessTools.Method(typeof(LevelUpMenu), "getProfessionName"), postfix: new HarmonyMethod(AccessTools.Method(typeof(LevelUpMenuProfessionNameHook), nameof(LevelUpMenuProfessionNameHook.Postfix)))); harmony.Patch(AccessTools.Method(typeof(LevelUpMenu), nameof(LevelUpMenu.AddMissedProfessionChoices)), transpiler: new HarmonyMethod(AccessTools.Method(typeof(LevelUpMenuMissedStuffPatch), nameof(LevelUpMenuMissedStuffPatch.Transpiler)))); harmony.Patch(AccessTools.Method(typeof(LevelUpMenu), nameof(LevelUpMenu.AddMissedLevelRecipes)), transpiler: new HarmonyMethod(AccessTools.Method(typeof(LevelUpMenuMissedStuffPatch), nameof(LevelUpMenuMissedStuffPatch.Transpiler)))); } catch (Exception e) { Log.trace("Exception doing harmony: " + e); } checkForAllProfessions(); }
//thx Brrainz private static IEnumerable <CodeInstruction> DebugWindowsOpener_ToggleDebugActionsMenu_Patch(IEnumerable <CodeInstruction> instructions) { ConstructorInfo from = AccessTools.Constructor(typeof(Dialog_DebugActionsMenu)); ConstructorInfo to = AccessTools.Constructor(typeof(Dialog_MFIDebugActionMenu)); return(instructions.MethodReplacer(from: from, to: to)); }
public static void PatchLogMessage(Harmony harmony) { harmony.Patch(AccessTools.Constructor(typeof(LogMessage), new Type[] { typeof(string) }), prefix: new HarmonyMethod(typeof(MiscFixes), nameof(MiscFixes.LogMessage_ctor_string_prefix))); harmony.Patch(AccessTools.Constructor(typeof(LogMessage), new Type[] { typeof(LogMessageType), typeof(string), typeof(string) }), prefix: new HarmonyMethod(typeof(MiscFixes), nameof(MiscFixes.LogMessage_ctor_LogMessageType_string_string_prefix))); }
internal static void SaveLoaded(string uniqueID, ModEntry entry, ModConfig config, IEnumerable <SpawnableItem> items) { Config = config; modEntry = entry; var harmony = new Harmony(uniqueID); harmony.Patch( original: AccessTools.Constructor(typeof(InventoryMenu), new System.Type[] { typeof(int), typeof(int), typeof(bool), typeof(IList <Item>), typeof(InventoryMenu.highlightThisItem), typeof(int), typeof(int), typeof(int), typeof(int), typeof(bool) }), postfix: new HarmonyMethod(typeof(AedenthornInventory), nameof(AedenthornInventory.InventoryMenu_Ctor_Postfix)) ); harmony.Patch( original: AccessTools.Method(typeof(InventoryMenu), nameof(InventoryMenu.draw), new System.Type[] { typeof(SpriteBatch), typeof(int), typeof(int), typeof(int) }), prefix: new HarmonyMethod(typeof(AedenthornInventory), nameof(AedenthornInventory.InventoryMenu_draw_Prefix)), postfix: new HarmonyMethod(typeof(AedenthornInventory), nameof(AedenthornInventory.InventoryMenu_draw_Postfix)) ); harmony.Patch( original: AccessTools.Method(typeof(InventoryMenu), nameof(InventoryMenu.performHoverAction)), prefix: new HarmonyMethod(typeof(AedenthornInventory), nameof(AedenthornInventory.InventoryMenu_performHoverAction_Prefix)) ); AllItems = items.ToArray(); entry.Helper.Events.Input.MouseWheelScrolled += Input_MouseWheelScrolled; entry.Helper.Events.Input.ButtonPressed += Input_ButtonPressed; }
/// <summary>Apply the Harmony patch.</summary> /// <param name="harmony">The Harmony instance.</param> public void Apply(HarmonyInstance harmony) { ConstructorInfo constructor = AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }); MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(DialogueErrorPatch.Prefix)); harmony.Patch(constructor, new HarmonyMethod(prefix), null); }
public override void Entry(IModHelper helper) { DialoguePatches.Initialize(Monitor, helper); var harmony = HarmonyInstance.Create(ModManifest.UniqueID); HarmonyMethod hm = new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.Dialogue_Prefix)); hm.prioritiy = Priority.First; harmony.Patch( original: AccessTools.Constructor(typeof(Dialogue), new Type[] { typeof(string), typeof(NPC) }), prefix: hm ); harmony.Patch( original: AccessTools.Method(typeof(LocalizedContentManager), nameof(LocalizedContentManager.LoadString), new Type[] { typeof(string) }), postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.LocalizedContentManager_LoadString_Postfix)) ); harmony.Patch( original: AccessTools.Method(typeof(NPC), nameof(NPC.showTextAboveHead)), prefix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.NPC_showTextAboveHead_Prefix)) ); harmony.Patch( original: AccessTools.Method(typeof(NPC), nameof(NPC.getHi)), postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.NPC_getHi_Postfix)) ); }
private static AbstractActor InitAbstractActor(AbstractActor actor) { // Init the combat ref for constants ConstructorInfo constantsCI = AccessTools.Constructor(typeof(CombatGameConstants), new Type[] { }); CombatGameConstants constants = (CombatGameConstants)constantsCI.Invoke(new object[] { }); CombatGameState cgs = new CombatGameState(); Traverse constantsT = Traverse.Create(cgs).Property("Constants"); constantsT.SetValue(constants); Traverse combatT = Traverse.Create(actor).Property("Combat"); combatT.SetValue(cgs); // Init any required stats actor.StatCollection = new StatCollection(); // ModStats //actor.StatCollection.AddStatistic<int>(ModStats.PunchAttackMod, 0); // Vanilla actor.StatCollection.AddStatistic <float>("SensorSignatureModifier", 1.0f); return(actor); }
public static void ApplyPatch(Harmony harmony) { harmony.Patch( original: AccessTools.Constructor(typeof(FarmAnimal), new Type[] { typeof(string), typeof(long), typeof(long) }), prefix: new HarmonyMethod(typeof(FarmAnimalPatch), nameof(ctor_Prefix)), postfix: new HarmonyMethod(typeof(FarmAnimalPatch), nameof(ctor_Postfix))); }
/**** ** Methods ****/ /// <summary>Apply the harmony patches for patching game code.</summary> private void ApplyHarmonyPatches() { // create a new harmony instance for patching source code HarmonyInstance harmony = HarmonyInstance.Create(this.ModManifest.UniqueID); // apply the patches harmony.Patch( original: AccessTools.Constructor(typeof(StardewValley.Menus.InventoryPage), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) }), postfix: new HarmonyMethod(AccessTools.Method(typeof(InventoryPagePatch), nameof(InventoryPagePatch.ConstructorPostFix))) ); harmony.Patch( original: AccessTools.Method(typeof(StardewValley.Menus.InventoryPage), nameof(InventoryPage.receiveLeftClick)), postfix: new HarmonyMethod(AccessTools.Method(typeof(InventoryPagePatch), nameof(InventoryPagePatch.ReceiveLeftClickPostFix))) ); harmony.Patch( original: AccessTools.Method(typeof(StardewValley.Menus.InventoryPage), nameof(InventoryPage.draw), new Type[] { typeof(SpriteBatch) }), postfix: new HarmonyMethod(AccessTools.Method(typeof(InventoryPagePatch), nameof(InventoryPagePatch.DrawPostFix))) ); harmony.Patch( original: AccessTools.Method(typeof(StardewValley.FarmerRenderer), nameof(FarmerRenderer.draw), new Type[] { typeof(SpriteBatch), typeof(FarmerSprite.AnimationFrame), typeof(int), typeof(Rectangle), typeof(Vector2), typeof(Vector2), typeof(float), typeof(int), typeof(Color), typeof(float), typeof(float), typeof(Farmer) }), postfix: new HarmonyMethod(AccessTools.Method(typeof(FarmerRendererPatch), nameof(FarmerRendererPatch.DrawPostFix))) ); }
/// <summary> /// Applies the Harmony Patch to the game code /// </summary> /// <param name="harmony">The instance (targetted application) harmony will patch up.</param> public void Apply(HarmonyInstance harmony) { ConstructorInfo Constructor = null; MethodInfo Original = null; MethodInfo Prefix = (prefix) ? helper.Reflection.GetMethod(type, "Prefix").MethodInfo : null; MethodInfo Transpile = (transpiler) ? helper.Reflection.GetMethod(type, "Transpiler").MethodInfo : null; MethodInfo Postfix = (postfix) ? helper.Reflection.GetMethod(type, "Postfix").MethodInfo : null; if (patchType == PatchType.Constructor) { Constructor = AccessTools.Constructor(getTypeSDV(sdvType), parameters); harmony.Patch(Constructor, (prefix) ? new HarmonyMethod(Prefix) : null, (postfix) ? new HarmonyMethod(Postfix) : null, (transpiler) ? new HarmonyMethod(Transpile) : null); } else { Original = AccessTools.Method(getTypeSDV(sdvType), original, parameters); harmony.Patch(Original, (prefix) ? new HarmonyMethod(Prefix) : null, (postfix) ? new HarmonyMethod(Postfix) : null, (transpiler) ? new HarmonyMethod(Transpile) : null); } return; }
public static void ApplyAll(HarmonyInstance harmony) { if (GlobalVars.SMAPIHelper.ModRegistry.Get(CONST_UID) is IModInfo automateModInfo) { GlobalVars.SMAPIMonitor.Log("Automate is found, installing dynamic compatibility patches...", LogLevel.Info); GlobalVars.SMAPIMonitor.Log($"The target version of Automate for the compatibility patch is '{CONST_VERSION}'.", LogLevel.Debug); if (String.Equals(automateModInfo.Manifest.Version.ToString(), CONST_VERSION, StringComparison.OrdinalIgnoreCase)) { // user is running the same version of Automate GlobalVars.SMAPIMonitor.Log("ChestEx is fully compatible with this Automate version.", LogLevel.Info); } else if (automateModInfo.Manifest.Version.IsNewerThan(CONST_VERSION)) { // user is running a newer version of Automate GlobalVars.SMAPIMonitor.Log("You seem to be running a newer version of Automate! This warning can safely be ignored if you don't experience any issues. However, if you do experience any issues, please report it to me on Discord or on Nexus.", LogLevel.Warn); } else if (automateModInfo.Manifest.Version.IsOlderThan(CONST_VERSION)) { // user is running an older version of Automate GlobalVars.SMAPIMonitor.Log("You seem to be running an older version of Automate! There is a high chance that you will experience issues, please update your copy of Automate.", LogLevel.Warn); } harmony.Patch( AccessTools.Constructor( Type.GetType("Pathoschild.Stardew.Automate.Framework.Storage.ChestContainer, Automate"), new Type[] { typeof(Chest), typeof(StardewValley.GameLocation), typeof(Microsoft.Xna.Framework.Vector2), typeof(IReflectionHelper) }), null, null, new HarmonyMethod(typeof(PatchesFor_ChestContainer).GetMethod("TranspilerPatchFor_ctor"))); } }
public static void Postfix(List <KIconToggleMenu.ToggleInfo> ___overlayToggleInfos) { var constructor = AccessTools.Constructor( AccessTools.Inner(typeof(OverlayMenu), "OverlayToggleInfo"), new[] { typeof(string), // text typeof(string), // icon_name typeof(HashedString), // sim_view typeof(string), // required_tech_item typeof(Action), // hotKey typeof(string), // tooltip typeof(string) // tooltip_header } ); var obj = constructor.Invoke( new object[] { MapOverlay.Name, MapOverlay.Icon, MapOverlay.ID, "", Action.NumActions, // TODO: Should be MapOverlay.Hotkey, but Overlay15 already is used by Traffic Visualiser and possibly will be taken by Radiation Overlay, too MapOverlay.Desc, MapOverlay.Name } ); ___overlayToggleInfos.Add((KIconToggleMenu.ToggleInfo)obj); }
public static IEnumerable <CodeInstruction> TranspilerPatches_RedirectingToChestExMenu(IEnumerable <CodeInstruction> instructions) { var orgCtor = AccessTools.Constructor(typeof(ItemGrabMenu), new Type[] { typeof(IList <StardewValley.Item>), typeof(Boolean), typeof(Boolean), typeof(InventoryMenu.highlightThisItem), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(String), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Int32), typeof(StardewValley.Item), typeof(Int32), typeof(Object) }); var newCtor = AccessTools.Constructor(typeof(Types.CustomTypes.ChestExMenu.MainMenu), new Type[] { typeof(IList <StardewValley.Item>), typeof(Boolean), typeof(Boolean), typeof(InventoryMenu.highlightThisItem), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(String), typeof(ItemGrabMenu.behaviorOnItemSelect), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Boolean), typeof(Int32), typeof(StardewValley.Item), typeof(Int32), typeof(Object) }); foreach (var instruction in instructions) { if (instruction.opcode == OpCodes.Newobj) { // ItemGrabMenu.ctor[2] if ((ConstructorInfo)instruction.operand == orgCtor) { yield return(new CodeInstruction(OpCodes.Newobj, newCtor)); continue; } } // IsInst ItemGrabMenu else if (instruction.opcode == OpCodes.Isinst && (Type)instruction.operand == typeof(ItemGrabMenu)) { yield return(new CodeInstruction(OpCodes.Isinst, typeof(Types.BaseTypes.ICustomItemGrabMenu))); continue; } yield return(instruction); } }
static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { var from = AccessTools.Constructor(typeof(DamageFlasher), new Type[] { typeof(Pawn) }); var to = AccessTools.Constructor(typeof(ZombieDamageFlasher), new Type[] { typeof(Pawn) }); return(Transpilers.MethodReplacer(instructions, from, to)); }
/// <summary>Patches out <see cref="System.Random"/> calls using <see cref="FixRNG(IEnumerable{CodeInstruction})"/>, and optionally surrounds the method with <see cref="Rand.PushState"/> and <see cref="Rand.PopState"/>.</summary> /// <param name="type">Type with a constructors that needs patching</param> /// <param name="patchPushPop">Determines if the methods should be surrounded with push/pop calls</param> public static void PatchSystemRandCtor(string[] types, bool patchPushPop = true) { foreach (var method in types) { PatchSystemRand(AccessTools.Constructor(AccessTools.TypeByName(method)), patchPushPop); } }
internal void Apply(Harmony harmony) { harmony.Patch(AccessTools.Method(_object, nameof(Object.draw), new[] { typeof(SpriteBatch), typeof(int), typeof(int), typeof(float) }), prefix: new HarmonyMethod(GetType(), nameof(DrawPrefix))); harmony.Patch(AccessTools.Method(_object, nameof(Object.drawPlacementBounds), new[] { typeof(SpriteBatch), typeof(GameLocation) }), prefix: new HarmonyMethod(GetType(), nameof(DrawPlacementBoundsPrefix))); harmony.Patch(AccessTools.Method(_object, nameof(Object.DayUpdate), new[] { typeof(GameLocation) }), postfix: new HarmonyMethod(GetType(), nameof(DayUpdatePostfix))); harmony.Patch(AccessTools.Method(_object, nameof(Object.rot), null), postfix: new HarmonyMethod(GetType(), nameof(RotPostfix))); harmony.Patch(AccessTools.Method(_object, nameof(Object.placementAction), new[] { typeof(GameLocation), typeof(int), typeof(int), typeof(Farmer) }), postfix: new HarmonyMethod(GetType(), nameof(PlacementActionPostfix))); harmony.Patch(AccessTools.Constructor(_object, new[] { typeof(Vector2), typeof(int), typeof(int) }), postfix: new HarmonyMethod(GetType(), nameof(ObjectPostfix))); if (PatchTemplate.IsDGAUsed()) { try { if (Type.GetType("DynamicGameAssets.Game.CustomObject, DynamicGameAssets") is Type dgaObjectType && dgaObjectType != null) { harmony.Patch(AccessTools.Method(dgaObjectType, nameof(Object.draw), new[] { typeof(SpriteBatch), typeof(int), typeof(int), typeof(float) }), prefix: new HarmonyMethod(GetType(), nameof(DrawPrefix))); harmony.Patch(AccessTools.Method(dgaObjectType, nameof(Object.placementAction), new[] { typeof(GameLocation), typeof(int), typeof(int), typeof(Farmer) }), postfix: new HarmonyMethod(GetType(), nameof(PlacementActionPostfix))); } if (Type.GetType("DynamicGameAssets.Game.CustomBigCraftable, DynamicGameAssets") is Type dgaCraftableType && dgaCraftableType != null) { harmony.Patch(AccessTools.Method(dgaCraftableType, nameof(Object.draw), new[] { typeof(SpriteBatch), typeof(int), typeof(int), typeof(float) }), prefix: new HarmonyMethod(GetType(), nameof(DrawPrefix))); } } catch (Exception ex) { _monitor.Log($"Failed to patch Dynamic Game Assets in {this.GetType().Name}: AT may not be able to override certain DGA object types!", LogLevel.Warn); _monitor.Log($"Patch for DGA failed in {this.GetType().Name}: {ex}", LogLevel.Trace); } } }
public static ConstructorInfo Constructor(Type type, Type[] parameters = null) { // Harmony 1.x matched both static and instance constructors return (AccessTools.Constructor(type, parameters, searchForStatic: false) ?? AccessTools.Constructor(type, parameters, searchForStatic: true)); }
static Patch_RimHUDBase() { try { ((Action)(() => { if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "RimHUD")) { Log.Message("DInterests: RimHUD running, attempting to patch"); var harmony = new Harmony("io.github.dametri.interests"); hudPawnModel = AccessTools.TypeByName("RimHUD.Data.Models.PawnModel"); hudSkillModel = AccessTools.TypeByName("RimHUD.Data.Models.SkillModel"); var hudTarget1 = AccessTools.Constructor(hudSkillModel, new[] { hudPawnModel, typeof(SkillDef) }); var hudInvoke1 = AccessTools.Method(typeof(RimHUDPatches.Patch_SkillModelConstructor_Postfix), "Postfix"); if (hudTarget1 != null && hudInvoke1 != null) { harmony.Patch(hudTarget1, postfix: new HarmonyMethod(hudInvoke1)); } var hudTarget2 = AccessTools.Method(hudSkillModel, "GetSkillPassionColor"); var hudInvoke2 = AccessTools.Method(typeof(RimHUDPatches.Patch_GetSkillPassionColor_Prefix), "Prefix"); if (hudTarget2 != null && hudInvoke2 != null) { harmony.Patch(hudTarget2, prefix: new HarmonyMethod(hudInvoke2)); } } }))(); } catch (TypeLoadException ex) { Log.Message(ex.ToString()); } }
public CashRegister(ModContentPack mod) { var type = AccessTools.TypeByName("CashRegister.Shifts.ITab_Register_Shifts"); MpCompat.RegisterLambdaMethod(type, "GetGizmos", 1).SetContext(SyncContext.MapSelected); MP.RegisterSyncWorker <object>(NoSync, type, shouldConstruct: true); MP.RegisterSyncMethod(typeof(CashRegister), nameof(SyncedSetShifts)).ExposeParameter(1).ExposeParameter(2).ExposeParameter(3).ExposeParameter(4).ExposeParameter(5).MinTime(100); MpCompat.harmony.Patch(AccessTools.Method(type, "FillTab"), prefix: new HarmonyMethod(typeof(CashRegister), nameof(PreFillTab)), postfix: new HarmonyMethod(typeof(CashRegister), nameof(PostFillTab))); type = AccessTools.TypeByName("CashRegister.Gizmo_Radius"); gizmoRadiusConstructor = AccessTools.GetDeclaredConstructors(type).First(x => x.GetParameters().Length == 1); gizmoSelectionField = AccessTools.FieldRefAccess <Building[]>(type, "selection"); MP.RegisterSyncMethod(AccessTools.DeclaredMethod(type, "ButtonDown")); MP.RegisterSyncMethod(AccessTools.DeclaredMethod(type, "ButtonUp")); MP.RegisterSyncMethod(AccessTools.DeclaredMethod(type, "ButtonCenter")); MP.RegisterSyncWorker <Gizmo>(SyncGizmoRadius, type); type = AccessTools.TypeByName("CashRegister.Building_CashRegister"); cashRegisterType = type.MakeArrayType(); shiftsListField = AccessTools.FieldRefAccess <IList>(type, "shifts"); type = AccessTools.TypeByName("CashRegister.Shifts.Shift"); shiftConstructor = AccessTools.Constructor(type); timetableField = AccessTools.FieldRefAccess <object>(type, "timetable"); assignedField = AccessTools.FieldRefAccess <List <Pawn> >(type, "assigned"); type = AccessTools.TypeByName("CashRegister.Timetable.TimetableBool"); timesField = AccessTools.FieldRefAccess <List <bool> >(type, "times"); }
/// <summary> /// Applies the Harmony Patch to the game code. /// </summary> /// <param name="h">The instance (targetted application) harmony will patch up.</param> public void Apply(HarmonyInstance h) { ConstructorInfo con; MethodInfo orig; MethodInfo prefix; MethodInfo postfix; MethodInfo transpiler; prefix = (hasPrefix) ? Memory.instance.Helper.Reflection.GetMethod(type, "Prefix").MethodInfo : null; postfix = (hasPostfix) ? Memory.instance.Helper.Reflection.GetMethod(type, "Postfix").MethodInfo : null; transpiler = (hasTranspiler) ? Memory.instance.Helper.Reflection.GetMethod(type, "Transpiler").MethodInfo : null; switch (infoType) { case 0: orig = AccessTools.Method(getTypeSDV(SDVType), original, constructorType); h.Patch(orig, (prefix != null) ? new HarmonyMethod(prefix) : null, (postfix != null) ? new HarmonyMethod(postfix) : null, (transpiler != null) ? new HarmonyMethod(transpiler) : null);; break; case 1: con = AccessTools.Constructor(getTypeSDV(SDVType), constructorType); h.Patch(con, (prefix != null) ? new HarmonyMethod(prefix) : null, (postfix != null) ? new HarmonyMethod(postfix) : null, (transpiler != null) ? new HarmonyMethod(transpiler) : null); break; } return; }