コード例 #1
0
            // This method creates the hooks
            private void HookRando()
            {
                /*
                 * First we need to navigate the randomizer namespace to get the class and therefore the type
                 * This is done by using Type.GetType ("Namespace , AssemblyName")
                 * AssemblyName will always be RandomizerMod3.0 if it's rando you're hooking. If you're hooking another mod, it's the mod's name on the top left in the title screen
                 * Namespace is usually figured out through going to Github and checking the code of the mod
                 *
                 */

                /*
                 * As an example, here we'll obtain both GiveItemActions, and CreateNewShiny, found respectively on
                 * https://github.com/homothetyhk/HollowKnight.RandomizerMod/blob/e75fce28f373e178d12dfda007f2a1aae19cfba3/RandomizerMod3.0/GiveItemActions.cs
                 * (Namespace RandomizerMod + . + Class name => "RandomizerMod.GiveItemActions, RandomizerMod3.0")
                 * https://github.com/homothetyhk/HollowKnight.RandomizerMod/blob/e75fce28f373e178d12dfda007f2a1aae19cfba3/RandomizerMod3.0/Actions/CreateNewShiny.cs
                 * (Namespace RandomizerMod.Actions + . + Class name => ""RandomizerMod.Actions.CreateNewShiny, RandomizerMod3.0" )
                 */

                Type giveItemActions = Type.GetType("RandomizerMod.GiveItemActions, RandomizerMod3.0");
                Type createNewShiny  = Type.GetType("RandomizerMod.Actions.CreateNewShiny, RandomizerMod3.0");

                // After doing this you have to check the types aren't null before interacting with them. This ensures the mod is actually present and loaded, instead of dying if
                // the user is using your mod without the hooked one

                if (giveItemActions == null || createNewShiny == null)
                {
                    return;
                }

                BingoUI.Log("Hooking Rando");

                BingoUI.Log("Hooking GiveItemActions");

                /*  This is the hook constructor.
                 *  It's Hook( Method you're hooking , Method you're replacing it with)
                 *  Here we will replace GiveItemAction's GiveItem() method with out own FixRando
                 *  Since this takes two MethodInfo, you need to fetch your own method through Reflection too, which is slightly sad imo
                 */
                _giveActionsSetIntHook = new Hook
                                         (
                    giveItemActions.GetMethod("GiveItem"),                 // This is this method https://github.com/homothetyhk/HollowKnight.RandomizerMod/blob/e75fce28f373e178d12dfda007f2a1aae19cfba3/RandomizerMod3.0/GiveItemActions.cs#L46
                    typeof(RandoCompatibility).GetMethod(nameof(FixRando)) // This is our own. Look below
                                         );

                BingoUI.Log("Hooking CreateNewShiny for Cornifer locations");

                _corniferLocationHook = new Hook
                                        (
                    createNewShiny.GetMethod("Process"),                             // This is this method https://github.com/homothetyhk/HollowKnight.RandomizerMod/blob/e75fce28f373e178d12dfda007f2a1aae19cfba3/RandomizerMod3.0/Actions/CreateNewShiny.cs#L25
                    typeof(RandoCompatibility).GetMethod(nameof(PatchRandoCornifer)) // This is our own. Look below
                                        );
            }
コード例 #2
0
            private void HookPlando()
            {
                ItemChanger.GiveItemActions.OnGiveItem += FixPlandoDelayStarter;

                Type createNewShiny = Type.GetType("ItemChanger.Actions.CreateNewShiny, ItemChanger");

                BingoUI.Log("Hooking CreateNewShiny for Cornifer locations");

                _corniferLocationHook = new Hook
                                        (
                    createNewShiny?.GetMethod("Process"),
                    typeof(PlandoCompatibility).GetMethod(nameof(PatchPlandoCornifer))
                                        );
            }
コード例 #3
0
            public static void PatchRandoCornifer
            (
                Action <RandomizerAction, string, object> orig,
                RandomizerAction self,
                string scene,
                object changeObj
            )
            {
                orig(self, scene, changeObj); // This is a call to the originally hooked method to make it run. If you don't do this the original method will never run, which is something BingoUI does not want (but you might)

                // Below this it's mostly things not related to hooking but to BingoUI execution so I won't bother adding comments.

                if (!CorniferPositions.Keys.Contains(scene))
                {
                    return;
                }

                Type createNewShiny = Type.GetType("RandomizerMod.Actions.CreateNewShiny, RandomizerMod3.0");

                if (createNewShiny == null)
                {
                    return;
                }

                // ReSharper disable PossibleNullReferenceException
                float x = (float)createNewShiny.GetField("_x", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(self);
                float y = (float)createNewShiny.GetField("_y", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(self);

                // ReSharper enable PossibleNullReferenceException

                if ((CorniferPositions[scene] - new Vector2(x, y)).magnitude > 3.0f)
                {
                    return;
                }

                BingoUI.Log("Patching rando cornifer");

                GameObject cornifer = GameObject.Find
                                      (
                    (string)createNewShiny
                    .GetField("_newShinyName", BindingFlags.NonPublic | BindingFlags.Instance)?
                    .GetValue(self)
                                      );

                PlayMakerFSM shinyControl = cornifer.LocateMyFSM("Shiny Control");

                shinyControl.InsertMethod("Hero Down", 0, () => OnCorniferLocation.Invoke(scene));
            }
コード例 #4
0
            public static void PatchPlandoCornifer
            (
                Action <ItemChanger.Actions.RandomizerAction, string, object> orig,
                ItemChanger.Actions.RandomizerAction self,
                string scene,
                object changeObj
            )
            {
                orig(self, scene, changeObj);

                if (!CorniferPositions.Keys.Contains(scene))
                {
                    return;
                }

                Type createNewShiny = Type.GetType("ItemChanger.Actions.CreateNewShiny, ItemChanger");

                if (createNewShiny == null)
                {
                    return;
                }

                // ReSharper disable once PossibleNullReferenceException
                float x = (float)createNewShiny.GetField("_x", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(self);
                // ReSharper disable once PossibleNullReferenceException
                float y = (float)createNewShiny.GetField("_y", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(self);

                if ((CorniferPositions[scene] - new Vector2(x, y)).magnitude > 3.0f)
                {
                    return;
                }

                BingoUI.Log("Patching plando cornifer");

                GameObject cornifer = GameObject.Find
                                      (
                    (string)createNewShiny
                    .GetField("_newShinyName", BindingFlags.NonPublic | BindingFlags.Instance)
                    ?.GetValue(self)
                                      );

                PlayMakerFSM shinyControl = cornifer.LocateMyFSM("Shiny Control");

                shinyControl.InsertMethod("Hero Down", 0, () => OnCorniferLocation?.Invoke(scene));
            }
コード例 #5
0
        public override void Initialize()
        {
            Instance = this;

            SpriteLoader.LoadSprites();
            AbstractCounter.SetupCanvas();

            if (ModHooks.GetMod(nameof(ItemChanger.ItemChangerMod)) is Mod)
            {
                Log("Hooking Itemchanger");
                ItemChangerCompatibility.Initialize();
            }

            AbstractCounter.InitializeCounters();

            // Pause Hooks
            On.UIManager.GoToPauseMenu    += OnPause;
            On.UIManager.UIClosePauseMenu += OnUnpause;
            On.UIManager.ReturnToMainMenu += OnUnpauseQuitGame;
            UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;

            GeoTracker.Hook();
        }
コード例 #6
0
            private void CheckPlando()
            {
                /*
                 * Hooking plando is a huge hassle, because it has an internal hook we have to use
                 * (and so need to split the actual hooking up into two in order for it to not die), and
                 * because said hook is called before it actually does its thing so it needs to be delayed by a coroutine, which needs to not reference
                 * plando, else when it gets compiled into a class it dies
                 * So Check => Hook => Start routine => Delay => Actually do the hook stuff
                 */

                Type t = Type.GetType("ItemChanger.GiveItemActions, ItemChanger");

                if (t == null)
                {
                    return;
                }

                _plandoFound = true;

                BingoUI.Log("Hooking Plando");

                HookPlando();
            }
コード例 #7
0
            public static void FixRando
            (
                Action <GiveItemActions.GiveAction, string, string, int> orig,
                GiveItemActions.GiveAction action,
                string item,
                string location,
                int geo
            )
            {
                orig(action, item, location, geo); // This is a call to the originally hooked method to make it run. If you don't do this the original method will never run, which is something BingoUI does not want (but you might)

                // Below this it's mostly things not related to hooking but to BingoUI execution so comments won't be as in-depth.

                // Obtain the reqDef, which is how Rando manages which pool objects belong to. This is used for Grub locations in our case

                Type logicManager = Type.GetType("RandomizerMod.Randomization.LogicManager, RandomizerMod3.0");

                MethodInfo getItemDef = logicManager?.GetMethod("GetItemDef");

                if (getItemDef == null)
                {
                    return;
                }

                object reqDef = null;

                try
                {
                    reqDef = getItemDef.Invoke(null, new object[] { location }); // Shops are made to throw so catch it if it's a shop
                }
                catch (TargetInvocationException e)
                {
                    // If it's not a shop, re-throw.
                    if (!(e.InnerException is KeyNotFoundException))
                    {
                        BingoUI.Log($"Inner exception was not KeyNotFoundException, instead was {e.InnerException}");

                        throw;
                    }
                }

                string pool = (string)reqDef?.GetType().GetField("pool").GetValue(reqDef);  // Finally obtain the pool

                if (pool == "Grub")
                {
                    OnGrubLocation?.Invoke(location);
                }

                // This part is the one that checks what rando assigned then runs SetInt or SetBool so that other mods catch on
                // Literally just let rando do its thing and increment or whatever, then call SetInt with the same value so the hooked things run
                PlayerData pd = PlayerData.instance;

                switch (action)
                {
                case GiveItemActions.GiveAction.WanderersJournal:
                    pd.SetInt(nameof(pd.trinket1), pd.trinket1);
                    break;

                case GiveItemActions.GiveAction.HallownestSeal:
                    pd.SetInt(nameof(pd.trinket2), pd.trinket2);
                    break;

                case GiveItemActions.GiveAction.KingsIdol:
                    pd.SetInt(nameof(pd.trinket3), pd.trinket3);
                    break;

                case GiveItemActions.GiveAction.ArcaneEgg:
                    pd.SetInt(nameof(pd.trinket4), pd.trinket4);
                    break;

                case GiveItemActions.GiveAction.Grub:
                    if (OnGrubObtain?.Invoke() ?? true)
                    {
                        pd.SetInt(nameof(pd.grubsCollected), pd.grubsCollected);
                    }
                    break;

                case GiveItemActions.GiveAction.Kingsoul:
                    pd.SetBool(nameof(pd.gotCharm_36), true);
                    break;
                }
            }