diff --git a/src/RealPOV.Core/RealPOVCore.cs b/src/RealPOV.Core/RealPOVCore.cs index d1a9e51..5d713df 100644 --- a/src/RealPOV.Core/RealPOVCore.cs +++ b/src/RealPOV.Core/RealPOVCore.cs @@ -28,14 +28,17 @@ public abstract class RealPOVCore : BaseUnityPlugin private static float backupFOV; private static float backupNearClip; + protected static float defaultViewOffset = 0.03f; + protected static float defaultFov = 70f; + protected virtual void Awake() { Logger = base.Logger; POVHotkey = Config.Bind(SECTION_HOTKEYS, "Toggle POV", new KeyboardShortcut(KeyCode.Backspace)); - DefaultFOV = Config.Bind(SECTION_GENERAL, "Default FOV", 70f, new ConfigDescription("", new AcceptableValueRange(20f, 120f))); + DefaultFOV = Config.Bind(SECTION_GENERAL, "Default FOV", defaultFov, new ConfigDescription("", new AcceptableValueRange(20f, 120f))); MouseSens = Config.Bind(SECTION_GENERAL, "Mouse sensitivity", 1f, new ConfigDescription("", new AcceptableValueRange(0.1f, 2f))); - ViewOffset = Config.Bind(SECTION_GENERAL, "View offset", 0.03f); + ViewOffset = Config.Bind(SECTION_GENERAL, "View offset", defaultViewOffset); } private void Update() diff --git a/src/RealPOV.Koikatu/RealPOV.cs b/src/RealPOV.Koikatu/RealPOV.cs index 910a922..6159776 100644 --- a/src/RealPOV.Koikatu/RealPOV.cs +++ b/src/RealPOV.Koikatu/RealPOV.cs @@ -4,6 +4,7 @@ using Studio; using System.Collections.Generic; using System.Linq; +using BepInEx.Configuration; using UnityEngine; using UnityEngine.SceneManagement; @@ -14,68 +15,93 @@ namespace RealPOV.Koikatu [BepInPlugin(GUID, PluginName, Version)] public class RealPOV : RealPOVCore { - public const string Version = "1.0.4." + BuildNumber.Version; + public const string Version = "1.1.0." + BuildNumber.Version; + + internal ConfigEntry HideHead { get; set; } private static int backupLayer; private static ChaControl currentChara; private static Queue charaQueue; - private bool isStudio = Paths.ProcessName == "CharaStudio"; + private readonly bool isStudio = Paths.ProcessName == "CharaStudio"; + private bool prevVisibleHeadAlways; + private HFlag hFlag; protected override void Awake() { + defaultFov = 90; + defaultViewOffset = 0.001f; base.Awake(); + + HideHead = Config.Bind(SECTION_GENERAL, "Hide character head", true, "Whene entering POV, hide the character's head. Prevents accessories and hair from obstructing the view."); + Harmony.CreateAndPatchAll(GetType()); - SceneManager.activeSceneChanged += (arg0, scene) => charaQueue = null; + SceneManager.sceneLoaded += (arg0, scene) => + { + hFlag = FindObjectOfType(); + charaQueue = null; + }; + SceneManager.sceneUnloaded += arg0 => charaQueue = null; } internal override void EnablePOV() { - - if(isStudio) + if (isStudio) { var selectedCharas = GuideObjectManager.Instance.selectObjectKey.Select(x => Studio.Studio.GetCtrlInfo(x) as OCIChar).Where(x => x != null).ToList(); - if(selectedCharas.Count > 0) + if (selectedCharas.Count > 0) currentChara = selectedCharas.First().charInfo; else Logger.LogMessage("Select a character in workspace to enter its POV"); } else { - void CreateQueue() + Queue CreateQueue() { - charaQueue = new Queue(); - foreach (ChaControl chara in FindObjectsOfType()) - charaQueue.Enqueue(chara); - if (charaQueue.Count > 0) + return new Queue(FindObjectsOfType()); + } + ChaControl GetCurrentChara() + { + for (int i = 0; i < charaQueue.Count; i++) { - currentChara = charaQueue.Dequeue(); - charaQueue.Enqueue(currentChara); + var chaControl = charaQueue.Dequeue(); + + // Remove destroyed + if (chaControl == null) + continue; + + // Rotate the queue + charaQueue.Enqueue(chaControl); + if (chaControl.sex == 0 && hFlag != null && (hFlag.mode == HFlag.EMode.aibu || hFlag.mode == HFlag.EMode.lesbian || hFlag.mode == HFlag.EMode.masturbation)) continue; + // Found a valid character, otherwise skip (needed for story mode H because roam mode characters are in the queue too, just disabled) + if (chaControl.objTop.activeInHierarchy) return chaControl; } + return null; } - currentChara = null; - if(charaQueue == null) - { - CreateQueue(); - } - else - { - while (charaQueue.Count > 0 && (currentChara = charaQueue.Dequeue()) == null) {} + if (charaQueue == null) charaQueue = CreateQueue(); - if (currentChara != null) - charaQueue.Enqueue(currentChara); - else - CreateQueue(); + currentChara = GetCurrentChara(); + if (currentChara == null) + { + charaQueue = CreateQueue(); + currentChara = GetCurrentChara(); } } - if(currentChara) + if (currentChara) { //foreach(var bone in currentChara.neckLookCtrl.neckLookScript.aBones) // bone.neckBone.rotation = new Quaternion(); + prevVisibleHeadAlways = currentChara.fileStatus.visibleHeadAlways; + if (HideHead.Value) currentChara.fileStatus.visibleHeadAlways = false; + GameCamera = Camera.main; + var cc = (MonoBehaviour)GameCamera.GetComponent() ?? GameCamera.GetComponent(); + if (cc) cc.enabled = false; + + LookRotation = currentChara.objHeadBone.transform.rotation.eulerAngles; base.EnablePOV(); @@ -86,16 +112,22 @@ void CreateQueue() internal override void DisablePOV() { + currentChara.fileStatus.visibleHeadAlways = prevVisibleHeadAlways; + + var cc = (MonoBehaviour)GameCamera.GetComponent() ?? GameCamera.GetComponent(); + if (cc) cc.enabled = true; + base.DisablePOV(); + GameCamera.gameObject.layer = backupLayer; } [HarmonyPrefix, HarmonyPatch(typeof(NeckLookControllerVer2), "LateUpdate")] private static bool ApplyRotation(NeckLookControllerVer2 __instance) { - if(POVEnabled) + if (POVEnabled) { - if(__instance.neckLookScript && currentChara.neckLookCtrl == __instance) + if (__instance.neckLookScript && currentChara.neckLookCtrl == __instance) { __instance.neckLookScript.aBones[0].neckBone.rotation = Quaternion.identity; __instance.neckLookScript.aBones[1].neckBone.rotation = Quaternion.identity;