diff --git a/CustomNotes/Installers/CustomNotesGameInstaller.cs b/CustomNotes/Installers/CustomNotesGameInstaller.cs index 034e18a..5e10326 100644 --- a/CustomNotes/Installers/CustomNotesGameInstaller.cs +++ b/CustomNotes/Installers/CustomNotesGameInstaller.cs @@ -18,6 +18,7 @@ public override void InstallBindings() { Container.BindInterfacesAndSelfTo().AsSingle(); Container.Bind().To().AsSingle(); + Container.Bind().AsSingle(); } } } diff --git a/CustomNotes/Installers/CustomNotesMenuInstaller.cs b/CustomNotes/Installers/CustomNotesMenuInstaller.cs index 40028bf..1947658 100644 --- a/CustomNotes/Installers/CustomNotesMenuInstaller.cs +++ b/CustomNotes/Installers/CustomNotesMenuInstaller.cs @@ -16,7 +16,7 @@ public override void InstallBindings() Container.Bind().FromNewComponentAsViewController().AsSingle(); Container.Bind().FromNewComponentAsViewController().AsSingle(); Container.BindInterfacesAndSelfTo().AsSingle(); - Container.BindFlowCoordinator(); + Container.Bind().FromNewComponentOnNewGameObject(nameof(NotesFlowCoordinator)).AsSingle(); Container.BindInterfacesTo().AsSingle(); Container.BindInterfacesTo().AsSingle(); diff --git a/CustomNotes/Managers/CustomBombController.cs b/CustomNotes/Managers/CustomBombController.cs index ce4f497..2b85190 100644 --- a/CustomNotes/Managers/CustomBombController.cs +++ b/CustomNotes/Managers/CustomBombController.cs @@ -10,10 +10,12 @@ namespace CustomNotes.Managers internal class CustomBombController : MonoBehaviour, INoteControllerDidInitEvent { private PluginConfig _pluginConfig; + private CustomNoteManager.Flags _customNoteFlags; private CustomNote _customNote; private NoteMovement _noteMovement; private BombNoteController _bombNoteController; + private MeshRenderer _bombMeshRenderer; protected Transform bombMesh; protected GameObject fakeFirstPersonBombMesh; @@ -22,10 +24,15 @@ internal class CustomBombController : MonoBehaviour, INoteControllerDidInitEvent protected SiraPrefabContainer container; protected SiraPrefabContainer.Pool bombPool; + private bool _eventsRegistered = false; + [Inject] - internal void Init(PluginConfig pluginConfig, NoteAssetLoader noteAssetLoader, [InjectOptional(Id = "cn.bomb")] SiraPrefabContainer.Pool bombContainerPool) + internal void Init(PluginConfig pluginConfig, NoteAssetLoader noteAssetLoader, CustomNoteManager.Flags customNoteFlags, [InjectOptional(Id = "cn.bomb")] SiraPrefabContainer.Pool bombContainerPool) { _pluginConfig = pluginConfig; + _customNoteFlags = customNoteFlags; + + _customNote = noteAssetLoader.CustomNoteObjects[noteAssetLoader.SelectedNote]; bombPool = bombContainerPool; @@ -33,20 +40,28 @@ internal void Init(PluginConfig pluginConfig, NoteAssetLoader noteAssetLoader, [ _bombNoteController = GetComponent(); _noteMovement = GetComponent(); - if(bombPool != null) - { - _bombNoteController.didInitEvent.Add(this); - _noteMovement.noteDidFinishJumpEvent += DidFinish; - } + bombMesh = gameObject.transform.Find("Mesh"); - MeshRenderer bm = GetComponentInChildren(); + _bombMeshRenderer = GetComponentInChildren(); + + if (_customNoteFlags.ForceDisable) + { + return; + } + + SetupCustomBomb(); + } + + protected virtual void SetupCustomBomb() + { + DeOrRegisterEvents(true); - if ((_pluginConfig.HMDOnly || LayerUtils.HMDOverride)) + if (_pluginConfig.HMDOnly || LayerUtils.HMDOverride) { - if(bombPool == null) + if (bombPool == null) { // create fake bombs for Custom Notes without Custom Bombs fakeFirstPersonBombMesh = UnityEngine.Object.Instantiate(bombMesh.gameObject); @@ -56,26 +71,65 @@ internal void Init(PluginConfig pluginConfig, NoteAssetLoader noteAssetLoader, [ fakeFirstPersonBombMesh.transform.localScale = Vector3.one; fakeFirstPersonBombMesh.transform.localPosition = Vector3.zero; fakeFirstPersonBombMesh.transform.rotation = Quaternion.identity; - fakeFirstPersonBombMesh.layer = (int)LayerUtils.NoteLayer.FirstPerson; + fakeFirstPersonBombMesh.layer = (int) LayerUtils.NoteLayer.FirstPerson; } - } else if (bombPool != null) { - bm.enabled = false; + _bombMeshRenderer.enabled = false; } + } - + protected virtual void RevertToDefaultBomb() + { + DeOrRegisterEvents(false); + + if (fakeFirstPersonBombMesh != null) + { + fakeFirstPersonBombMesh.SetActive(false); + } + _bombMeshRenderer.enabled = true; + } + + protected virtual void DeOrRegisterEvents(bool register) + { + if (_eventsRegistered == register || bombPool == null) return; + + _eventsRegistered = register; + + if (register) + { + _bombNoteController.didInitEvent.Add(this); + _noteMovement.noteDidFinishJumpEvent += DidFinish; + return; + } + + if (_bombNoteController != null) + { + _bombNoteController.didInitEvent.Remove(this); + } + if (_noteMovement != null) + { + _noteMovement.noteDidFinishJumpEvent -= DidFinish; + } } private void DidFinish() { + if (_customNoteFlags.ForceDisable || container == null) return; + container.transform.SetParent(null); bombPool.Despawn(container); + container = null; } public void HandleNoteControllerDidInit(NoteController noteController) { + if(_customNoteFlags.ForceDisable) + { + RevertToDefaultBomb(); + return; + } SpawnThenParent(bombPool); } @@ -107,10 +161,7 @@ private void SpawnThenParent(SiraPrefabContainer.Pool bombModelPool) protected void OnDestroy() { - if (_bombNoteController != null) - { - _bombNoteController.didInitEvent.Remove(this); - } + DeOrRegisterEvents(false); Destroy(fakeFirstPersonBombMesh); } } diff --git a/CustomNotes/Managers/CustomNoteController.cs b/CustomNotes/Managers/CustomNoteController.cs index f95c76a..8eaded3 100644 --- a/CustomNotes/Managers/CustomNoteController.cs +++ b/CustomNotes/Managers/CustomNoteController.cs @@ -12,11 +12,13 @@ namespace CustomNotes.Managers public class CustomNoteController : MonoBehaviour, IColorable, INoteControllerNoteWasCutEvent, INoteControllerNoteWasMissedEvent, INoteControllerDidInitEvent { private PluginConfig _pluginConfig; + private CustomNoteManager.Flags _customNoteFlags; protected Transform noteCube; private CustomNote _customNote; private GameNoteController _gameNoteController; private CustomNoteColorNoteVisuals _customNoteColorNoteVisuals; + private MeshRenderer _noteMesh; protected GameObject activeNote; protected SiraPrefabContainer container; @@ -27,17 +29,22 @@ public class CustomNoteController : MonoBehaviour, IColorable, INoteControllerNo private SiraPrefabContainer.Pool _leftArrowNotePool; private SiraPrefabContainer.Pool _rightArrowNotePool; + private bool _eventsRegistered = false; + public Color Color => _customNoteColorNoteVisuals != null ? _customNoteColorNoteVisuals.noteColor : Color.white; [Inject] internal void Init(PluginConfig pluginConfig, NoteAssetLoader noteAssetLoader, + CustomNoteManager.Flags customNoteFlags, [Inject(Id = "cn.left.arrow")] SiraPrefabContainer.Pool leftArrowNotePool, [Inject(Id = "cn.right.arrow")] SiraPrefabContainer.Pool rightArrowNotePool, [InjectOptional(Id = "cn.left.dot")] SiraPrefabContainer.Pool leftDotNotePool, [InjectOptional(Id = "cn.right.dot")] SiraPrefabContainer.Pool rightDotNotePool) { _pluginConfig = pluginConfig; + _customNoteFlags = customNoteFlags; + _leftArrowNotePool = leftArrowNotePool; _rightArrowNotePool = rightArrowNotePool; @@ -49,22 +56,68 @@ internal void Init(PluginConfig pluginConfig, _gameNoteController = GetComponent(); _customNoteColorNoteVisuals = gameObject.AddComponent(); - _gameNoteController.didInitEvent.Add(this); - _gameNoteController.noteWasMissedEvent.Add(this); - _gameNoteController.noteWasCutEvent.Add(this); - _customNoteColorNoteVisuals.didInitEvent += Visuals_DidInit; - noteCube = _gameNoteController.gameObject.transform.Find("NoteCube"); - MeshRenderer noteMesh = GetComponentInChildren(); + _noteMesh = GetComponentInChildren(); + + if (_customNoteFlags.ShouldDisableCustomNote()) + { + // Don't set up if it's forcefully disabled or + // if Ghost Notes are enabled and this note is not part of the first set of notes + // (for late spawning notes when the pool has to be expanded) + return; + } + + SetupCustomNote(); + } + + protected virtual void SetupCustomNote() + { + DeOrRegisterEvents(true); + if (_pluginConfig.HMDOnly == false && LayerUtils.HMDOverride == false) { // only disable if custom notes display on both hmd and display - noteMesh.forceRenderingOff = true; + _noteMesh.forceRenderingOff = true; } else { - noteMesh.gameObject.layer = (int) LayerUtils.NoteLayer.ThirdPerson; + _noteMesh.gameObject.layer = (int) LayerUtils.NoteLayer.ThirdPerson; + } + } + + protected virtual void RevertToDefaultNote() + { + DeOrRegisterEvents(false); + + _noteMesh.forceRenderingOff = false; + _noteMesh.gameObject.layer = (int) LayerUtils.NoteLayer.Note; + } + + protected virtual void DeOrRegisterEvents(bool register) + { + if (_eventsRegistered == register) return; + + _eventsRegistered = register; + + if (register) + { + _gameNoteController.didInitEvent.Add(this); + _gameNoteController.noteWasMissedEvent.Add(this); + _gameNoteController.noteWasCutEvent.Add(this); + _customNoteColorNoteVisuals.didInitEvent += Visuals_DidInit; + return; + } + + if (_gameNoteController != null) + { + _gameNoteController.didInitEvent.Remove(this); + _gameNoteController.noteWasMissedEvent.Remove(this); + _gameNoteController.noteWasCutEvent.Remove(this); + } + if (_customNoteColorNoteVisuals != null) + { + _customNoteColorNoteVisuals.didInitEvent -= Visuals_DidInit; } } @@ -93,6 +146,11 @@ public void HandleNoteControllerNoteWasCut(NoteController nc, in NoteCutInfo _) public void HandleNoteControllerDidInit(NoteController noteController) { + if(_customNoteFlags.ShouldDisableCustomNote()) + { + RevertToDefaultNote(); + return; + } var data = noteController.noteData; SpawnThenParent(data.colorType == ColorType.ColorA ? data.cutDirection == NoteCutDirection.Any ? _leftDotNotePool : _leftArrowNotePool @@ -135,6 +193,10 @@ protected void SetActiveThenColor(GameObject note, Color color) private void Visuals_DidInit(ColorNoteVisuals visuals, NoteController noteController) { + if (_customNoteFlags.ShouldDisableCustomNote()) + { + return; + } SetActiveThenColor(activeNote, visuals.noteColor); // Hide certain parts of the default note which is not required if(_pluginConfig.HMDOnly == false && LayerUtils.HMDOverride == false) @@ -171,16 +233,7 @@ private void Visuals_DidInit(ColorNoteVisuals visuals, NoteController noteContro protected void OnDestroy() { - if (_gameNoteController != null) - { - _gameNoteController.didInitEvent.Remove(this); - _gameNoteController.noteWasMissedEvent.Remove(this); - _gameNoteController.noteWasCutEvent.Remove(this); - } - if (_customNoteColorNoteVisuals != null) - { - _customNoteColorNoteVisuals.didInitEvent -= Visuals_DidInit; - } + DeOrRegisterEvents(false); } public void SetColor(Color color) diff --git a/CustomNotes/Managers/CustomNoteManager.cs b/CustomNotes/Managers/CustomNoteManager.cs index 677b0e5..ea38e2b 100644 --- a/CustomNotes/Managers/CustomNoteManager.cs +++ b/CustomNotes/Managers/CustomNoteManager.cs @@ -6,6 +6,7 @@ using CustomNotes.Settings.Utilities; using IPA.Loader; using System.Linq; +using UnityEngine; namespace CustomNotes.Managers { @@ -17,10 +18,13 @@ internal class CustomNoteManager : IInitializable private readonly PluginConfig _pluginConfig; private readonly IDifficultyBeatmap _level; - internal CustomNoteManager([InjectOptional] Submission submission, NoteAssetLoader noteAssetLoader, GameplayCoreSceneSetupData gameplayCoreSceneSetupData, PluginConfig pluginConfig, IDifficultyBeatmap level) + public Flags _customNoteFlags { get; private set; } + + internal CustomNoteManager([InjectOptional] Submission submission, NoteAssetLoader noteAssetLoader, Flags customNoteFlags, GameplayCoreSceneSetupData gameplayCoreSceneSetupData, PluginConfig pluginConfig, IDifficultyBeatmap level) { _submission = submission; _noteAssetLoader = noteAssetLoader; + _customNoteFlags = customNoteFlags; _gameplayCoreSceneSetupData = gameplayCoreSceneSetupData; _pluginConfig = pluginConfig; _level = level; @@ -38,19 +42,86 @@ public void Initialize() if (_gameplayCoreSceneSetupData.gameplayModifiers.ghostNotes) { - _submission?.DisableScoreSubmission("Custom Notes", "Ghost Notes"); + if (_pluginConfig.DisableOnModifier) _customNoteFlags.GhostNotesEnabled = true; + else _submission?.DisableScoreSubmission("Custom Notes", "Ghost Notes"); } if (_gameplayCoreSceneSetupData.gameplayModifiers.disappearingArrows) { - _submission?.DisableScoreSubmission("Custom Notes", "Disappearing Arrows"); + if (_pluginConfig.DisableOnModifier) _customNoteFlags.ForceDisable = true; + else _submission?.DisableScoreSubmission("Custom Notes", "Disappearing Arrows"); } if (_gameplayCoreSceneSetupData.gameplayModifiers.smallCubes) { - _submission?.DisableScoreSubmission("Custom Notes", "Small Notes"); + if (_pluginConfig.DisableOnModifier) _customNoteFlags.ForceDisable = true; + else _submission?.DisableScoreSubmission("Custom Notes", "Small Notes"); } if (Utils.IsNoodleMap(_level)) { - _submission?.DisableScoreSubmission("Custom Notes", "Noodle Extensions"); + if (_pluginConfig.DisableOnNoodle) + { + _customNoteFlags.ForceDisable = true; + } + else + { + _submission?.DisableScoreSubmission("Custom Notes", "Noodle Extensions"); + } + } + } + } + + public class Flags + { + public event Action OnAnyFlagUpdate; + + public bool ShouldDisableCustomNote() + { + return ForceDisable + || (GhostNotesEnabled && !IsInFirstSet()); + } + + public bool IsInFirstSet() + { + if (FirstFrameCount == 0) + { + FirstFrameCount = Time.frameCount; + return true; + } + + if (FirstFrameCount != Time.frameCount) + { + return false; + } + + return true; + } + + private bool _forceDisable = false; + public bool ForceDisable { + get => _forceDisable; + set + { + _forceDisable = value; + OnAnyFlagUpdate?.Invoke(); + } + } + + private bool _ghostNotesEnabled = false; + public bool GhostNotesEnabled { + get => _ghostNotesEnabled; + set + { + _ghostNotesEnabled = value; + OnAnyFlagUpdate?.Invoke(); + } + } + + private int _firstFrameCount = 0; + public int FirstFrameCount { + get => _firstFrameCount; + set + { + _firstFrameCount = value; + OnAnyFlagUpdate?.Invoke(); } } } diff --git a/CustomNotes/Managers/GameCameraManager.cs b/CustomNotes/Managers/GameCameraManager.cs index 237e533..8c7798c 100644 --- a/CustomNotes/Managers/GameCameraManager.cs +++ b/CustomNotes/Managers/GameCameraManager.cs @@ -12,17 +12,25 @@ public class GameCameraManager : IInitializable, IDisposable public Camera MainCamera { get; private set; } = null; private PluginConfig _pluginConfig; + private CustomNoteManager.Flags _customNoteFlags; + private MainCamera _mainCamera; [Inject] - internal GameCameraManager(PluginConfig pluginConfig) + internal GameCameraManager(PluginConfig pluginConfig, CustomNoteManager.Flags customNoteFlags, MainCamera mainCamera) { _pluginConfig = pluginConfig; + _customNoteFlags = customNoteFlags; + _mainCamera = mainCamera; } public void Initialize() { Logger.log.Debug($"Initializing {nameof(GameCameraManager)}!"); - MainCamera = Camera.main; + _customNoteFlags.OnAnyFlagUpdate += _customNoteFlags_OnAnyFlagUpdate; + + // Awake() hasn't been called yet so _mainCamera.camera is still null + MainCamera = _mainCamera.GetComponent(); + if (_pluginConfig.HMDOnly || LayerUtils.HMDOverride) { LayerUtils.CreateWatermark(); @@ -30,10 +38,35 @@ public void Initialize() } } + private void _customNoteFlags_OnAnyFlagUpdate() + { + if(_customNoteFlags.ForceDisable || _customNoteFlags.GhostNotesEnabled) + { + SetWatermarkAndLayerActive(false); + return; + } + + SetWatermarkAndLayerActive(true); + } + + private void SetWatermarkAndLayerActive(bool active) + { + LayerUtils.SetWatermarkActive(active); + + if (active) + { + LayerUtils.SetCamera(MainCamera, LayerUtils.CameraView.FirstPerson); + return; + } + + LayerUtils.SetCamera(MainCamera, LayerUtils.CameraView.Default); + } + public void Dispose() { Logger.log.Debug($"Disposing {nameof(GameCameraManager)}!"); LayerUtils.DestroyWatermark(); + _customNoteFlags.OnAnyFlagUpdate -= _customNoteFlags_OnAnyFlagUpdate; if (_pluginConfig.HMDOnly || LayerUtils.HMDOverride) { LayerUtils.SetCamera(MainCamera, LayerUtils.CameraView.Default); diff --git a/CustomNotes/Plugin.cs b/CustomNotes/Plugin.cs index 36ee07c..e905cff 100644 --- a/CustomNotes/Plugin.cs +++ b/CustomNotes/Plugin.cs @@ -24,7 +24,7 @@ public Plugin(IPALogger logger, Config config, Zenjector zenjector) Logger.log = logger; zenjector.OnApp().WithParameters(config.Generated()); zenjector.OnMenu(); - zenjector.OnGame(false).ShortCircuitForTutorial(); + zenjector.OnGame(false).ShortCircuitForTutorial().Expose(); } [OnEnable] diff --git a/CustomNotes/Settings/UI/NoteDetailsViewController.cs b/CustomNotes/Settings/UI/NoteDetailsViewController.cs index 998cb00..17c596c 100644 --- a/CustomNotes/Settings/UI/NoteDetailsViewController.cs +++ b/CustomNotes/Settings/UI/NoteDetailsViewController.cs @@ -21,10 +21,16 @@ internal class NoteDetailsViewController : BSMLResourceViewController public TextPageScrollView noteDescription = null; [UIComponent("size-slider")] - private SliderSetting sizeSlider; + private SliderSetting sizeSlider = null; [UIComponent("hmd-checkbox")] - private ToggleSetting hmdCheckbox; + private ToggleSetting hmdCheckbox = null; + + [UIComponent("noodle-disable-checkbox")] + private ToggleSetting noodleDisableCheckbox = null; + + [UIComponent("modifier-disable-checkbox")] + private ToggleSetting modifierDisableCheckbox = null; public void OnNoteWasChanged(CustomNote customNote) { @@ -45,6 +51,14 @@ public void OnNoteWasChanged(CustomNote customNote) { hmdCheckbox.ReceiveValue(); } + if (noodleDisableCheckbox != null) + { + noodleDisableCheckbox.ReceiveValue(); + } + if (modifierDisableCheckbox != null) + { + modifierDisableCheckbox.ReceiveValue(); + } } [Inject] @@ -69,8 +83,21 @@ public float noteSize public bool hmdOnly { get { return _pluginConfig.HMDOnly; } - set - { _pluginConfig.HMDOnly = value; } + set { _pluginConfig.HMDOnly = value; } + } + + [UIValue("noodle-disable")] + public bool noodleDisable + { + get { return _pluginConfig.DisableOnNoodle; } + set { _pluginConfig.DisableOnNoodle = value; } + } + + [UIValue("modifier-disable")] + public bool modifierDisable + { + get { return _pluginConfig.DisableOnModifier; } + set { _pluginConfig.DisableOnModifier = value; } } } } diff --git a/CustomNotes/Settings/UI/NoteModifierViewController.cs b/CustomNotes/Settings/UI/NoteModifierViewController.cs index 7b52833..dbf540e 100644 --- a/CustomNotes/Settings/UI/NoteModifierViewController.cs +++ b/CustomNotes/Settings/UI/NoteModifierViewController.cs @@ -25,18 +25,18 @@ class NoteModifierViewController : IInitializable, IDisposable private List notesList = new List(); [UIComponent("notes-dropdown")] - private DropDownListSetting notesDropdown; + private DropDownListSetting notesDropdown = null; [UIComponent("notes-dropdown")] - private RectTransform notesDropdownTransform; + private RectTransform notesDropdownTransform = null; - private RectTransform dropdownListTransform; + private RectTransform dropdownListTransform = null; [UIComponent("size-slider")] - private SliderSetting sizeSlider; + private SliderSetting sizeSlider = null; [UIComponent("hmd-checkbox")] - private ToggleSetting hmdCheckbox; + private ToggleSetting hmdCheckbox = null; public NoteModifierViewController(PluginConfig pluginConfig, NoteAssetLoader noteAssetLoader) diff --git a/CustomNotes/Settings/UI/Views/noteDetails.bsml b/CustomNotes/Settings/UI/Views/noteDetails.bsml index ed6702d..a5c3669 100644 --- a/CustomNotes/Settings/UI/Views/noteDetails.bsml +++ b/CustomNotes/Settings/UI/Views/noteDetails.bsml @@ -1,4 +1,4 @@ - + @@ -13,6 +13,8 @@ + + diff --git a/CustomNotes/Settings/Utilities/PluginConfig.cs b/CustomNotes/Settings/Utilities/PluginConfig.cs index 2ede2ea..16d74dc 100644 --- a/CustomNotes/Settings/Utilities/PluginConfig.cs +++ b/CustomNotes/Settings/Utilities/PluginConfig.cs @@ -7,5 +7,9 @@ public class PluginConfig public virtual float NoteSize { get; set; } = 1; public virtual bool HMDOnly { get; set; } = false; + + public virtual bool DisableOnNoodle { get; set; } = true; + + public virtual bool DisableOnModifier { get; set; } = true; } } \ No newline at end of file diff --git a/CustomNotes/Utilities/LayerUtils.cs b/CustomNotes/Utilities/LayerUtils.cs index dce3ac6..b993cf3 100644 --- a/CustomNotes/Utilities/LayerUtils.cs +++ b/CustomNotes/Utilities/LayerUtils.cs @@ -122,13 +122,19 @@ public static void CreateWatermark() SetLayer(_watermarkObject, NoteLayer.ThirdPerson); } + public static void SetWatermarkActive(bool active = true) + { + if (_watermarkObject == null) return; + _watermarkObject.SetActive(active); + } + public static void DestroyWatermark() { if (_watermarkObject == null) return; _watermarkObject.SetActive(false); UnityEngine.Object.Destroy(_watermarkObject); _watermarkObject = null; - } + } /// /// Force custom notes to only be visible in-headset, regardless of the player's settings. diff --git a/CustomNotes/Utilities/Utils.cs b/CustomNotes/Utilities/Utils.cs index 865bf9c..3f669f1 100644 --- a/CustomNotes/Utilities/Utils.cs +++ b/CustomNotes/Utilities/Utils.cs @@ -7,6 +7,7 @@ using IPA.Utilities; using System; using CustomNotes.Settings.Utilities; +using System.Collections; namespace CustomNotes.Utilities {