Example #1
0
 private void Awake()
 {
     CharacterApi.RegisterExtraBehaviour <InvisibleBodyCharaController>("KK_InvisibleBody");
     MakerAPI.RegisterCustomSubCategories += MakerAPI_RegisterCustomSubCategories;
 }
Example #2
0
 private static CharacterApi.ControllerRegistration GetControllerRegistration()
 {
     return(CharacterApi.GetRegisteredBehaviour(KoiClothesOverlayMgr.GUID));
 }
Example #3
0
        internal void Main()
        {
            CharacterApi.RegisterExtraBehaviour <BetterPenetrationController>(BEHAVIOR);

            harmony = new Harmony("KK_Studio_BetterPenetration");
            harmony.PatchAll(typeof(KK_Studio_BetterPenetration));

            Chainloader.PluginInfos.TryGetValue("com.deathweasel.bepinex.uncensorselector", out PluginInfo pluginInfo);
            if (pluginInfo == null || pluginInfo.Instance == null)
            {
                return;
            }

            Type nestedType = pluginInfo.Instance.GetType().GetNestedType("UncensorSelectorController", AccessTools.all);

            if (nestedType == null)
            {
                return;
            }

            MethodInfo methodInfo = AccessTools.Method(nestedType, "ReloadCharacterPenis", null, null);

            if (methodInfo == null)
            {
                return;
            }

            harmony.Patch(methodInfo, prefix: new HarmonyMethod(typeof(KK_Studio_BetterPenetration), "BeforeDanCharacterReload"),
                          postfix: new HarmonyMethod(typeof(KK_Studio_BetterPenetration), "AfterDanCharacterReload"));
            Debug.Log("Studio_BetterPenetration: patched UncensorSelectorController::ReloadCharacterPenis correctly");

            methodInfo = AccessTools.Method(nestedType, "ReloadCharacterBalls", null, null);
            if (methodInfo == null)
            {
                return;
            }

            harmony.Patch(methodInfo, prefix: new HarmonyMethod(typeof(KK_Studio_BetterPenetration), "BeforeTamaCharacterReload"),
                          postfix: new HarmonyMethod(typeof(KK_Studio_BetterPenetration), "AfterTamaCharacterReload"));
            Debug.Log("Studio_BetterPenetration: patched UncensorSelectorController::ReloadCharacterBalls correctly");

            Chainloader.PluginInfos.TryGetValue("com.joan6694.illusionplugins.nodesconstraints", out pluginInfo);
            if (pluginInfo == null || pluginInfo.Instance == null)
            {
                return;
            }

            nodeConstraintPlugin = pluginInfo.Instance;
            Type nodeConstraintType = nodeConstraintPlugin.GetType();

            if (nodeConstraintType == null)
            {
                return;
            }

            methodInfo = AccessTools.Method(nodeConstraintType, "AddConstraint", null, null);
            if (methodInfo == null)
            {
                return;
            }

            harmony.Patch(methodInfo, postfix: new HarmonyMethod(typeof(KK_Studio_BetterPenetration), "AfterAddConstraint"));
            Debug.Log("Studio_BetterPenetration: patched NodeConstraints::AddConstraint correctly");

            methodInfo = AccessTools.Method(nodeConstraintType, "ApplyNodesConstraints", null, null);
            if (methodInfo == null)
            {
                return;
            }

            harmony.Patch(methodInfo, postfix: new HarmonyMethod(typeof(KK_Studio_BetterPenetration), "AfterApplyNodesConstraints"));
            Debug.Log("Studio_BetterPenetration: patched NodeConstraints::ApplyNodesConstraints correctly");

            methodInfo = AccessTools.Method(nodeConstraintType, "ApplyConstraints", null, null);
            if (methodInfo == null)
            {
                return;
            }

            harmony.Patch(methodInfo, postfix: new HarmonyMethod(typeof(KK_Studio_BetterPenetration), "AfterApplyConstraints"));
            Debug.Log("Studio_BetterPenetration: patched NodeConstraints::ApplyConstraints correctly");
        }
Example #4
0
        public void Awake()
        {
            WindowIDSleep = Config.Bind(SECTION_GENERAL, "__Window ID (Sleep Hours)", 83464);
            WindowIDDead  = Config.Bind(SECTION_GENERAL, "__Window ID (Dead)", 83465);

            StatusKey = Config.Bind(SECTION_SURVIVAL, "Status UI Key", new KeyboardShortcut(KeyCode.T));
            (PlayerStats = Config.Bind(SECTION_SURVIVAL, "Player Life Stats", true, DESCRIPTION_PLAYER_LIFE)).SettingChanged += (s, e) =>
            {
                playerController.statusHUD.SetVisible(Status.visibileHUD, PlayerDeath.Value != DeathType.None, PlayerStats.Value);
                Status.UpdateCellPhoneVisibility(PlayerDeath.Value != DeathType.None, PlayerStats.Value, AgentDeath.Value != DeathType.None);
            };
            (PlayerDeath = Config.Bind(SECTION_SURVIVAL, "Player Death", DeathType.Incapacitated, DESCRIPTION_PLAYER_DEATH)).SettingChanged += (s, e) =>
            {
                playerController.statusHUD.SetVisible(Status.visibileHUD, PlayerDeath.Value != DeathType.None, PlayerStats.Value);
                Status.UpdateCellPhoneVisibility(PlayerDeath.Value != DeathType.None, PlayerStats.Value, AgentDeath.Value != DeathType.None);
            };
            (AgentDeath = Config.Bind(SECTION_SURVIVAL, "Agent Death", DeathType.Incapacitated, DESCRIPTION_AGENT_DEATH)).SettingChanged += (s, e) =>
            {
                foreach (var controller in agentControllers.Where(n => n != null))
                {
                    controller.statusHUD.SetVisible(Status.visibileHUD, AgentDeath.Value != DeathType.None, AgentDeath.Value != DeathType.None);
                }

                Status.UpdateCellPhoneVisibility(PlayerDeath.Value != DeathType.None, PlayerStats.Value, AgentDeath.Value != DeathType.None);
            };

            SleepAnytime   = Config.Bind(SECTION_SLEEP, "Sleep Anytime", true);
            SetHoursAsleep = Config.Bind(SECTION_SLEEP, "Set Hours Asleep", true, DESCRIPTION_SET_HOURS_ASLEEP);
            WakeHour       = Config.Bind(SECTION_SLEEP, "Wake Up Hour", 8, new ConfigDescription(DESCRIPTION_WAKE_HOUR, new AcceptableValueRange <int>(0, 23)));

            AgentHealthLoss          = Config.Bind(SECTION_LOSS, "Agent Health Loss - Collapsed", 2f, new ConfigDescription(DESCRIPTION_AGENT_HEALTH_LOSS, new AcceptableValueRange <float>(0, 100)));
            AgentHealthLossCold      = Config.Bind(SECTION_LOSS, "Agent Health Loss - Cold", 1f, new ConfigDescription(DESCRIPTION_AGENT_HEALTH_LOSS_COLD, new AcceptableValueRange <float>(0, 100)));
            AgentHealthLossHeat      = Config.Bind(SECTION_LOSS, "Agent Health Loss - Heatstroke", 4f, new ConfigDescription(DESCRIPTION_AGENT_HEALTH_LOSS_HEAT, new AcceptableValueRange <float>(0, 100)));
            AgentHealthLossHurt      = Config.Bind(SECTION_LOSS, "Agent Health Loss - Hurt", 6f, new ConfigDescription(DESCRIPTION_AGENT_HEALTH_LOSS_HURT, new AcceptableValueRange <float>(0, 100)));
            AgentHealthLossHunger    = Config.Bind(SECTION_LOSS, "Agent Health Loss - Hunger", 2f, new ConfigDescription(DESCRIPTION_AGENT_HEALTH_LOSS_HUNGER, new AcceptableValueRange <float>(0, 100)));
            AgentHealthLossThirst    = Config.Bind(SECTION_LOSS, "Agent Health Loss - Thirst", 2f, new ConfigDescription(DESCRIPTION_AGENT_HEALTH_LOSS_THIRST, new AcceptableValueRange <float>(0, 100)));
            AgentFoodLossStomachache = Config.Bind(SECTION_LOSS, "Agent Food Loss - Stomachache", 2f, new ConfigDescription(DESCRIPTION_AGENT_FOOD_LOSS_STOMACHACHE, new AcceptableValueRange <float>(0, 100)));
            AgentStaminaLossOverwork = Config.Bind(SECTION_LOSS, "Agent Stamina Loss - Overwork", 4f, new ConfigDescription(DESCRIPTION_AGENT_STAMINA_LOSS_OVERWORK, new AcceptableValueRange <float>(0, 100)));

            HealthLoss  = Config.Bind(SECTION_LOSS, "Player Health Loss", 2.5f, new ConfigDescription(DESCRIPTION_HEALTH_LOSS, new AcceptableValueRange <float>(0, 100)));
            StaminaLoss = Config.Bind(SECTION_LOSS, "Player Stamina Loss", 4f, new ConfigDescription(DESCRIPTION_STAMINA_LOSS, new AcceptableValueRange <float>(0, 100)));
            CaloriePool = Config.Bind(SECTION_LOSS, "Player Calorie Pool", 7500f, new ConfigDescription(DESCRIPTION_CALORIE_POOL, new AcceptableValueRange <float>(2500, 25000)));
            CalorieLoss = Config.Bind(SECTION_LOSS, "Player Calorie Loss Per Day", 2500f, new ConfigDescription(DESCRIPTION_CALORIE_LOSS, new AcceptableValueRange <float>(0, 10000)));
            WaterPool   = Config.Bind(SECTION_LOSS, "Player Water Pool", 4000f, new ConfigDescription(DESCRIPTION_WATER_POOL, new AcceptableValueRange <float>(2000, 20000)));
            WaterLoss   = Config.Bind(SECTION_LOSS, "Player Water Loss Per Day", 2000f, new ConfigDescription(DESCRIPTION_WATER_LOSS, new AcceptableValueRange <float>(0, 8000)));

            AgentHealthRate   = Config.Bind(SECTION_RECOVER, "Agent Health Recovery (per Game-Hour)", 1f, new ConfigDescription(DESCRIPTION_AGENT_HEALTH_RATE, new AcceptableValueRange <float>(0, 100)));
            HealthRate        = Config.Bind(SECTION_RECOVER, "Player Health Recovery (per Game-Hour)", 1f, new ConfigDescription(DESCRIPTION_HEALTH_RATE, new AcceptableValueRange <float>(0, 100)));
            StaminaRate       = Config.Bind(SECTION_RECOVER, "Player Stamina Recovery (per Game-Hour)", 10f, new ConfigDescription(DESCRIPTION_STAMINA_RATE, new AcceptableValueRange <float>(0, 100)));
            CalorieEfficiency = Config.Bind(SECTION_RECOVER, "Restore Food Efficiency", 100f, new ConfigDescription(DESCRIPTION_FOOD_EFFICIENCY, new AcceptableValueRange <float>(0, 500)));
            WaterEfficiency   = Config.Bind(SECTION_RECOVER, "Restore Water Efficiency", 100f, new ConfigDescription(DESCRIPTION_WATER_EFFICIENCY, new AcceptableValueRange <float>(0, 500)));

            AgentLowFood       = Config.Bind(SECTION_PENALTY, "Agent Low Food Threshold", 0f, new ConfigDescription(DESCRIPTION_AGENT_LOW_FOOD, new AcceptableValueRange <float>(0, 100)));
            AgentLowWater      = Config.Bind(SECTION_PENALTY, "Agent Low Water Threshold", 0f, new ConfigDescription(DESCRIPTION_AGENT_LOW_WATER, new AcceptableValueRange <float>(0, 100)));
            LowFood            = Config.Bind(SECTION_PENALTY, "Player Low Food Threshold", 0f, new ConfigDescription(DESCRIPTION_LOW_FOOD, new AcceptableValueRange <float>(0, 100)));
            LowWater           = Config.Bind(SECTION_PENALTY, "Player Low Water Threshold", 0f, new ConfigDescription(DESCRIPTION_LOW_WATER, new AcceptableValueRange <float>(0, 100)));
            LowStamina         = Config.Bind(SECTION_PENALTY, "Player Low Stamina Threshold", 0f, new ConfigDescription(DESCRIPTION_LOW_STAMINA, new AcceptableValueRange <float>(0, 100)));
            AgentRevivePenalty = Config.Bind(SECTION_PENALTY, "Agent Revive Penalty", RevivePenalty.StatLoss, DESCRIPTION_AGENT_REVIVE_PENALTY);
            PlayerDeathReset   = Config.Bind(SECTION_PENALTY, "Player Death Agent Reset", true, DESCRIPTION_PLAYER_DEATH_RESET);

            HealthWarn  = Config.Bind(SECTION_WARN, "Health Warning", 30, new ConfigDescription(DESCRIPTION_HEALTH_WARN, new AcceptableValueRange <int>(0, 100)));
            AgentWarn   = Config.Bind(SECTION_WARN, "Agent Health Warning", 30, new ConfigDescription(DESCRIPTION_AGENT_WARN, new AcceptableValueRange <int>(0, 100)));
            FoodWarn    = Config.Bind(SECTION_WARN, "Food Warning", 20, new ConfigDescription(DESCRIPTION_FOOD_WARN, new AcceptableValueRange <int>(0, 100)));
            WaterWarn   = Config.Bind(SECTION_WARN, "Water Warning", 20, new ConfigDescription(DESCRIPTION_WATER_WARN, new AcceptableValueRange <int>(0, 100)));
            StaminaWarn = Config.Bind(SECTION_WARN, "Stamina Warning", 20, new ConfigDescription(DESCRIPTION_STAMINA_WARN, new AcceptableValueRange <int>(0, 100)));

            CharacterApi.RegisterExtraBehaviour <LifeStatsController>(BEHAVIOR);
            HarmonyLib.Harmony.CreateAndPatchAll(typeof(HardcoreMode));
        }
 private void Main()
 {
     AnimationControllerHotkey = new SavedKeyboardShortcut(nameof(AnimationControllerHotkey), nameof(KK_AnimationController), new KeyboardShortcut(KeyCode.Minus));
     CharacterApi.RegisterExtraBehaviour <AnimationControllerCharaController>(GUID);
     StudioSaveLoadApi.RegisterExtraBehaviour <AnimationControllerSceneController>(GUID);
 }
Example #6
0
        internal void Start()
        {
            Logger = base.Logger;

            ConfigEnablePushup = Config.Bind("Config", "Enable Pushup By Default", false, new ConfigDescription("Whether the pushup effect is enabled by default when a bra is worn.", null, new ConfigurationManagerAttributes {
                Order = 10
            }));
            ConfigFirmnessDefault = Config.Bind("Config", "Firmness Default Value", 0.9f, new ConfigDescription("Firmness of the breasts. More firm means less bounce.", new AcceptableValueRange <float>(0f, 1f), new ConfigurationManagerAttributes {
                Order = 9
            }));
            ConfigLiftDefault = Config.Bind("Config", "Lift Default Value", 0.6f, new ConfigDescription("Lift of the breasts. Lift is the minimum height position of the breasts when a bra is worn.", new AcceptableValueRange <float>(0f, 1f), new ConfigurationManagerAttributes {
                Order = 8
            }));
            ConfigPushTogetherDefault = Config.Bind("Config", "Push Together Default Value", 0.55f, new ConfigDescription("How much the breasts will be pushed together when a bra is worn, if they are set far apart.", new AcceptableValueRange <float>(0f, 1f), new ConfigurationManagerAttributes {
                Order = 7
            }));
            ConfigSqueezeDefault = Config.Bind("Config", "Squeeze Default Value", 0.6f, new ConfigDescription("Long breasts will be flattened by this amount.", new AcceptableValueRange <float>(0f, 1f), new ConfigurationManagerAttributes {
                Order = 6
            }));
            ConfigNippleCenteringDefault = Config.Bind("Config", "Nipple Centering Default Value", 0.5f, new ConfigDescription("If the nipples point up or down, wearing a bra will make them point forwards.", new AcceptableValueRange <float>(0f, 1f), new ConfigurationManagerAttributes {
                Order = 5
            }));
            ConfigFlattenNipplesDefault = Config.Bind("Config", "Flatten Nipples Default", true, new ConfigDescription("Flatten nipples while a bra is worn.", null, new ConfigurationManagerAttributes {
                Order = 4
            }));
            ConfigSliderMin = Config.Bind("Config", "Advanced Mode Slider Minimum", -100, new ConfigDescription("Minimum value of advanced mode sliders.", new AcceptableValueRange <int>(-500, 0), new ConfigurationManagerAttributes {
                Order = 3
            }));
            ConfigSliderMax = Config.Bind("Config", "Advanced Mode Slider Maximum", 200, new ConfigDescription("Maximum value of advanced mode sliders.", new AcceptableValueRange <int>(100, 500), new ConfigurationManagerAttributes {
                Order = 2
            }));

            CharacterApi.RegisterExtraBehaviour <PushupController>(GUID);
            MakerAPI.RegisterCustomSubCategories += RegisterCustomSubCategories;
            MakerAPI.ReloadCustomInterface       += ReloadCustomInterface;
            MakerAPI.MakerExiting         += MakerExiting;
            MakerAPI.MakerFinishedLoading += MakerFinishedLoading;
            RegisterStudioControls();

            var harmony = HarmonyWrapper.PatchAll(typeof(Hooks));

            //Patch all the slider onValueChanged events to return false and cancel original code
            //Pushup adds its own onValueChanged event that manages this stuff
            foreach (var anonType in typeof(ChaCustom.CvsBreast).GetNestedTypes(AccessTools.all).Where(x => x.Name.Contains("<Start>")))
            {
                foreach (var anonTypeMethod in anonType.GetMethods(AccessTools.all).Where(x => x.Name.Contains("<>m")))
                {
                    if (anonTypeMethod.GetParameters().Any(x => x.ParameterType == typeof(float)))
                    {
                        harmony.Patch(anonTypeMethod, new HarmonyMethod(typeof(Hooks).GetMethod(nameof(Hooks.SliderHook), AccessTools.all)));
                    }
                }
            }

            var sliders = typeof(ChaCustom.CvsBreast).GetMethods(AccessTools.all).Where(x => x.Name.Contains("<Start>") && x.GetParameters().Any(y => y.ParameterType == typeof(float))).ToList();

            //Don't patch areola size or nipple gloss since they are not managed by this plugin
            foreach (var slider in sliders)
            {
                if (Application.productName == Constants.MainGameProcessName)
                {
                    if (slider.Name == "<Start>m__E")
                    {
                    }                                    //areola size
                    else if (slider.Name == "<Start>m__14")
                    {
                    }                                          //nipple gloss
                    else
                    {
                        harmony.Patch(slider, new HarmonyMethod(typeof(Hooks).GetMethod(nameof(Hooks.SliderHook), AccessTools.all)));
                    }
                }
                else if (Application.productName == Constants.MainGameProcessNameSteam)
                {
                    if (slider.Name == "<Start>m__10")
                    {
                    }                                     //areola size
                    else if (slider.Name == "<Start>m__17")
                    {
                    }                                          //nipple gloss
                    else
                    {
                        harmony.Patch(slider, new HarmonyMethod(typeof(Hooks).GetMethod(nameof(Hooks.SliderHook), AccessTools.all)));
                    }
                }
            }
        }
Example #7
0
 internal void Main()
 {
     CharacterApi.RegisterExtraBehaviour <ProfileController>(PluginNameInternal);
     MakerAPI.RegisterCustomSubCategories += MakerAPI_RegisterCustomSubCategories;
     MakerAPI.MakerFinishedLoading        += MakerAPI_MakerFinishedLoading;
 }
        private void Start()
        {
            Logger = base.Logger;

            #if KK
            PregnancyProgressionSpeed = Config.Bind("General", "Pregnancy progression speed", 4,
                                                    new ConfigDescription("How much faster does the in-game pregnancy progresses than the standard 40 weeks. " +
                                                                          "It also reduces the time characters leave school for after birth.\n\n" +
                                                                          "x1 is 40 weeks, x2 is 20 weeks, x4 is 10 weeks, x10 is 4 weeks.",
                                                                          new AcceptableValueList <int>(1, 2, 4, 10)));
            #elif AI
            PregnancyProgressionSpeed = Config.Bind("General", "Pregnancy progression speed", 4,
                                                    new ConfigDescription("How much faster does the in-game pregnancy progresses than the standard 4 weeks. \n\n" +
                                                                          "x1 is 4 weeks, x2 is 2 weeks, x4 is 1 week, x10 is ~4 days.",
                                                                          new AcceptableValueList <int>(1, 2, 4, 10)));
            #endif

            ConceptionEnabled = Config.Bind("General", "Enable conception", true,
                                            "Allows characters to get pregnant from vaginal sex. Doesn't affect already pregnant characters.");

            FertilityOverride = Config.Bind("General", "Minimum fertility level", 0f,
                                            new ConfigDescription("If a character has a lower fertility level than this set, this level will be used instead. \n\n" +
                                                                  "0 - The value saved in the character card is used (30% by default)\n" +
                                                                  "30%, 50%, 75%, 100% - If the character card's saved value is lower, it will be raised to this level in HScenes.",
                                                                  new AcceptableValueList <float>(0f, 0.3f, 0.5f, 0.75f, 1f)));

            AnalConceptionEnabled = Config.Bind("General", "Enable anal conception", false,
                                                "Allows characters to get pregnant from anal sex. Doesn't affect already pregnant characters.");

            ShowPregnancyIconEarly = Config.Bind("General", "Show pregnancy icon early", false,
                                                 "By default pregnancy status icon in class roster is shown after a few days or weeks (the character had a chance to do the test or noticed something is wrong).\n" +
                                                 "Turning this on will always make the icon show up at the end of the current day.");

            HSceneMenstrIconOverride = Config.Bind("General", "Use custom safe/risky icons in H Scenes", true,
                                                   "Replaces the standard safe/risky indicators with custom indicators that can also show pregnancy and unknown status. " +
                                                   "If the status is unknown you will have to listen for the voice cues instead.\nChanges take effect after game restart.");

            InflationEnable = Config.Bind("Inflation", "Enable inflation", true, "Turn on the inflation effect.");

            InflationSpeed = Config.Bind("Inflation", "Inflation speed modifier", 1,
                                         new ConfigDescription("How quickly the belly will inflate/deflate compared to normal (1x, 2x, 3x as fast).", new AcceptableValueList <int>(1, 2, 3)));

            InflationOpenClothAtMax = Config.Bind("Inflation", "Open clothes at max inflation", true,
                                                  "If clothes are fully on, open them when inflation reaches the max value (they 'burst' open).");

            InflationMaxCount = Config.Bind("Inflation", "Cum count until full", 8,
                                            new ConfigDescription("How many times you have to let out inside to reach the maximum belly size.", new AcceptableValueRange <int>(2, 15)));

            #if KK
            LactationEnabled = Config.Bind("Lactation", "Enable lactation", true,
                                           "Enable the lactation effect. For the effect to work the character has to be pregnant, or the override setting has to be enabled.");

            LactationFillTime = Config.Bind("Lactation", "Time to fully refill", 5,
                                            new ConfigDescription("How many minutes it takes to fully refill the milk. 0 is always fully refilled.", new AcceptableValueRange <int>(0, 10)));

            LactationForceMaxCapacity = Config.Bind("Lactation", "Force max milk capacity", false,
                                                    "If enabled, all characters will lactate and have full capacity. If off, capacity depends on the pregnancy progress.");
            #endif

            CharacterApi.RegisterExtraBehaviour <PregnancyCharaController>(GUID);
            GameAPI.RegisterExtraBehaviour <PregnancyGameController>(GUID);

            var hi = new Harmony(GUID);
            Hooks.InitHooks(hi);
            PregnancyGui.Init(hi, this);
        }
 private void Awake()
 {
     CharacterApi.RegisterExtraBehaviour <KoiClothesOverlayController>(GUID);
     KoiClothesOverlayController.Hooks.Init(GUID);
 }
Example #10
0
 void Awake()
 {
     instance = this;
 }
Example #11
0
 private void Awake()
 {
     CharacterApi.RegisterExtraBehaviour <CharaController>(GUID);
     StudioSaveLoadApi.RegisterExtraBehaviour <SceneController>(GUID);
     SceneManager.sceneLoaded += OnSceneLoaded;
 }
Example #12
0
        private void Start()
        {
            CharacterApi.RegisterExtraBehaviour <MaterialRouterController>(GUID);

            HooksInstance = Harmony.CreateAndPatchAll(typeof(Hooks));

            BepInEx.Bootstrap.Chainloader.PluginInfos.TryGetValue("com.deathweasel.bepinex.materialeditor", out PluginInfo PluginInfo);
            Type MaterialEditorCharaController = PluginInfo.Instance.GetType().Assembly.GetType("KK_Plugins.MaterialEditor.MaterialEditorCharaController");

            HooksInstance.Patch(MaterialEditorCharaController.GetMethod("OnReload", AccessTools.all, null, new[] { typeof(GameMode), typeof(bool) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialEditorCharaController_OnReload_Prefix)));
            HooksInstance.Patch(MaterialEditorCharaController.GetMethod("OnCoordinateBeingLoaded", AccessTools.all, null, new[] { typeof(ChaFileCoordinate), typeof(bool) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialEditorCharaController_OnCoordinateBeingLoaded_Prefix)));
            HooksInstance.Patch(MaterialEditorCharaController.GetMethod("CorrectTongue", AccessTools.all, null, new Type[0], null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialEditorCharaController_CorrectTongue_Prefix)));
            Type MaterialEditorMaterialAPI = PluginInfo.Instance.GetType().Assembly.GetType("MaterialEditorAPI.MaterialAPI");

            if (MaterialEditorMaterialAPI.GetMethods().Single(x => x.Name == "SetTexture").GetParameters().ElementAtOrDefault(3)?.ParameterType == typeof(Texture))
            {
                HooksInstance.Patch(MaterialEditorMaterialAPI.GetMethod("SetTexture", AccessTools.all, null, new[] { typeof(GameObject), typeof(string), typeof(string), typeof(Texture) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialAPI_SetTexture_Prefix)));
            }
            else
            {
                HooksInstance.Patch(MaterialEditorMaterialAPI.GetMethod("SetTexture", AccessTools.all, null, new[] { typeof(GameObject), typeof(string), typeof(string), typeof(Texture2D) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialAPI_SetTexture_Prefix)));
            }

            MakerAPI.MakerBaseLoaded += (object sender, RegisterCustomControlsEvent ev) =>
            {
                HooksMakerInstance = Harmony.CreateAndPatchAll(typeof(HooksMaker));
            };

            MakerAPI.MakerFinishedLoading += (object sender, EventArgs ev) =>
            {
                btmGetTemplate.Visible.OnNext(false);
                btmImportSetting.Visible.OnNext(false);
                btmRemoveSetting.Visible.OnNext(false);
            };

            AccessoriesApi.SelectedMakerAccSlotChanged += (object sender, AccessorySlotEventArgs ev) =>
            {
                InitCurrentSlot();
            };

            MakerAPI.MakerExiting += (object sender, EventArgs ev) =>
            {
                HooksMakerInstance.UnpatchAll(HooksMakerInstance.Id);
                HooksMakerInstance = null;
            };

            AccessoriesApi.AccessoryTransferred += (object sender, AccessoryTransferEventArgs ev) =>
            {
                MaterialRouterController pluginCtrl = GetController(MakerAPI.GetCharacterControl());
                pluginCtrl.AccessoryTransferEvent(ev);
            };

            AccessoriesApi.AccessoriesCopied += (object sender, AccessoryCopyEventArgs ev) =>
            {
                MaterialRouterController pluginCtrl = GetController(MakerAPI.GetCharacterControl());
                pluginCtrl.AccessoryCopyEvent(ev);
            };

            MakerAPI.RegisterCustomSubCategories += (object sender, RegisterSubCategoriesEvent ev) =>
            {
                ChaControl chaCtrl = MakerAPI.GetCharacterControl();
                MaterialRouterController pluginCtrl = GetController(chaCtrl);

                MakerCategory category = new MakerCategory("05_ParameterTop", "tglMaterialRouter", MakerConstants.Parameter.Attribute.Position + 1, "Router");
                ev.AddSubCategory(category);

                ev.AddControl(new MakerText("BodyTrigger", category, this));

                ev.AddControl(new MakerButton("Export", category, this)).OnClick.AddListener(delegate { pluginCtrl.ExportBodyTrigger(); });
                ev.AddControl(new MakerButton("Import", category, this)).OnClick.AddListener(delegate { pluginCtrl.ImportBodyTrigger(); });
                ev.AddControl(new MakerButton("Reset", category, this)).OnClick.AddListener(delegate { pluginCtrl.ResetBodyTrigger(); });

                ev.AddControl(new MakerSeparator(category, this));

                ev.AddControl(new MakerText("OutfitTriggers", category, this));

                ev.AddControl(new MakerButton("Export", category, this)).OnClick.AddListener(delegate { pluginCtrl.ExportOutfitTrigger(); });
                ev.AddControl(new MakerButton("Import", category, this)).OnClick.AddListener(delegate { pluginCtrl.ImportOutfitTrigger(); });
                ev.AddControl(new MakerButton("Reset", category, this)).OnClick.AddListener(delegate { pluginCtrl.ResetOutfitTrigger(); });

                ev.AddControl(new MakerSeparator(category, this));

                ev.AddControl(new MakerText("Config", category, this));

                tglSkipCloned = ev.AddControl(new MakerToggle(category, "Get Template Skip Cloned", CfgSkipCloned.Value, this));
                tglSkipCloned.ValueChanged.Subscribe(value => CfgSkipCloned.Value = value);

                ev.AddControl(new MakerSeparator(category, this));

                ev.AddControl(new MakerText("Tools", category, this));

                ev.AddControl(new MakerButton("Reload", category, Instance)).OnClick.AddListener(delegate
                {
                    string CardPath = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Paths.ExecutablePath) + "_MaterialRouter.png");
                    chaCtrl.chaFile.SaveCharaFile(CardPath, byte.MaxValue, false);

                    chaCtrl.chaFile.LoadFileLimited(CardPath);
                    if (chaCtrl.chaFile.GetLastErrorCode() != 0)
                    {
                        throw new Exception("LoadFileLimited failed");
                    }
                    chaCtrl.ChangeCoordinateType(true);
                    chaCtrl.Reload();
                    CustomBase.Instance.updateCustomUI = true;
                });

                ev.AddControl(new MakerButton("Info", category, Instance)).OnClick.AddListener(delegate
                {
                    Logger.LogInfo($"[BodyTrigger][{pluginCtrl?.BodyTrigger?.Count}]");
                    for (int i = 0; i < chaCtrl.chaFile.coordinate.Length; i++)
                    {
                        Logger.LogInfo($"[OutfitTriggers][{i}][{pluginCtrl?.OutfitTriggers?[i].Count}]");
                    }
                });

                ev.AddControl(new MakerButton("Head Get Template", MakerConstants.Face.All, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHead, true));
                ev.AddControl(new MakerButton("Body Get Template", MakerConstants.Face.All, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objBody, true));

                const string labelConsolePrint    = "Console Output";
                const string labelGenerateSetting = "Generate Setting";
                const string labelRemoveSetting   = "Remove Setting";

                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Top, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[0]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Bottom, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[1]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Bra, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[2]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Shorts, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[3]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Gloves, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[4]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Panst, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[5]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Socks, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[6]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.InnerShoes, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[7]));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.OuterShoes, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[8]));

                btmGetTemplate = MakerAPI.AddAccessoryWindowControl(new MakerButton(labelConsolePrint, null, this));
                btmGetTemplate.OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.GetAccessoryObject(AccessoriesApi.SelectedMakerAccSlot)));
                btmImportSetting = MakerAPI.AddAccessoryWindowControl(new MakerButton(labelGenerateSetting, null, this));
                btmImportSetting.OnClick.AddListener(() => pluginCtrl.ImportFromRendererInfo(AccessoriesApi.SelectedMakerAccSlot));
                btmRemoveSetting = MakerAPI.AddAccessoryWindowControl(new MakerButton(labelRemoveSetting, null, this));
                btmRemoveSetting.OnClick.AddListener(() => pluginCtrl.RemoveAccSlotInfo(AccessoriesApi.SelectedMakerAccSlot));

                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Back, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[0], true));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Front, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[1], true));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Side, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[2], true));
                ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Extension, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[3], true));
            };
        }