inventory troubles

hello so tldr to keep items persistence in my project I’ve attached a dontdestroy script to them my problem arises from the fact I can pick one test item up in the room and it shows up the first inventory slot but as I go to the door and load a new scene turn around and go back to the item room and try picking the other test item up it does not show up in the 2nd inventory slot as intended I’ve don’t some debugging its not the pickup script but its the OnpickupItem function in my script

help would be appreciated as I have no clue on what to due

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.EventSystems;
using FMODUnity;

public class InventorySelectController : MonoBehaviour
{
  
  
   
   [SerializeField] private GameObject _inventoryView;
   [SerializeField] private TMP_Text _itemNameText;
   [SerializeField] private TMP_Text _itemDescriptionText;
   [SerializeField] private EventReference OpenInventorySound;
   [SerializeField] private EventReference CloseInventorySound;
   [SerializeField] private List<ItemSlot> _slots;

   [SerializeField] private Playermovement _Playermovement;
   [SerializeField] private ScreenFader _fader;

   private enum State
   {
   menuClosed,
   menuOpen,
   };
  
   private State _state;
  

   private void OnEnable()
   {
    EventBus.Instance.onPickUpItem += OnItemPickedUp;
   }


   private void OnDisable()
   {
    EventBus.Instance.onPickUpItem -= OnItemPickedUp;
   }

   private void OnItemPickedUp(ItemData itemData)
   {
    foreach (var slot in _slots)
    {
      if (slot.isEmpty())
      {
        slot.itemData = itemData;
        Debug.Log("slot has been filled");
        break;
      }
    }
   }
  
   public void OnSlotSelected(ItemSlot selectedSlot)
   {
     if (selectedSlot.itemData == null)
     {
     _itemNameText.ClearMesh();  
     _itemDescriptionText.ClearMesh();
    
     return;
     }
      _itemNameText.SetText(selectedSlot.itemData.Name);
      _itemDescriptionText.SetText(selectedSlot.itemData.Description[0]);
    
     if (selectedSlot == null)
     {
      Debug.Log("slot selected");
     
     }  
   }

private void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
   if (_state == State.menuClosed)
   {
    EventBus.Instance.PauseGamePlay();
   Debug.Log(_state);
   _fader.FadeToBlack(0.3f, FadeFromMenuCallback);
   _state = State.menuOpen;
   }
   else if (_state == State.menuOpen)
   {
    EventBus.Instance.ResumeGamePlay();
  Debug.Log(_state);
   _fader.FadeToBlack(0.3f, FadeToMenuCallback);
   _state = State.menuClosed;
   }
}

}
private void FadeFromMenuCallback()
{
AudioManager.instance.PlayOneShot(OpenInventorySound, this.transform.position);
_inventoryView.SetActive(true);
_fader.FadeFromBlack(0.3f, null);
//Debug.Log(_state);
}
private void FadeToMenuCallback()
{
AudioManager.instance.PlayOneShot(OpenInventorySound, this.transform.position);
_inventoryView.SetActive(false);
_fader.FadeFromBlack(0.3f, null);
//Debug.Log(_state);
}


}

I mean your OnItemPickedUp method is exceedingly simple. And at glance I don’t see how it could be the issue, unless there is something wrong with your isEmpty() method. What debugging have you done to make you think it’s the issue? It sounds like you have more debugging to do.

in the on pick up method the debug log tells me if the slots have been filled as you can see here after picking up an item before leaving the room the slots filled but when I come back and pick up the other object the log will not fire off

also here is an image of the hierarchy for persistent objects



here is the log after I picked up the item that was now a persistent object on dontdestroyonload

the pickup script work and destroyed the game object but the debof log for slot filled did not fire off

Right, that much is obvious. Like I said, the method is exceedingly simple. It alone in isolation is probably not the problem. Have you check your isEmpty() method? Have you confirmed there is actually more than one slot? Is there something wrong with your DDoL implementation? Honestly, using DDoL for persistent items in an inventory system raises alarm bells, as does that “there is more than one manager” log message. You need to keep debugging.

added a debug log to the isEmpy method nothing showed up upon picking up an item 9829497--1413513--upload_2024-5-12_1-52-45.png

How do you handle the situation when all slots are full?

like in resident evil 1 there will be a storage box

Your code is assuming there will be an empty slot.

What is DDoL? Google search finds 0 results for this acronym.

Which means the code isn’t running. Which means something is probably up with your inventory slots. Which means you have your next point to investigate. Don’t just add one more Debug.Log and keeping coming back to us. Keep investigating. We can’t debug your code for you.

DontDestroyOnLoad.

1 Like

DonDestroyOnLoad

The return keyword exits the method as soon as its reached. Since you’re calling return before the Debug.Log the logging will never happen even when it should have.

3 Likes

ok still debugging but heres a video to give a better example of what happening

edit: not sure if this also helps but upon starting the game the persistent stuff for both player and items become DDOL and functions fine with collection and viewing items until you leave and come back so im wondering if its were there some sort of data separation or mishandling im not seeing

I will rewrite this Debug.log today when I get home and see what happens thank you :slight_smile:

ok i just finish debugging in
in the itemslot script when I pick up items before leaving the room the log fires off but if I leave and comeback it does as I’ve described its doesn’t fire off

If you haven’t identified the source of the problem, then your debugging process hasn’t finished yet. Debugging involves finding the source of your problem, rather than just describing it. Use what you’ve found so far to keep digging.

3 Likes

Yes, exactly what Spiney says.

Turn this statement:

into this conversation in your head:

"I expect when I leave and come back, mechanism X should cause the code to be running.
However, mechanism X isn’t happening so the code doesn’t run.
What is wrong with mechanism X?"

Keep in mind “mechanism X” may be a complex series of steps, such as loading the scene, activating other pieces of code, etc., I don’t know what all you’re doing.

But that is the mindset you need to debug.

2 Likes

think i found the source of the problem game uses and eventbus
if I’m correct on how events work as soon as I pick up and item

pickupitem is called which invokes the onitempickup in the inventory

now the question is why does this happen when the items that children DDOL

“Inventory Controller”

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.EventSystems;
using FMODUnity;

public class InventorySelectController : MonoBehaviour
{
  
  
   
   [SerializeField] private GameObject _inventoryView;
   [SerializeField] private TMP_Text _itemNameText;
   [SerializeField] private TMP_Text _itemDescriptionText;
   [SerializeField] private EventReference OpenInventorySound;
   [SerializeField] private EventReference CloseInventorySound;
   [SerializeField] private List<ItemSlot> _slots;

   [SerializeField] private Playermovement _Playermovement;
   [SerializeField] private ScreenFader _fader;

   private enum State
   {
   menuClosed,
   menuOpen,
   };
  
   private State _state;
  

   private void OnEnable()
   {
    EventBus.Instance.onPickUpItem += OnItemPickedUp;
   }


   private void OnDisable()
   {
    EventBus.Instance.onPickUpItem -= OnItemPickedUp;
   }

   private void OnItemPickedUp(ItemData itemData)
   {
    foreach (var slot in _slots)
    {
      if (slot.isEmpty())
      {
        slot.itemData = itemData;
        //Debug.Log("slot has been filled");
        break;
      }
    }
   }
  
   public void OnSlotSelected(ItemSlot selectedSlot)
   {
     if (selectedSlot.itemData == null)
     {
     _itemNameText.ClearMesh();  
     _itemDescriptionText.ClearMesh();
    
     return;
     }
      _itemNameText.SetText(selectedSlot.itemData.Name);
      _itemDescriptionText.SetText(selectedSlot.itemData.Description[0]);
    
     if (selectedSlot == null)
     {
      Debug.Log("slot selected");
     
     }  
   }

private void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
   if (_state == State.menuClosed)
   {
    EventBus.Instance.PauseGamePlay();
   Debug.Log(_state);
   _fader.FadeToBlack(0.3f, FadeFromMenuCallback);
   _state = State.menuOpen;
   }
   else if (_state == State.menuOpen)
   {
    EventBus.Instance.ResumeGamePlay();
  Debug.Log(_state);
   _fader.FadeToBlack(0.3f, FadeToMenuCallback);
   _state = State.menuClosed;
   }
}

}
private void FadeFromMenuCallback()
{
AudioManager.instance.PlayOneShot(OpenInventorySound, this.transform.position);
_inventoryView.SetActive(true);
_fader.FadeFromBlack(0.3f, null);
//Debug.Log(_state);
}
private void FadeToMenuCallback()
{
AudioManager.instance.PlayOneShot(OpenInventorySound, this.transform.position);
_inventoryView.SetActive(false);
_fader.FadeFromBlack(0.3f, null);
//Debug.Log(_state);
}


}

“EventBus”

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventBus : MonoBehaviour
{
    public static EventBus Instance {get; private set;}
    public event Action onOpenInventory;
    public event Action onCloseInventory;
   
    public event Action<ItemData> onPickUpItem;

    public event Action onGameplayePaused;
    public event Action onGameplayeResumed;
    public void OpenInventory()
    {
        onOpenInventory?.Invoke();
    }
    public void CloseInventory()
    {
        onCloseInventory?.Invoke();
    }

    public void PickUpItem(ItemData itemData)
    {
       if(onPickUpItem == null)
       Debug.LogError("nothing subscribed to onPickUpItem");
       onPickUpItem?.Invoke(itemData); 
    }
   
  public void EquipItem(ItemData itemData)
    {
        //onEquipItem?.Invoke(itemData); 
    }

  public void StoreItem(ItemData itemData)
    {
        //onStoreItem?.Invoke(itemData); 
    }
public void PauseGamePlay()
    {
       onGameplayePaused?.Invoke(); 
    }

    public void ResumeGamePlay()
    {
        onGameplayeResumed?.Invoke(); 
    }


    // Update is called once per frame
    private void Awake()
    {
        Instance = this;
    }
}

I’m not sure if im missing something here but i assume your DDoL scripts are in the scene you start with, do you check to see if you have duplicates which would happen when you leave the scene and return. In which case you would need to do a check and make sure only 1 version of these scripts is running at a time. I’m not seeing this in any of the scripts that you have posted so far.

1 Like

Building on what @TeaJunkie suggests above, your EventBus looks like a horribly defective singleton implementation.

If you are expecting that to be DontDestroyOnLoad() then you absolutely CANNOT connect it to ANYTHING else that is not also marked DDoL. If you do so, then those other objects will go away while this object persists and refers to them, and now you have errors.

And if you place this in a scene and reload that scene, your Awake() function will WIPE OUT the old instance reference and now you will have two of them. There is no lifetime our uniqueness control in your code whatsoever.

Ideally, do not mark ANYTHING as DontDestroyOnLoad()

If you absolutely must, then NEVER place it in any scene, EVER. It’s that bad to do so, even if every single tutorial out there shows you to do that. Those tutorials all assume you never reload the scene, and this error happens all the time in here.

Instead, use this pattern if you absolutely must have a DontDestroyOnLoad() object, and NEVER place it in a scene.

Simple Singleton (UnitySingleton):

Some super-simple Singleton examples to take and modify:

Simple Unity3D Singleton (no predefined data):

Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance

Alternately you could start one up with a RuntimeInitializeOnLoad attribute.

1 Like

no the EventBus is connected to anything in scene if I’m reading your post correctly
I’m gonna be honest I got most of this code from an incomplete tutorial series and I’ve been doing my best to foot it on my own from there

but the event bus isn’t in the scene whatso ever as far as I see it this is how the script sequence of events goes

pickup.cs fires Pickupitem() =====> eventbus fires of Pickupitem which invokes onPickupitem which the inventory controller subscribes to

honestly if it is the don’t destroyonload that’s causing problems I think I’m better off doing what I initially planned and code a save/load system for rooms

I also don’t know if this helps even more but this is the dontdestory script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DontDestroy : MonoBehaviour
{
private static GameObject[] persistentObjects = new GameObject[3];
public int objectIndex;
  void Awake()
  {
     if(persistentObjects[objectIndex]== null)
     {
     persistentObjects[objectIndex] = gameObject;
     DontDestroyOnLoad(gameObject);
     }
 
     else if (persistentObjects[objectIndex] != gameObject)
     {
       Destroy(gameObject);
     }

   }

}