internal void UpdateCurrentCardTranslationMode() { var origMode = CurrentCardLoadTranslationMode; if (StudioAPI.InsideStudio) { CurrentCardLoadTranslationMode = StudioTranslateCardNameOnLoad?.Value ?? CardLoadTranslationMode.Disabled; CurrentGameMode = GameMode.Studio; } else if (MakerAPI.InsideMaker) { CurrentCardLoadTranslationMode = MakerTranslateCardNameOnLoad?.Value ?? CardLoadTranslationMode.Disabled; CurrentGameMode = GameMode.Maker; } else { CurrentGameMode = KoikatuAPI.GetCurrentGameMode(); if (CurrentGameMode == GameMode.MainGame) { CurrentCardLoadTranslationMode = GameTranslateCardNameOnLoad?.Value ?? CardLoadTranslationMode.Disabled; } else { CurrentCardLoadTranslationMode = CardLoadTranslationMode.Disabled; } } Logger.LogDebug($"UpdateCurrentCardTranslationMode: {origMode} => {CurrentCardLoadTranslationMode}"); }
private ChaFile GetExtDataTargetChaFile(bool setDirty) { #if KK || KKS // In main game store ext data for the character inside of the main chaFile object (the one that gets saved to game saves) instead of its copies. // This allows saving ext data inside talk scenes and H scenes without losing it after exiting to main map. if (KoikatuAPI.GetCurrentGameMode() == GameMode.MainGame) { var heroine = ChaControl.GetHeroine(); if (heroine != null) { if (setDirty) { CharacterApi.Hooks.SetDirty(heroine, true); } return(heroine.charFile); } var player = ChaControl.GetPlayer(); if (player != null) { if (setDirty) { CharacterApi.Hooks.SetDirty(player, true); } return(player.charFile); } } #endif return(ChaFileControl); }
public static bool GetFileNamePatch(ref string __result, string path) { // Should only work during main game var gmode = KoikatuAPI.GetCurrentGameMode(); if (gmode != GameMode.MainGame && gmode != GameMode.Maker) { return(true); } try { if (File.Exists(UserData.Path + "chara/female/" + path)) { __result = path; return(false); } var lookedAtPath = new Uri(path); var basePathForChara = new Uri(UserData.Path + "chara/female/"); if (basePathForChara.IsBaseOf(lookedAtPath)) { __result = MainGameFolders.GetRelativePath(path, UserData.Path + "chara/female/"); return(false); } return(true); } catch { return(true); } }
public void UpdateHover() { if (KoikatuAPI.GetCurrentGameMode() != GameMode.Studio) { if (!isShoeActive || currentConfig == null || !GroundAnim) { DisableHover(); } else { EnableHover(); } } else { if (!isShoeActive || currentConfig == null) { DisableHover(); } else { EnableHover(); } } }
public static bool ConvertCharaFilePath(ref ChaFileControl __instance, ref string __result, string path) { // Should only work during main game var gmode = KoikatuAPI.GetCurrentGameMode(); if (gmode != GameMode.MainGame && gmode != GameMode.Maker) { return(true); } if (path == null) { return(true); } if (!path.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { path += ".png"; } if (File.Exists(path)) { __result = path; return(false); } if (File.Exists(UserData.Path + "chara/female/" + path)) { __result = UserData.Path + "chara/female/" + path; return(false); } return(true); }
/// <summary> /// Save your custom data to the character card under the ID you specified when registering this controller. /// This should be used inside the <see cref="OnCardBeingSaved"/> event. /// Consider using one of the other "Get___ExtData" and "Set___ExtData" methods instead since they are more reliable and handle copying and transferring outfits and they conform to built in maker load toggles. /// </summary> /// <param name="data">Your custom data to be written to the character card. Can be null to remove the data.</param> public void SetExtendedData(PluginData data) { if (ExtendedDataId == null) { throw new ArgumentException(nameof(ExtendedDataId)); } ExtendedSave.SetExtendedDataById(ChaFileControl, ExtendedDataId, data); #if KK //todo || KKS // Needed for propagating changes back to the original charFile since they don't get copied back. var heroine = ChaControl.GetHeroine(); if (heroine != null) { ExtendedSave.SetExtendedDataById(heroine.charFile, ExtendedDataId, data); if (ChaControl != heroine.chaCtrl) { ExtendedSave.SetExtendedDataById(heroine.chaCtrl.chaFile, ExtendedDataId, data); // Update other instance to reflect the new ext data var other = heroine.chaCtrl.GetComponent(GetType()) as CharaCustomFunctionController; if (other != null) { other.OnReloadInternal(KoikatuAPI.GetCurrentGameMode()); } } var npc = heroine.GetNPC(); if (npc != null && npc.chaCtrl != null && npc.chaCtrl != ChaControl) { ExtendedSave.SetExtendedDataById(npc.chaCtrl.chaFile, ExtendedDataId, data); // Update other instance to reflect the new ext data var other = npc.chaCtrl.GetComponent(GetType()) as CharaCustomFunctionController; if (other != null) { other.OnReloadInternal(KoikatuAPI.GetCurrentGameMode()); } } } var player = ChaControl.GetPlayer(); if (player != null) { ExtendedSave.SetExtendedDataById(player.charFile, ExtendedDataId, data); if (ChaControl != player.chaCtrl) { ExtendedSave.SetExtendedDataById(player.chaCtrl.chaFile, ExtendedDataId, data); // Update other instance to reflect the new ext data var other = player.chaCtrl.GetComponent(GetType()) as CharaCustomFunctionController; if (other != null) { other.OnReloadInternal(KoikatuAPI.GetCurrentGameMode()); } } } #endif }
private void LateUpdate() { if (NeedsFullRefresh) { OnReload(KoikatuAPI.GetCurrentGameMode(), true); NeedsFullRefresh = false; return; } if (_baselineKnown == true) { if (NeedsBaselineUpdate) { UpdateBaseline(); } foreach (var modifier in Modifiers) { var additionalModifiers = _additionalBoneEffects .Select(x => x.GetEffect(modifier.BoneName, this, CurrentCoordinate.Value)) .Where(x => x != null) .ToList(); modifier.Apply(CurrentCoordinate.Value, additionalModifiers, _isDuringHScene); } } else if (_baselineKnown == false) { _baselineKnown = null; CollectBaseline(); } NeedsBaselineUpdate = false; }
private void LateUpdate() { if (NeedsFullRefresh) { OnReload(KoikatuAPI.GetCurrentGameMode(), true); NeedsFullRefresh = false; return; } if (_baselineKnown == true) { if (NeedsBaselineUpdate) { UpdateBaseline(); } ApplyEffects(); } else if (_baselineKnown == false) { _baselineKnown = null; CollectBaseline(); } NeedsBaselineUpdate = false; }
private void Start() { EnableBld = new ConfigWrapper <bool>(nameof(EnableBld), this, true); EnableBldAlways = new ConfigWrapper <bool>(nameof(EnableBldAlways), this, false); EnableCum = new ConfigWrapper <bool>(nameof(EnableCum), this, true); EnableSwt = new ConfigWrapper <bool>(nameof(EnableSwt), this, true); EnableTear = new ConfigWrapper <bool>(nameof(EnableTear), this, true); EnableDrl = new ConfigWrapper <bool>(nameof(EnableDrl), this, true); EnablePersistance = new ConfigWrapper <bool>(nameof(EnablePersistance), this, true); Hooks.InstallHook(); CharacterApi.RegisterExtraBehaviour <SkinEffectsController>(GUID); GameAPI.RegisterExtraBehaviour <SkinEffectGameController>(GUID); SkinEffectsGui.Init(this); if (KoikatuAPI.GetCurrentGameMode() != GameMode.Studio) { SceneManager.sceneLoaded += (arg0, mode) => { // Preload effects for H scene in case they didn't get loaded yet to prevent freeze on first effect appearing if (arg0.name == "H") { TextureLoader.InitializeTextures(); } }; } }
private void LateUpdate() { if (NeedsFullRefresh) { OnReload(KoikatuAPI.GetCurrentGameMode(), true); NeedsFullRefresh = false; return; } if (_baselineKnown == true) { if (NeedsBaselineUpdate) { UpdateBaseline(); } foreach (var modifier in Modifiers) { modifier.Apply(CurrentCoordinate.Value); } } else if (_baselineKnown == false) { _baselineKnown = null; StartCoroutine(CollectBaselineCo()); } NeedsBaselineUpdate = false; }
/// <summary> /// Warning: When overriding make sure to call the base method at the end of your logic! /// </summary> protected virtual void OnEnable() { // Order is Awake - OnEnable - Start, so need to check if we started yet if (Started) { OnReloadInternal(KoikatuAPI.GetCurrentGameMode()); } }
private static void ChaControl_ChangeSettingEyelineUp(ChaControl __instance) { //Only care about maker and studio, other modes have problems that aren't worth the effort if (KoikatuAPI.GetCurrentGameMode() == GameMode.MainGame) { return; } EyebrowFix.SetEyeliners(__instance, __instance.chaFile.custom.face.foregroundEyes); }
internal static void ChaFile_SaveFile_Postfix(ChaFile __instance) { // ReSharper disable once UseNullPropagation if (__instance == null) { return; } __instance.GetTranslationHelperController() .SafeProcObject(c => c.OnCardSaveComplete(KoikatuAPI.GetCurrentGameMode())); }
internal static void TriggerHelperCoroutine() { //Only trigger if not already running, and in main game if (coroutineActive || KoikatuAPI.GetCurrentGameMode() != GameMode.MainGame) { return; } coroutineActive = true; pluginInstance.StartCoroutine(LoopEveryXSeconds()); }
private static void NotBraShortsOverride(ChaControl __instance, ref bool value) { if (__instance.GetCurrentCrest() == CrestType.liberated) { if (KoikatuAPI.GetCurrentGameMode() == GameMode.MainGame || GameAPI.InsideHScene) { // Force underwear to be off value = true; } } }
private static void OnCardBeingSaved(ChaFile chaFile) { KoikatuAPI.Log(LogLevel.Debug, "[KKAPI] Character save: " + chaFile.parameter.fullname); var gamemode = KoikatuAPI.GetCurrentGameMode(); foreach (var behaviour in GetBehaviours(MakerAPI.GetCharacterControl())) { behaviour.OnCardBeingSavedInternal(gamemode); } }
private static int GetCurrentMapNo() { if (KoikatuAPI.GetCurrentGameMode() != GameMode.MainGame) { return(-1); } if (!Game.IsInstance() || Game.Instance.actScene == null || Game.Instance.actScene.Map == null) { return(-1); } return(Game.Instance.actScene.Map.no); }
private IEnumerator Start() { yield return(new WaitUntil(() => { switch (KKAPI.KoikatuAPI.GetCurrentGameMode()) { case KKAPI.GameMode.Maker: return KKAPI.Maker.MakerAPI.InsideAndLoaded; case KKAPI.GameMode.Studio: return KKAPI.Studio.StudioAPI.StudioLoaded; case KKAPI.GameMode.MainGame: return null != GameObject.Find("MapScene") && SceneManager.GetActiveScene().isLoaded&& null != Camera.main; //KKAPI doesn't provide an api for in game check default: return false; } })); Settings = new GlobalSettings(); CameraSettings = new CameraSettings(); LightingSettings = new LightingSettings(); PostProcessingSettings = new PostProcessingSettings(CameraSettings.MainCamera); _skyboxManager = Instance.GetOrAddComponent <SkyboxManager>(); _skyboxManager.Parent = this; _skyboxManager.AssetPath = ConfigCubeMapPath.Value; _skyboxManager.Logger = Logger; DontDestroyOnLoad(_skyboxManager); _postProcessingManager = Instance.GetOrAddComponent <PostProcessingManager>(); _postProcessingManager.Parent = this; _postProcessingManager.LensDirtTexturesPath = ConfigLensDirtPath.Value; DontDestroyOnLoad(_postProcessingManager); _lightManager = new LightManager(this); _focusPuller = Instance.GetOrAddComponent <FocusPuller>(); _focusPuller.init(this); DontDestroyOnLoad(_focusPuller); _presetManager = new PresetManager(ConfigPresetPath.Value, this); _inspector = new Inspector.Inspector(this); // It takes some time to fully loaded in studio to save/load stuffs. yield return(new WaitUntil(() => { return (KoikatuAPI.GetCurrentGameMode() == GameMode.Studio) ? KKAPI.Studio.StudioAPI.InsideStudio && _skyboxManager != null : true; })); _isLoaded = true; }
private static void ChaFile_SaveFile_Postfix(ChaFile __instance) { try { __instance.SafeProc(i => i.GetTranslationHelperController() .SafeProc(c => c.OnCardSaveComplete(KoikatuAPI.GetCurrentGameMode()))); } catch (Exception err) { Logger.LogException(err, nameof(ChaFile_SaveFile_Postfix)); } }
private static void ReloadChara(ChaControl chaControl = null) { if (IsCurrentlyReloading(chaControl)) { return; } if (chaControl == null) { _currentlyReloading.UnionWith(ChaControls); } else { _currentlyReloading.Add(chaControl); } KoikatuAPI.Logger.LogDebug("Character load/reload: " + GetLogName(chaControl)); // Always send events to controllers before subscribers of CharacterReloaded var gamemode = KoikatuAPI.GetCurrentGameMode(); foreach (var behaviour in GetBehaviours(chaControl)) { behaviour.OnReloadInternal(gamemode); } var args = new CharaReloadEventArgs(chaControl); try { CharacterReloaded?.Invoke(null, args); } catch (Exception e) { KoikatuAPI.Logger.LogError(e); } if (MakerAPI.InsideAndLoaded) { MakerAPI.OnReloadInterface(args); } if (chaControl == null) { _currentlyReloading.Clear(); } else { _currentlyReloading.Remove(chaControl); } }
/// <summary> /// Save your custom data to the character card under the ID you specified when registering this controller. /// This should be used inside the <see cref="OnCardBeingSaved"/> event. /// Consider using one of the other "Get___ExtData" and "Set___ExtData" methods instead since they are more reliable and handle copying and transferring outfits and they conform to built in maker load toggles. /// </summary> /// <param name="data">Your custom data to be written to the character card. Can be null to remove the data.</param> public void SetExtendedData(PluginData data) { if (ExtendedDataId == null) { throw new ArgumentException(nameof(ExtendedDataId)); } ExtendedSave.SetExtendedDataById(ChaFileControl, ExtendedDataId, data); #if KK || KKS if (KoikatuAPI.GetCurrentGameMode() == GameMode.MainGame) { // In main game store ext data for the character inside of the main chaFile object (the one that gets saved to game saves). // This allows saving ext data inside talk scenes and H scenes without losing it after exiting to main map. var heroine = ChaControl.GetHeroine(); if (heroine != null) { ExtendedSave.SetExtendedDataById(heroine.charFile, ExtendedDataId, data); if (ChaControl != heroine.chaCtrl) { ExtendedSave.SetExtendedDataById(heroine.chaCtrl.chaFile, ExtendedDataId, data); // Update other instance to reflect the new ext data CharacterApi.Hooks.SetDirty(heroine, true); } var npc = heroine.GetNPC(); if (npc != null && npc.chaCtrl != null && npc.chaCtrl != ChaControl && npc.chaCtrl != heroine.chaCtrl) { ExtendedSave.SetExtendedDataById(npc.chaCtrl.chaFile, ExtendedDataId, data); // Update other instance to reflect the new ext data CharacterApi.Hooks.SetDirty(heroine, true); } } else { var player = ChaControl.GetPlayer(); if (player != null) { ExtendedSave.SetExtendedDataById(player.charFile, ExtendedDataId, data); if (ChaControl != player.chaCtrl) { ExtendedSave.SetExtendedDataById(player.chaCtrl.chaFile, ExtendedDataId, data); // Update other instance to reflect the new ext data CharacterApi.Hooks.SetDirty(player, true); } } } } #endif }
protected override void Start() { if (KoikatuAPI.GetCurrentGameMode() == GameMode.MainGame) { return; } HairAccessoryCustomizer = new HairAccessoryCustomizerSupport.UrineBag(ChaControl); MaterialEditor = new MaterialEditorSupport.UrineBag(ChaControl); MaterialRouter = new MaterialRouterSupport.UrineBag(ChaControl); AccStateSync = new AccStateSyncSupport.UrineBag(ChaControl); DynamicBoneEditor = new DynamicBoneEditorSupport.UrineBag(ChaControl); CurrentCoordinate.Subscribe(value => { OnCoordinateChanged(); }); base.Start(); }
public void RefreshTexture(string texType) { if (texType != null && KoikatuAPI.GetCurrentGameMode() != GameMode.Studio) { var i = Array.FindIndex(ChaControl.objClothes, x => x != null && x.name == texType); if (i >= 0) { ChaControl.ChangeCustomClothes(i, true, false, false, false); return; } } // Fall back if the specific tex couldn't be refreshed RefreshAllTextures(); }
private static void OnCardBeingSaved(ChaFile chaFile) { KoikatuAPI.Logger.LogDebug("Character save: " + chaFile.parameter.fullname); var gamemode = KoikatuAPI.GetCurrentGameMode(); var chaControl = gamemode == GameMode.Maker ? MakerAPI.GetCharacterControl() : ChaControls.FirstOrDefault(control => control.chaFile == chaFile); foreach (var behaviour in GetBehaviours(chaControl)) { behaviour.OnCardBeingSavedInternal(gamemode); } }
public CoroutineLimiter(long limit, string limiterName, bool resetOnSceneTransition = false) { Limit = limit; _limiterName = limiterName; _waitUntilBelowLimit = new WaitUntil(IsBelowLimit); if (resetOnSceneTransition) { SceneManager.activeSceneChanged += ActiveSceneChanged; } if (KoikatuAPI.GetCurrentGameMode() == GameMode.Studio) { StudioSaveLoadApi.SceneLoad += StudioSaveLoadApi_SceneLoad; } Reset(); }
private bool IsLoaded() { switch (KoikatuAPI.GetCurrentGameMode()) { case GameMode.Maker: return(KKAPI.Maker.MakerAPI.InsideAndLoaded); case GameMode.Studio: return(KKAPI.Studio.StudioAPI.StudioLoaded); case GameMode.MainGame: return("MyRoom" == SceneManager.GetActiveScene().name&& SceneManager.GetActiveScene().isLoaded&& null != Camera.main); //HS2API doesn't provide an api for in game check default: return(false); } }
//Got tired of searching for the correct hooks, just check for new dynamic bones on a loop. Genious! internal static IEnumerator LoopEveryXSeconds() { while (coroutineActive) { //If not in the main game, continue if (KoikatuAPI.GetCurrentGameMode() != GameMode.MainGame) { yield return(new WaitForSeconds(3)); } VRControllerCollider.SetVRControllerColliderToDynamicBones(); // VRPlugin.Logger.Log(LogLevel.Info, $"Camera distance {distance}"); yield return(new WaitForSeconds(3)); } }
private static void ReloadChara(Human chaControl = null) { if (IsCurrentlyReloading(chaControl)) { return; } if (chaControl == null) { _currentlyReloading.UnionWith(ChaControls); } else { _currentlyReloading.Add(chaControl); } KoikatuAPI.Logger.LogDebug("Character load/reload"); // Always send events to controllers before subscribers of CharacterReloaded var gamemode = KoikatuAPI.GetCurrentGameMode(); foreach (var behaviour in GetBehaviours(chaControl)) { behaviour.OnReloadInternal(gamemode); } OnCharacterReload(chaControl); if (MakerAPI.InsideAndLoaded) { MakerAPI.OnReloadInterface(new CharaReloadEventArgs(chaControl)); } if (chaControl == null) { _currentlyReloading.Clear(); Hooks.LastLoadedCardPaths.Clear(); } else { _currentlyReloading.Remove(chaControl); Hooks.LastLoadedCardPaths[chaControl] = null; } }
private void Start() { Instance = this; Logger = base.Logger; if (KoikatuAPI.GetCurrentGameMode() != GameMode.Studio) { XyzMode = Config.Wrap("Maker", Metadata.XyzModeName, Metadata.XyzModeDesc, false); RaiseLimits = Config.Wrap("Maker", Metadata.RaiseLimitsName, Metadata.RaiseLimitsDesc, false); XyzMode.SettingChanged += KKABMX_GUI.OnIsAdvancedModeChanged; var showAdv = Config.Wrap("Maker", "Show Advanced Bonemod Window", "", false); showAdv.SettingChanged += (sender, args) => gameObject.GetComponent <KKABMX_AdvancedGUI>().enabled = showAdv.Value; gameObject.AddComponent <KKABMX_GUI>(); } CharacterApi.RegisterExtraBehaviour <BoneController>(ExtDataGUID); Hooks.Init(); }
private IEnumerator Start() { yield return(new WaitUntil(() => { switch (KoikatuAPI.GetCurrentGameMode()) { case GameMode.Studio: return KKAPI.Studio.StudioAPI.StudioLoaded; case GameMode.Unknown: case GameMode.Maker: case GameMode.MainGame: return false; default: return false; } })); ConfigKey1 = Config.Bind("1. Roll", "Roll (clockwise)", new KeyboardShortcut(F4), new ConfigDescription("Keyboard shortcut to roll clockwise (right)")); ConfigKey2 = Config.Bind("2. Front/Back", "Front/Back", new KeyboardShortcut(F6), new ConfigDescription("Keyboard shortcut to rotate into front/back")); ConfigKey3 = Config.Bind("3. Side", "Side (clockwise)", new KeyboardShortcut(F7), new ConfigDescription("Keyboard shortcut to rotate to side in clockwise manner")); ConfigKeyC1 = Config.Bind("1. Roll", "Roll (counter-clockwise)", new KeyboardShortcut(F4, Ctrl), new ConfigDescription("Keyboard shortcut to roll counter-clockwise (left)")); ConfigKeyC3 = Config.Bind("3. Side", "Side (counter-clockwise)", new KeyboardShortcut(F7, Ctrl), new ConfigDescription("Keyboard shortcut to rotate to side in counter-clockwise manner")); RollAngle = Config.Bind("1. Roll", "Roll Angle", Key1Default, new ConfigDescription("Roll angle", new AcceptableValueRange <float>(Key1Min, Key1Max))); FrontBackAngle = Config.Bind("2. Front/Back", "Front/Back Angle (leave this be)", Key2Default, new ConfigDescription("No point adjusting this unless you don't want front/back", new AcceptableValueRange <float>(Key2Min, Key2Max))); SideAngle = Config.Bind("3. Side", "Side Angle", Key3Default, new ConfigDescription("Angle to rotate to side", new AcceptableValueRange <float>(Key3Min, Key3Max))); }