using System; using System.Collections.Generic; using UnityEngine; using Interactions; namespace Core { /// /// Central registry for pickups and item slots. /// Mirrors the singleton pattern used by PuzzleManager. /// public class ItemManager : MonoBehaviour { private static ItemManager _instance; private static bool _isQuitting; public static ItemManager Instance { get { if (_instance == null && Application.isPlaying && !_isQuitting) { _instance = FindAnyObjectByType(); if (_instance == null) { var go = new GameObject("ItemManager"); _instance = go.AddComponent(); // DontDestroyOnLoad(go); } } return _instance; } } private readonly HashSet _pickups = new HashSet(); private readonly HashSet _itemSlots = new HashSet(); // Central events forwarded from registered pickups/slots // Broadcasts when any registered pickup was picked up (passes the picked item data) public event Action OnItemPickedUp; // Broadcasts when any registered ItemSlot reports a correct item slotted // Args: slot's itemData (the slot definition), then the slotted item data public event Action OnCorrectItemSlotted; void Awake() { _instance = this; } void Start() { // Subscribe to scene load completed so we can clear registrations when scenes change // Access Instance directly to ensure the service is initialized and we get the event hookup. SceneManagerService.Instance.SceneLoadCompleted += OnSceneLoadCompleted; } void OnDestroy() { // Unsubscribe from SceneManagerService if (SceneManagerService.Instance != null) SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted; // Ensure we clean up any subscriptions from registered items when the manager is destroyed ClearAllRegistrations(); } void OnApplicationQuit() { _isQuitting = true; } private void OnSceneLoadCompleted(string sceneName) { // Clear all registrations when a new scene is loaded, so no stale references persist ClearAllRegistrations(); } /// /// Unsubscribe all pickup/slot event handlers and clear registries and manager events. /// private void ClearAllRegistrations() { // Unsubscribe pickup handlers var pickupsCopy = new List(_pickups); foreach (var p in pickupsCopy) { if (p != null) p.OnItemPickedUp -= Pickup_OnItemPickedUp; } _pickups.Clear(); // Unsubscribe slot handlers var slotsCopy = new List(_itemSlots); foreach (var s in slotsCopy) { if (s != null) s.OnCorrectItemSlotted -= ItemSlot_OnCorrectItemSlotted; } _itemSlots.Clear(); // Clear manager-level event subscribers OnItemPickedUp = null; OnCorrectItemSlotted = null; } public void RegisterPickup(Pickup pickup) { if (pickup == null) return; // only subscribe if newly added to avoid duplicate subscriptions if (_pickups.Add(pickup)) { pickup.OnItemPickedUp += Pickup_OnItemPickedUp; } } public void UnregisterPickup(Pickup pickup) { if (pickup == null) return; if (_pickups.Remove(pickup)) { pickup.OnItemPickedUp -= Pickup_OnItemPickedUp; } } public void RegisterItemSlot(ItemSlot slot) { if (slot == null) return; if (_itemSlots.Add(slot)) { slot.OnCorrectItemSlotted += ItemSlot_OnCorrectItemSlotted; } } public void UnregisterItemSlot(ItemSlot slot) { if (slot == null) return; if (_itemSlots.Remove(slot)) { slot.OnCorrectItemSlotted -= ItemSlot_OnCorrectItemSlotted; } } // Handler that forwards pickup events private void Pickup_OnItemPickedUp(PickupItemData data) { OnItemPickedUp?.Invoke(data); } // Handler that forwards correct-slot events private void ItemSlot_OnCorrectItemSlotted(PickupItemData slotData, PickupItemData slottedItem) { OnCorrectItemSlotted?.Invoke(slotData, slottedItem); } /// /// Returns the current slot state for the given item data by searching registered slots. /// If the item is currently slotted in a slot, returns that slot's state; otherwise returns ItemSlotState.None. /// public ItemSlotState GetSlotStatusForItem(PickupItemData itemData) { if (itemData == null) return ItemSlotState.None; foreach (var slot in _itemSlots) { var slottedObj = slot.GetSlottedObject(); if (slottedObj == null) continue; var pickup = slottedObj.GetComponent(); if (pickup == null) continue; if (pickup.itemData == itemData) { return slot.CurrentSlottedState; } } return ItemSlotState.None; } public IEnumerable Pickups => _pickups; public IEnumerable ItemSlots => _itemSlots; } }