예제 #1
0
        /// <summary>Runs once after all mods are loaded by SMAPI. Initializes file data, events, and Harmony patches.</summary>
        public override void Entry(IModHelper helper)
        {
            //initialize utilities
            AssetHelper.Initialize(helper);
            TileData.Monitor = Monitor;

            //load config.json
            ModConfig.Initialize(helper, Monitor);

            //initialize mod interactions
            helper.Events.GameLoop.GameLaunched += GameLoop_GameLaunched_InitializeModInteractions;

            //initialize Harmony and mod features
            Harmony harmony = new Harmony(ModManifest.UniqueID);

            //fish locations
            HarmonyPatch_FishLocations.ApplyPatch(harmony, Monitor);

            //custom order boards
            HarmonyPatch_CustomOrderBoards.ApplyPatch(harmony, Monitor);
            DisplayNewOrderExclamationPoint.Enable(helper, Monitor);
            Command_CustomBoard.Enable(helper, Monitor);

            //destroyable bushes
            HarmonyPatch_DestroyableBushes.ApplyPatch(harmony, Monitor);

            //bed placement
            HarmonyPatch_BedPlacement.ApplyPatch(harmony, Monitor);
            HarmonyPatch_PassOutSafely.ApplyPatch(harmony, Monitor);

            //kitchen features
            HarmonyPatch_ActionKitchen.ApplyPatch(harmony, Monitor);
            HarmonyPatch_AllowMiniFridges.ApplyPatch(harmony, Monitor);

            //water color
            WaterColor.Enable(helper, Monitor);
        }
        /// <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;
        }