From 6f4b85b967de687f33f42827191c49de30870865 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 8 Dec 2023 16:11:45 -0500 Subject: [PATCH] Show fish info popups when using the spyglass --- .../Patches/SpyglassHarvestablePOIPatches.cs | 14 ++ .../Patches/SpyglassMapStampPatches.cs | 40 ++++ .../Spyglass/Patches/SpyglassUIPatches.cs | 14 ++ .../Ability/Spyglass/SpyglassHarvestPOIUI.cs | 189 ++++++++++++++++++ DredgeVR/VRUI/VRUIManager.cs | 6 +- DredgeVR/mod_meta.json | 2 +- 6 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 DredgeVR/Ability/Spyglass/Patches/SpyglassHarvestablePOIPatches.cs create mode 100644 DredgeVR/Ability/Spyglass/Patches/SpyglassMapStampPatches.cs create mode 100644 DredgeVR/Ability/Spyglass/Patches/SpyglassUIPatches.cs create mode 100644 DredgeVR/Ability/Spyglass/SpyglassHarvestPOIUI.cs diff --git a/DredgeVR/Ability/Spyglass/Patches/SpyglassHarvestablePOIPatches.cs b/DredgeVR/Ability/Spyglass/Patches/SpyglassHarvestablePOIPatches.cs new file mode 100644 index 0000000..8aecd8d --- /dev/null +++ b/DredgeVR/Ability/Spyglass/Patches/SpyglassHarvestablePOIPatches.cs @@ -0,0 +1,14 @@ +using HarmonyLib; + +namespace DredgeVR.Ability.Spyglass.Patches; + +[HarmonyPatch(typeof(HarvestPOI))] +internal class SpyglassHarvestablePOIPatches +{ + [HarmonyPostfix] + [HarmonyPatch(nameof(HarvestPOI.Start))] + public static void HarvestPOI_Start(HarvestPOI __instance) + { + __instance.gameObject.AddComponent(); + } +} diff --git a/DredgeVR/Ability/Spyglass/Patches/SpyglassMapStampPatches.cs b/DredgeVR/Ability/Spyglass/Patches/SpyglassMapStampPatches.cs new file mode 100644 index 0000000..df70708 --- /dev/null +++ b/DredgeVR/Ability/Spyglass/Patches/SpyglassMapStampPatches.cs @@ -0,0 +1,40 @@ +using HarmonyLib; +using UnityEngine; + +namespace DredgeVR.Ability.Patches; + +// TODO + +/* +[HarmonyPatch(typeof(SpyglassMapStamp))] +public static class SpyglassMapStampPatches +{ + [HarmonyPrefix] + [HarmonyPatch(nameof(SpyglassMapStamp.LateUpdate))] + public static bool SpyglassMapStamp_LateUpdate(SpyglassMapStamp __instance) + { + // Normal method has these flat on the screen + // We keep them at their world position + + __instance.transform.position = __instance.worldPosition + Vector3.up; + + // Count them as viewable if within 100m + // TODO: Would probably be good to also actually check if they are in front of the player + __instance.isOnScreen = (__instance.transform.position - GameManager.Instance.Player.transform.position).magnitude < 100; + __instance.stampImage.enabled = __instance.isOnScreen; + __instance.distanceTextField.enabled = __instance.isOnScreen; + + if (__instance.isOnScreen) + { + __instance.timeUntilDistanceUpdate -= Time.deltaTime; + if (__instance.timeUntilDistanceUpdate < 0f) + { + __instance.timeUntilDistanceUpdate = __instance.timeBetweenDistanceUpdates; + __instance.UpdatePlayerDistance(); + } + } + + return false; + } +} +*/ diff --git a/DredgeVR/Ability/Spyglass/Patches/SpyglassUIPatches.cs b/DredgeVR/Ability/Spyglass/Patches/SpyglassUIPatches.cs new file mode 100644 index 0000000..1be293f --- /dev/null +++ b/DredgeVR/Ability/Spyglass/Patches/SpyglassUIPatches.cs @@ -0,0 +1,14 @@ +using HarmonyLib; + +namespace DredgeVR.Ability.Spyglass.Patches; + +[HarmonyPatch(typeof(SpyglassUI))] +public static class SpyglassUIPatches +{ + [HarmonyPostfix] + [HarmonyPatch(nameof(SpyglassUI.OnPlayerAbilityToggled))] + public static void SpyglassUI_OnPlayerAbilityToggled(SpyglassUI __instance) + { + __instance.crosshairContainer.SetActive(false); + } +} diff --git a/DredgeVR/Ability/Spyglass/SpyglassHarvestPOIUI.cs b/DredgeVR/Ability/Spyglass/SpyglassHarvestPOIUI.cs new file mode 100644 index 0000000..428a24f --- /dev/null +++ b/DredgeVR/Ability/Spyglass/SpyglassHarvestPOIUI.cs @@ -0,0 +1,189 @@ +using DredgeVR.Helpers; +using DredgeVR.VRCamera; +using UnityEngine; +using UnityEngine.Localization; +using UnityEngine.Localization.Components; +using UnityEngine.UI; +using Random = UnityEngine.Random; + +namespace DredgeVR.Ability.Spyglass; + +[RequireComponent(typeof(HarvestPOI))] +public class SpyglassHarvestPOIUI : MonoBehaviour +{ + private static GameObject _prefab; + + private HarvestPOI _harvestPOI; + private HarvestableItemData _firstHarvestableItem; + + private GameObject _container; + private LocalizeStringEvent _itemNameString; + // private TextMeshProUGUI _itemDistanceTextField; //Unused in SpyglassUI + private Image _itemImage; + private Image _invalidEquipmentImage; + private Sprite _hiddenItemSprite; + private HarvestableTypeTagUI _harvestableTypeTagUI; + private LocalizedString _obscuredString; + + private float _containerScale = 0.005f; + private bool _shouldShowContainer; + + private AbilityData _spyglassAbilityData; + private bool _usingSpyglass; + + private float _updateTimer; + public const float UPDATE_TIME = 1f; + + private void Awake() + { + GameEvents.Instance.OnPlayerAbilityToggled += this.OnPlayerAbilityToggled; + } + + private void OnDestroy() + { + GameEvents.Instance.OnPlayerAbilityToggled -= this.OnPlayerAbilityToggled; + } + + public void Start() + { + var spyglassUI = GameManager.Instance.UI.spyglassUI; + _spyglassAbilityData = spyglassUI.spyglassAbilityData; + + if (_prefab == null) + { + _prefab = GameObject.Instantiate(spyglassUI.container); + _prefab.SetActive(false); + // Needs to be worldspace + var canvas = _prefab.AddComponent(); + canvas.renderMode = RenderMode.WorldSpace; + GameObject.DontDestroyOnLoad(_prefab); + } + + _harvestPOI = GetComponent(); + + _container = GameObject.Instantiate(_prefab); + _container.SetParent(transform); + _container.transform.localPosition = Vector3.up; + _container.transform.localScale = Vector3.zero; + + // Grab all the components + _itemNameString = _container.transform.Find("Backplate/BackplateInner/NameText").GetComponent(); + _itemImage = _container.transform.Find("Backplate/BackplateInner/Image").GetComponent(); + _invalidEquipmentImage = _container.transform.Find("Backplate/BackplateInner/InvalidEquipmentImage").GetComponent(); + _hiddenItemSprite = spyglassUI.hiddenItemSprite; + _harvestableTypeTagUI = _container.transform.Find("Backplate/HarvestableTypeTag").GetComponent(); + _obscuredString = spyglassUI.obscuredString; + + _updateTimer = Random.Range(0, UPDATE_TIME); + } + + public void Update() + { + if (!_usingSpyglass) + { + return; + } + + // Spread out update checks + _updateTimer -= Time.deltaTime; + if (_updateTimer < 0) + { + _updateTimer += UPDATE_TIME; + CheckPlayerPosition(); + } + + // Lerp scale based on if active + var targetScale = _shouldShowContainer ? Vector3.one * _containerScale : Vector3.zero; + if (_container.transform.localScale != targetScale) + { + var t = Mathf.Clamp01(Mathf.InverseLerp(_shouldShowContainer ? 0f : _containerScale, targetScale.x, _container.transform.localScale.x) + Time.deltaTime); + _container.transform.localScale = Vector3.Slerp(_container.transform.localScale, targetScale, t); + + if (!_shouldShowContainer && _container.transform.localScale == Vector3.zero) + { + _container.SetActive(false); + } + } + } + + private void CheckPlayerPosition() + { + // Only show objects within a certain range + if ((GameManager.Instance.Player.transform.position - transform.position).magnitude < 60) + { + _shouldShowContainer = true; + + if (!_container.activeInHierarchy) + { + _container.SetActive(true); + } + + // First harvestable item can change + UpdateHarvestableItem(); + + if (_firstHarvestableItem == null) + { + _shouldShowContainer = false; + } + else + { + // TODO: Ideally we'd also check that you're looking towards it + GameManager.Instance.SaveData.SetHasSpiedHarvestCategory(_firstHarvestableItem.harvestableType, true); + GameManager.Instance.AchievementManager.EvaluateAchievement(DredgeAchievementId.ABILITY_SPYGLASS); + + // LookAt makes them backwards though + _container.transform.LookAt(VRCameraManager.VRPlayer.transform.position); + _container.transform.Rotate(Vector3.up, 180f); + } + } + else + { + _shouldShowContainer = false; + } + } + + private void UpdateHarvestableItem() + { + var currentFirstHarvestableItem = _harvestPOI.Harvestable.GetActiveFirstHarvestableItem(); + + if (_firstHarvestableItem != currentFirstHarvestableItem) + { + _firstHarvestableItem = currentFirstHarvestableItem; + + if (_firstHarvestableItem != null) + { + // Most of this is adapted from SpyglassUI which has a single focused UI for the harvestPOI you're looking at + if (GameManager.Instance.SaveData.GetCaughtCountById(_firstHarvestableItem.id) > 0) + { + _itemNameString.StringReference = _firstHarvestableItem.itemNameKey; + } + else + { + _itemNameString.StringReference = _obscuredString; + } + _itemNameString.StringReference.RefreshString(); + _itemImage.sprite = ((_firstHarvestableItem.itemSubtype == ItemSubtype.TRINKET) ? _hiddenItemSprite : _firstHarvestableItem.sprite); + _harvestableTypeTagUI.Init(_firstHarvestableItem.harvestableType); + _invalidEquipmentImage.gameObject.SetActive(!GameManager.Instance.PlayerStats.HarvestableTypes.Contains(_firstHarvestableItem.harvestableType)); + } + } + } + + private void OnPlayerAbilityToggled(AbilityData abilityData, bool enabled) + { + if (_spyglassAbilityData.name == abilityData.name) + { + _usingSpyglass = enabled; + if (enabled) + { + // Reset them when entering into spyglass + _shouldShowContainer = false; + _container.transform.localScale = Vector3.zero; + } + else + { + _container.SetActive(false); + } + } + } +} diff --git a/DredgeVR/VRUI/VRUIManager.cs b/DredgeVR/VRUI/VRUIManager.cs index 31b0be7..253ec70 100644 --- a/DredgeVR/VRUI/VRUIManager.cs +++ b/DredgeVR/VRUI/VRUIManager.cs @@ -101,6 +101,9 @@ private void OnSceneStart(string scene) private void MakeCanvasWorldSpace(Canvas canvas) { + // If already world space, skip over it + if (canvas.renderMode == RenderMode.WorldSpace) return; + canvas.renderMode = RenderMode.WorldSpace; canvas.worldCamera = VRInputModule.Instance.RaycastCamera; canvas.scaleFactor = 1f; @@ -189,11 +192,12 @@ private GameObject CreatePromptContainer(string name, Transform parent) private void OnGameSceneStart() { // Add a component to orient game UI relative to the player camera + // Ignore HarvestablePOIs foreach (var canvas in GameObject.FindObjectsOfType()) { // When finding objects of type make sure they are in the game scene, could be on Manager or DontDestroyOnLoad or whatever // Also ignore canvases that have parent canvases, since they will inherit their position - if (canvas.gameObject.scene.name == "Game" && canvas.isRootCanvas) + if (canvas.gameObject.scene.name == "Game" && canvas.isRootCanvas && canvas.transform.parent?.name != "HarvestPOIs") { canvas.gameObject.AddComponent(); } diff --git a/DredgeVR/mod_meta.json b/DredgeVR/mod_meta.json index c361a5e..7498c20 100644 --- a/DredgeVR/mod_meta.json +++ b/DredgeVR/mod_meta.json @@ -1,7 +1,7 @@ { "Name": "DredgeVR", "ModGUID": "xen.DredgeVR", - "Version": "0.3.0", + "Version": "0.3.1", "ModAssembly": "DredgeVR.dll", "MinWinchVersion": "0.3.0", "Entrypoint": "DredgeVR.Loader/Initialize",