heey1LX10C

Created at: Aug 29 14:51 2025

using System;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewModdingAPI.Utilities;
using StardewValley;
using StardewValley.Locations;

namespace BeaSummitPatches
{
    /// <summary>The mod entry point.</summary>
    internal sealed class ModEntry : Mod
    {
        public static IMonitor smonitor;
        internal static Action<GameLocation, GameTime> GameLocation_UpdateWhenCurrentLocation_Call = null!;
        public override void Entry(IModHelper helper)
        {
            ModEntry.smonitor = this.Monitor;
            var harmony = new Harmony(this.ModManifest.UniqueID);

            // harmony.Patch(
            //     //         public TemporaryAnimatedSprite(string textureName, Rectangle sourceRect, float animationInterval, int animationLength, int numberOfLoops, Vector2 position, bool flicker, bool flipped, float layerDepth, float alphaFade, Color color, float scale, float scaleChange, float rotation, float rotationChange, bool local = false)        

            //     //                original: AccessTools.Constructor(typeof(SDate), new Type[] { typeof(int), typeof(string), typeof(int), typeof(bool) }),
            //     original: AccessTools.Constructor(typeof(TemporaryAnimatedSprite), new Type[] { typeof(string), typeof(Rectangle), typeof(float), typeof(int), typeof(int), typeof(Vector2), typeof(bool), typeof(bool), typeof(float), typeof(float), typeof(Color), typeof(float), typeof(float), typeof(float), typeof(float), typeof(bool) }),
            //     postfix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.TemporaryAnimatedSprite_Constructor_Postfix))
            // );
            // https://github.com/Mushymato/HaveMoreKids/blob/main/HaveMoreKids/Framework/Patches/Child.cs#L30 - MPL2.0

            var baseMethod = typeof(GameLocation).GetMethod(
                "UpdateWhenCurrentLocation",
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
            );

            var dm = new DynamicMethod(
                "GameLocation_UpdateWhenCurrentLocation",
                typeof(void),
                new[] { typeof(GameLocation), typeof(GameTime) },
                typeof(GameLocation)
            );

            var il = dm.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Call, baseMethod);
            il.Emit(OpCodes.Ret);

            GameLocation_UpdateWhenCurrentLocation_Call =
                (Action<GameLocation, GameTime>)dm.CreateDelegate(typeof(Action<GameLocation, GameTime>));

            harmony.Patch(
                original: AccessTools.Method(typeof(StardewValley.Locations.Summit), nameof(StardewValley.Locations.Summit.UpdateWhenCurrentLocation)),
                prefix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.UpdateWhenCurrentLocation_Prefix)),
                postfix: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.UpdateWhenCurrentLocation_Postfix))
            );

            harmony.Patch(
                original: AccessTools.Method(typeof(StardewValley.Game1), nameof(StardewValley.Game1.drawWeather)),
                transpiler: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.Game1_updateWeather_Transpiler))
            );

            harmony.Patch(
                original: AccessTools.Method(typeof(StardewValley.GameLocation), nameof(StardewValley.GameLocation.setUpLocationSpecificFlair)),
                transpiler: new HarmonyMethod(typeof(ModEntry), nameof(ModEntry.GameLocation_setUpLocationSpecificFlair_Transpiler))
            );

        }

        // return false to skip original, true to run the original
        public static bool UpdateWhenCurrentLocation_Prefix(Summit __instance, GameTime time)
        {
            // smonitor.Log($"update when current location prefix called! is raining here: {Game1.currentLocation.IsRainingHere()}, other check {!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2(Game1.viewport.X / 64, Game1.viewport.Y / 64))}", LogLevel.Info);
            GameLocation_UpdateWhenCurrentLocation_Call(__instance, time);

            return false;
        }

        public static void UpdateWhenCurrentLocation_Postfix(Summit __instance)
        {
            // smonitor.Log("postfix called!", LogLevel.Info);
        }
        
        public static IEnumerable<CodeInstruction> Game1_updateWeather_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
        {
            try
            {
                CodeMatcher matcher = new(instructions, generator);

                // refuses to work for some reason

                // IL_02b3: call class StardewValley.GameLocation StardewValley.Game1::get_currentLocation()
                // IL_02b8: isinst StardewValley.Locations.Summit
                // IL_02bd: brtrue IL_03ab

                matcher.MatchStartForward(
                    [
                        new(OpCodes.Call, AccessTools.PropertyGetter(typeof(Game1), nameof(Game1.currentLocation))),
                        new(OpCodes.Isinst, typeof(Summit)),
                        new(OpCodes.Brtrue),
                    ]
                );

                matcher.ThrowIfNotMatch("Failed to match summit check");
                matcher.RemoveInstructions(3);

                // matcher.Instructions().ForEach(inst =>
                //     {
                //         Console.WriteLine(inst);
                //     }
                // );

                return matcher.Instructions();
            }
            catch (Exception err)
            {
                smonitor.Log($"Error in Game1_updateWeather_Transpiler:\n{err}", LogLevel.Error);
                return instructions;
            }
        }

        public static IEnumerable<CodeInstruction> GameLocation_setUpLocationSpecificFlair_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
        {
            try
            {
                CodeMatcher matcher = new(instructions, generator);

                // refuses to work for some reason

                // IL_02b1: ldloc.s 7
                // IL_02b3: ldstr "Summit"
                // IL_02b8: call bool [System.Runtime]System.String::op_Equality(string, string)
                // IL_02bd: brtrue IL_0514

                // // break;
                // IL_02c2: ret


                matcher.MatchStartForward(
                    [
                        // new(OpCodes.Ldloc_S),
                        new(OpCodes.Ldstr, "Summit"),
                        // new(OpCodes.Call),
                        // new(OpCodes.Brtrue),
                        // new(OpCodes.Ret),
                    ]
                );

                

                matcher.ThrowIfNotMatch("Failed to match gamelocation specific flair check");
                matcher.RemoveInstructions(1);
                matcher.InsertAndAdvance(
                    [
                        new(OpCodes.Ldstr, "BeaSummitPatches.SummitDarkReplacement"),
                    ]
                );

                // matcher.Instructions().ForEach(inst =>
                //     {
                //         smonitor.Log(inst.ToString(), LogLevel.Info);
                //     }
                // );

                // matcher.Instructions().ForEach(inst =>
                //     {
                //         Console.WriteLine(inst);
                //     }
                // );

                return matcher.Instructions();
            }
            catch (Exception err)
            {
                smonitor.Log($"Error in GameLocation_setUpLocationSpecificFlair_Transpiler:\n{err}", LogLevel.Error);
                return instructions;
            }
        }
    }
}

Created by Pillow

Report Paste Raw Paste