Unable to save and load inventory accross scenes

Discussion and help for Easy Save 3
Post Reply
TrashRat
Posts: 4
Joined: Wed Feb 21, 2024 3:40 pm

Unable to save and load inventory accross scenes

Post by TrashRat »

Hey, so i'll try and keep this as swift as possible.


I have implimented an inventory system in my game that allows me to pick up spawned objects, through scriptable objects, and I can click and drag them, equip them, drop them back into the world etc.

The major headache comes with saving and loading these things into another scene. So if I pick up an object in one scene, then move into another, that object should still be in my inventory. I paid for Easy Save 3 as I was having such difficulty but I'm getting to that point of development where it's easy to be overwhelmed and feel like i'm only making matters worse.

Any help would be greatly appreciated, or even pointing in the right direction.

Thank you, please see below my Inventory script. This is attached to the player character. There are seperte scripts for Inventory SlotUI, and InventoryUI attached to the canvas.

Code: Select all

 /// <summary>
 /// Provides storage for the player inventory. A configurable number of
 /// slots are available.
 ///
 /// This component should be placed on the GameObject tagged "Player".
 /// </summary>
 public class Inventory : MonoBehaviour, ISaveable
 {
     // CONFIG DATA
     [Tooltip("Allowed size")]
     [SerializeField] int inventorySize = 16;

     // STATE
     InventorySlot[] slots;

     public struct InventorySlot
     {
         public InventoryItem item;
         public int number;
     }

     // PUBLIC
     [Tooltip("Typically leave unticked so temporary Dialogue Managers don't unregister your functions.")]
     public bool unregisterOnDisable = false;
     /// <summary>
     /// Broadcasts when the items in the slots are added/removed.
     /// </summary>
     public event Action inventoryUpdated;

     /// <summary>
     /// Convenience for getting the player's inventory.
     /// </summary>
     public static Inventory GetPlayerInventory()
     {
         var player = GameObject.FindWithTag("Player");
         return player.GetComponent<Inventory>();
     }

     /// <summary>
     /// Could this item fit anywhere in the inventory?
     /// </summary>
     public bool HasSpaceFor(InventoryItem item)
     {
         return FindSlot(item) >= 0;
     }

     /// <summary>
     /// How many slots are in the inventory?
     /// </summary>
     public int GetSize()
     {
         return slots.Length;
     }

     /// <summary>
     /// Attempt to add the items to the first available slot.
     /// </summary>
     /// <param name="item">The item to add.</param>
     /// <param name="number">The number to add.</param>
     /// <returns>Whether or not the item could be added.</returns>
     public bool AddToFirstEmptySlot(InventoryItem item, int number)
     {
         int i = FindSlot(item);

         if (i < 0)
         {
             return false;
         }

         slots[i].item = item;
         slots[i].number += number;
         print(slots[i].number);
         if (inventoryUpdated != null)
         {
             inventoryUpdated();
         }
         return true;
     }

     /// <summary>
     /// Is there an instance of the item in the inventory?
     /// </summary>
     public bool HasItem(InventoryItem item)
     {
         for (int i = 0; i < slots.Length; i++)
         {
             if (object.ReferenceEquals(slots[i].item, item))
             {
                 return true;
             }
         }
         return false;
     }

     public bool HasItemID(string itemID)
     {
         //if (slots[0].item == null) return false;

         for (int i = 0; i < slots.Length; i++)
         {
             if (slots[i].item != null)
             {
                 if (slots[i].item.GetItemID() == itemID)
                 {
                     return true;
                 }
             }  
         }
         return false;
     }

     /// <summary>
     /// Return the item type in the given slot.
     /// </summary>
     public InventoryItem GetItemInSlot(int slot)
     {
         return slots[slot].item;
     }

     /// <summary>
     /// Get the number of items in the given slot.
     /// </summary>
     public int GetNumberInSlot(int slot)
     {
         return slots[slot].number;
     }

     /// <summary>
     /// Remove a number of items from the given slot. Will never remove more
     /// that there are.
     /// </summary>
     public void RemoveFromSlot(int slot, int number)
     {
         slots[slot].number -= number;
         if (slots[slot].number <= 0)
         {
             slots[slot].number = 0;
             slots[slot].item = null;
         }
         if (inventoryUpdated != null)
         {
             inventoryUpdated();
         }
     }

     public void RemoveWithID(string itemID, double number)
     {

         for (int i = 0; i < slots.Length; i++)
         {
             if (slots[i].item != null)
             {
                 if (slots[i].item.GetItemID() == itemID)
                 {
                     RemoveFromSlot(i, Convert.ToInt32(number));
                     return;
                 }
             }
         }
         //slots[slot].number -= number;
         //if (slots[slot].number <= 0)
         //{
         //    slots[slot].number = 0;
         //    slots[slot].item = null;
         //}
         //if (inventoryUpdated != null)
         //{
         //    inventoryUpdated();
         //}
     }

     /// <summary>
     /// Will add an item to the given slot if possible. If there is already
     /// a stack of this type, it will add to the existing stack. Otherwise,
     /// it will be added to the first empty slot.
     /// </summary>
     /// <param name="slot">The slot to attempt to add to.</param>
     /// <param name="item">The item type to add.</param>
     /// <param name="number">The number of items to add.</param>
     /// <returns>True if the item was added anywhere in the inventory.</returns>
     public bool AddItemToSlot(int slot, InventoryItem item, int number)
     {
         if (slots[slot].item != null)
         {
             return AddToFirstEmptySlot(item, number); ;
         }

         var i = FindStack(item);
         if (i >= 0)
         {
             slot = i;
         }

         slots[slot].item = item;
         slots[slot].number += number;
         if (inventoryUpdated != null)
         {
             inventoryUpdated();
         }
         return true;
     }

     // PRIVATE

     private void Awake()
     {
         slots = new InventorySlot[inventorySize];
     }

     /// <summary>
     /// Find a slot that can accomodate the given item.
     /// </summary>
     /// <returns>-1 if no slot is found.</returns>
     private int FindSlot(InventoryItem item)
     {
         int i = FindStack(item);
         if (i < 0)
         {
             i = FindEmptySlot();
         }
         return i;
     }

     /// <summary>
     /// Find an empty slot.
     /// </summary>
     /// <returns>-1 if all slots are full.</returns>
     private int FindEmptySlot()
     {
         for (int i = 0; i < slots.Length; i++)
         {
             if (slots[i].item == null)
             {
                 return i;
             }
         }
         return -1;
     }

     /// <summary>
     /// Find an existing stack of this item type.
     /// </summary>
     /// <returns>-1 if no stack exists or if the item is not stackable.</returns>
     private int FindStack(InventoryItem item)
     {
         if (!item.IsStackable())
         {
             return -1;
         }

         for (int i = 0; i < slots.Length; i++)
         {
              if (object.ReferenceEquals(slots[i].item, item))
             {
                 return i;
             }
         }
         return -1;
     }

     [System.Serializable]
     private struct InventorySlotRecord
     {
         public string itemID;
         public int number;
     }
TrashRat
Posts: 4
Joined: Wed Feb 21, 2024 3:40 pm

Re: Unable to save and load inventory accross scenes

Post by TrashRat »

Oh and please ignore "ISavable" that was from a seperate attempt.
User avatar
Joel
Moodkie Staff
Posts: 4849
Joined: Wed Nov 07, 2012 10:32 pm

Re: Unable to save and load inventory accross scenes

Post by Joel »

Hi there,

Are you getting any warnings in console when loading? Could you provide more info on what isn't loading correctly, and how you're saving and loading?

Also be aware that objects which inherit from UnityEngine.Object (such as ScriptableObjects) will be saved and loaded by value. See the Saving References guide for more info:

https://docs.moodkie.com/easy-save-3/es ... eferences/

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
TrashRat
Posts: 4
Joined: Wed Feb 21, 2024 3:40 pm

Re: Unable to save and load inventory accross scenes

Post by TrashRat »

Hi Joel, this may (will no doubt) all just stem from a lack of my own understanding.

There are no errors in the console, and here is how I am saving and loading into a new scene (player presses 'E' at door, transition begins)

Code: Select all

public class SceneLoader : MonoBehaviour
{
    private bool CanLoadScene = false;
    [SerializeField] private string scene;
    [SerializeField] private AudioClip clip;
    [SerializeField] private AudioSource source;

    [SerializeField] private AudioSource currentAudio;
    [SerializeField] private float fadeTime = 4f;

    public Animator transition;
    public float transitionTime = 1f;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.E) && CanLoadScene)
        {
            StartCoroutine(LoadLevel());
        }
    }

    IEnumerator LoadLevel()
    {
        ES3.Save<Inventory>(this.name, Inventory.GetPlayerInventory());
        if (scene == "CroftInterior")
        {
            source.PlayOneShot(clip);
        }

        DontDestroyOnLoad(gameObject);
        transition.SetTrigger("Start");

        StartCoroutine(FadeOut(currentAudio, fadeTime));
        yield return new WaitForSeconds(transitionTime);

        
        yield return SceneManager.LoadSceneAsync(scene);
        ES3.LoadInto<Inventory>(this.name, Inventory.GetPlayerInventory());
        Destroy(gameObject);
    }


    public static IEnumerator FadeOut(AudioSource audioSource, float FadeTime)
    {
        float startVolume = audioSource.volume;

        while (audioSource.volume > 0)
        {
            audioSource.volume -= startVolume * Time.deltaTime / FadeTime;

            yield return null;
        }

        audioSource.Stop();
        audioSource.volume = startVolume;
    }

    private void OnTriggerEnter(Collider other)
    {
        CanLoadScene = true;
    }

    private void OnTriggerExit(Collider other)
    {
        CanLoadScene = false;
    }
}
User avatar
Joel
Moodkie Staff
Posts: 4849
Joined: Wed Nov 07, 2012 10:32 pm

Re: Unable to save and load inventory accross scenes

Post by Joel »

Hi there,

You appear to be saving in your LoadLevel method (which itself is unusual). And then when the level loads, you're loading your data. This seems redundant to me as the save data will always be the data you've saved before you've entered a level.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
TrashRat
Posts: 4
Joined: Wed Feb 21, 2024 3:40 pm

Re: Unable to save and load inventory accross scenes

Post by TrashRat »

Hi Joel,

Thanks for the reply. I think that was my attempt at saving the Inventory before the level loads, and then loading it back into the new scene which no doubt shows a complete lack of understanding on my part!
User avatar
Joel
Moodkie Staff
Posts: 4849
Joined: Wed Nov 07, 2012 10:32 pm

Re: Unable to save and load inventory accross scenes

Post by Joel »

In some situations that might be acceptable. However, the issue will arrive when going between sessions. For example if your player quits your game, loads it back up and then goes to the last saved level, it will overwrite the save data. Hope this helps :)
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
Post Reply