예제 #1
0
            /// <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;
        }