/// <summary>Applies this Harmony patch to the game through the provided instance.</summary> /// <param name="harmony">This mod's Harmony instance.</param> public static void ApplyPatch(Harmony harmony) { HashSet <Type> typesToPatch = new HashSet <Type>(); //dynamic set of types that implement (e.g. override) the target method foreach (Type type in AccessTools.AllTypes()) //for every type { if (typeof(Monster).IsAssignableFrom(type)) //if this is a subclass of monster { if (AccessTools.Method(type, nameof(Monster.getExtraDropItems)) is MethodInfo info) //if this type has an extra loot method { typesToPatch.Add(info.DeclaringType); //add that method's declaring type to the set } } } Utility.Monitor.Log($"Applying Harmony patch \"{nameof(HarmonyPatch_ToggleExtraLoot)}\": postfixing {typesToPatch.Count} implementations of SDV method \"Monster.getExtraDropitems()\".", LogLevel.Trace); foreach (Type type in typesToPatch) //for each type that implements a unique version of the target method { try { Utility.Monitor.VerboseLog($"* Postfixing SDV method \"{type.Name}.getExtraDropitems()\"."); harmony.Patch( original: AccessTools.Method(type, nameof(Monster.getExtraDropItems)), postfix: new HarmonyMethod(typeof(HarmonyPatch_ToggleExtraLoot), nameof(getExtraDropItems_Postfix)) ); } catch (Exception ex) { Utility.Monitor.VerboseLog($"Encountered an error while patching. Skipping {type.Name}. Full error message: {ex.ToString()}"); } } }
/// <summary>Applies this Harmony patch to the game.</summary> /// <param name="harmony">The <see cref="Harmony"/> created with this mod's ID.</param> /// <param name="monitor">The <see cref="IMonitor"/> provided by SMAPI. Used for log messages.</param> public static void ApplyPatch(Harmony harmony, IMonitor monitor) { if (Applied) { return; } //store args Monitor = monitor; //initialize assets/properties AssetName = ModEntry.AssetPrefix + "FishLocations"; //create asset name TilePropertyName = ModEntry.PropertyPrefix + "FishLocations"; //create tile property name AssetHelper.SetDefault(AssetName, new Dictionary <string, FishLocationsData>()); //create a default instance for the asset //get methods to patch dynamically HashSet <Type> getFishingLocationMethods = new HashSet <Type>(); //every type with a unique GameLocation.getFishingLocation(Vector2) HashSet <Type> oceanCrabPotMethods = new HashSet <Type>(); //every type with a unique GameLocation.catchOceanCrabPotFishFromThisSpot(int, int) foreach (Type type in AccessTools.AllTypes()) //for every type { if (typeof(GameLocation).IsAssignableFrom(type)) //if this is a type of GameLocation { if (AccessTools.Method(type, nameof(GameLocation.getFishingLocation), new[] { typeof(Vector2) }) is MethodInfo fishing) //if this type has a fishing method { getFishingLocationMethods.Add(fishing.DeclaringType); //add the method's declaring type to the set } if (AccessTools.Method(type, nameof(GameLocation.catchOceanCrabPotFishFromThisSpot), new[] { typeof(int), typeof(int) }) is MethodInfo ocean) //if this type has a crab pot method { oceanCrabPotMethods.Add(ocean.DeclaringType); //add the method's declaring type to the set } } } //apply patches Monitor.Log($"Applying Harmony patch \"{nameof(HarmonyPatch_FishLocations)}\": postfixing every implementation of method \"GameLocation.getFishingLocation(Vector2)\".", LogLevel.Trace); foreach (var type in getFishingLocationMethods) //for each unique version of the fishing method { Monitor.VerboseLog($"Applying Harmony patch \"{nameof(HarmonyPatch_FishLocations)}\": postfixing method \"{type.Name}.getFishingLocation(Vector2)\"."); harmony.Patch( original: AccessTools.Method(type, nameof(GameLocation.getFishingLocation), new[] { typeof(Vector2) }), postfix: new HarmonyMethod(typeof(HarmonyPatch_FishLocations), nameof(Postfix_getFishingLocation)) ); } Monitor.Log($"Applying Harmony patch \"{nameof(HarmonyPatch_FishLocations)}\": postfixing every implementation of method \"GameLocation.catchOceanCrabPotFishFromThisSpot(int, int)\".", LogLevel.Trace); foreach (var type in oceanCrabPotMethods) //for each unique version of the crab pot method { Monitor.VerboseLog($"Applying Harmony patch \"{nameof(HarmonyPatch_FishLocations)}\": postfixing method \"{type.Name}.catchOceanCrabPotFishFromThisSpot(int, int)\"."); harmony.Patch( original: AccessTools.Method(type, nameof(GameLocation.catchOceanCrabPotFishFromThisSpot), new[] { typeof(int), typeof(int) }), postfix: new HarmonyMethod(typeof(HarmonyPatch_FishLocations), nameof(Postfix_catchOceanCrabPotFishFromThisSpot)) ); } Monitor.Log($"Applying Harmony patch \"{nameof(HarmonyPatch_FishLocations)}\": transpiling method \"CrabPot.DayUpdate(GameLocation)\".", LogLevel.Trace); harmony.Patch( original: AccessTools.Method(typeof(CrabPot), nameof(CrabPot.DayUpdate)), transpiler: new HarmonyMethod(typeof(HarmonyPatch_FishLocations), nameof(Transpiler_CrabPot_DayUpdate)) ); Monitor.Log($"Applying Harmony patch \"{nameof(HarmonyPatch_FishLocations)}\": prefixing method \"GameLocation.getFish(float, int, int, Farmer, double, Vector2, string)\".", LogLevel.Trace); harmony.Patch( original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.getFish)), prefix: new HarmonyMethod(typeof(HarmonyPatch_FishLocations), nameof(Prefix_getFish)) ); Applied = true; }