I’ve been trying to create a save system that can save the items in my inventory and also save the position of where items are since the items can be dropped. With the code below the saving will keep the items in my inventory, but on the first load after saving, if I drop an item from my inventory with the “usebananaX”, it just removes the item from the inventory instead of placing it down.
sorry for the messy code, I have hit it with a hammer about 42 times trying different things
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System.IO;
//every object that can be interacted with needs to be a prefab even if its a clone of another object
public class Inventory : MonoBehaviour, IDataPersistence
{
// Array "inventory" with a size of 4 (modifiable)
public GameObject[] inventory = new GameObject[4];
public Button[] InventoryButtons = new Button[4];
public GameObject Player;
public Transform itemSpawnLocation;
public GameObject itemToSpawn;
public TMP_Text howManySticks;
public int stickCount;
public int stoneCount;
public int leafCount;
public int ironCount;
public int glassCount;
public Text invItemTXT;
public bool canYouUseIt0; //if true then there is something in "[0]" inventory slot
public bool canYouUseIt1;
public bool canYouUseIt2;
public bool canYouUseIt3;
public void LoadData(GameData data)
{
this.stickCount = data.stickCount;
this.stoneCount = data.stoneCount;
this.leafCount = data.leafCount;
this.ironCount = data.ironCount;
this.glassCount = data.glassCount;
// Clear the inventory and UI
for (int i = 0; i < inventory.Length; i++)
{
inventory[i] = null;
InventoryButtons[i].image.overrideSprite = null;
}
// Load saved items into the inventory
for (int i = 0; i < data.inventoryItems.Count; i++)
{
InventoryItemData itemData = data.inventoryItems[i];
// Load the original prefab from Resources
GameObject prefab = Resources.Load<GameObject>("Prefabs/" + itemData.prefabPath);
if (prefab != null)
{
GameObject item = prefab;
// Assign item properties
InteractionObject interactionObject = item.GetComponent<InteractionObject>();
interactionObject.itemType = itemData.itemType;
// Add item to inventory
inventory[i] = item;
InventoryButtons[i].image.overrideSprite = item.GetComponent<SpriteRenderer>().sprite;
// Deactivate item in the scene?
//item.SetActive(false);
}
else
{
Debug.LogWarning("Prefab not found for item: " + itemData.prefabPath);
}
}
}
public void SaveData(ref GameData data)
{
data.stickCount = this.stickCount;
data.stoneCount = this.stoneCount;
data.leafCount = this.leafCount;
data.ironCount = this.ironCount;
data.glassCount = this.glassCount;
data.inventoryItems.Clear();
for (int i = 0; i < inventory.Length; i++)
{
if (inventory[i] != null)
{
InteractionObject interactionObject = inventory[i].GetComponent<InteractionObject>();
InventoryItemData itemData = new InventoryItemData
{
itemID = interactionObject.id,
itemName = inventory[i].name,
itemType = inventory[i].GetComponent<InteractionObject>().itemType,
prefabPath = inventory[i].name, // Use prefab name for lookup
position = inventory[i].transform.position,
rotation = inventory[i].transform.rotation,
quantity = 1
};
data.inventoryItems.Add(itemData);
}
}
}
public void AddItem(GameObject item)
{
bool itemAdded = false;
// Finding the first empty slot in inventory
for (int i = 0; i < inventory.Length; i++)
{
if (inventory[i] == null)
{
inventory[i] = item;
Debug.Log(item.name + " was added");
itemAdded = true;
//update ui to show item in slot
InventoryButtons[i].image.overrideSprite = item.GetComponent<SpriteRenderer>().sprite;
// Do something with the object "DoInteraction" calls to other script with the same function name
item.SendMessage("DoInteraction", SendMessageOptions.DontRequireReceiver);
string itemType = item.GetComponent<InteractionObject>().itemType;
if (itemType == "Stick")
{
Debug.Log("you picked up a stick");
stickCount = stickCount + 1;
}
else if (itemType == "Stone")
{
stoneCount = stoneCount + 1;
}
else if (itemType == "Leaf")
{
leafCount = leafCount + 1;
}
else if (itemType == "Glass")
{
glassCount = glassCount + 1;
}
else if (itemType == "Iron")
{
ironCount = ironCount + 1;
}
item.SetActive(false);
break;
}
}
// If inventory is full
if (!itemAdded)
{
Debug.Log("Inventory full - item not added!!");
}
}
public bool FindItem(GameObject item)
{
for (int i = 0; i < inventory.Length; i++)
{
if (inventory[i] == item)
{
// We found the item
return true;
}
}
// We didn't find it
return false;
}
public GameObject FindItemByType(string itemType)
{
for (int i = 0; i < inventory.Length; i++)
{
if (inventory[i] != null)
{
if (inventory[i].GetComponent<InteractionObject>().itemType == itemType)
{
// We found it
return inventory[i];
}
}
}
// We didn't find it
return null;
}
public void RemoveItem(GameObject item)
{
for (int i = 0; i < inventory.Length; i++)
{
if (inventory[i] == item)
{
// If found, remove it
inventory[i] = null;
Debug.Log(item.name + " was removed from inventory");
//remove item from ui
InventoryButtons[i].image.overrideSprite = null;
string itemType = item.GetComponent<InteractionObject>().itemType;
if (itemType == "Stick")
{
stickCount = stickCount - 1;
}
if (itemType == "Stone")
{
stoneCount = stoneCount - 1;
}
if (itemType == "Leaf")
{
leafCount = leafCount - 1;
}
if (itemType == "Iron")
{
ironCount = ironCount - 1;
}
if (itemType == "Glass")
{
glassCount = glassCount - 1;
}
break;
}
}
}
public void pickedUpStick()
{
Debug.Log("picked up a stick");
stickCount = stickCount + 1;
}
public void Update()
{
howManySticks.text = stickCount.ToString();
GameObject stick = FindItemByType("Stick");
GameObject stone = FindItemByType("Stone");
GameObject leaf = FindItemByType("Leaf");
GameObject iron = FindItemByType("Iron");
GameObject glass = FindItemByType("Glass");
//if material is less than 0 return to 0
if (stickCount < 0)
{
stickCount = 0;
}
if (stoneCount < 0)
{
stoneCount = 0;
}
if (leafCount < 0)
{
leafCount = 0;
}
if (ironCount < 0)
{
ironCount = 0;
}
if (glassCount < 0)
{
glassCount = 0;
}
//checks to see if an item is in a certain slot
if (inventory[0] != null) //[i] is the specific slot in this case the first one on the left
{
canYouUseIt0 = true; //sets this value true to use in button ui "useBanana" function
}
if (inventory[1] != null) //[i] is the specific slot in this case the first one on the left
{
canYouUseIt1 = true; //sets this value true to use in button ui "useBanana" function
}
if (inventory[2] != null) //[i] is the specific slot in this case the first one on the left
{
canYouUseIt2 = true; //sets this value true to use in button ui "useBanana" function
}
if (inventory[3] != null) //[i] is the specific slot in this case the first one on the left
{
canYouUseIt3 = true; //sets this value true to use in button ui "useBanana" function
}
}
public void UseBanana0() //if "canYouUseIt" is true then this will run otherwise it won't
{
if (canYouUseIt0 && inventory[0] != null)
{
GameObject itemToDrop = inventory[0];
// Remove the item from the inventory
RemoveItem(itemToDrop);
// Reactivate and position the original item
Vector3 position = itemSpawnLocation != null ? itemSpawnLocation.position : transform.position;
itemToDrop.transform.position = position;
itemToDrop.SetActive(true);
Debug.Log(itemToDrop.name + " was dropped");
}
}
public void UseBanana1() //if "canYouUseIt" is true then this will run otherwise it won't
{
if (canYouUseIt1 && inventory[1] != null)
{
GameObject itemToDrop = inventory[1];
// Remove the item from the inventory
RemoveItem(itemToDrop);
// Reactivate and position the original item
Vector3 position = itemSpawnLocation != null ? itemSpawnLocation.position : transform.position;
itemToDrop.transform.position = position;
itemToDrop.SetActive(true);
Debug.Log(itemToDrop.name + " was dropped");
}
}
public void UseBanana2() //if "canYouUseIt" is true then this will run otherwise it won't
{
if (canYouUseIt2 && inventory[2] != null)
{
GameObject itemToDrop = inventory[2];
// Remove the item from the inventory
RemoveItem(itemToDrop);
// Reactivate and position the original item
Vector3 position = itemSpawnLocation != null ? itemSpawnLocation.position : transform.position;
itemToDrop.transform.position = position;
itemToDrop.SetActive(true);
Debug.Log(itemToDrop.name + " was dropped");
}
}
public void UseBanana3() //if "canYouUseIt" is true then this will run otherwise it won't
{
if (canYouUseIt3 && inventory[3] != null)
{
GameObject itemToDrop = inventory[3];
// Remove the item from the inventory
RemoveItem(itemToDrop);
// Reactivate and position the original item
Vector3 position = itemSpawnLocation != null ? itemSpawnLocation.position : transform.position;
itemToDrop.transform.position = position;
itemToDrop.SetActive(true);
Debug.Log(itemToDrop.name + " was dropped");
}
}
private void Start()
{
if(DataPersistenceManager.instance == null)
{
Debug.LogError("DataPersistenceManager instance is null. Ensure it is initialized");
return;
}
DataPersistenceManager.instance.LoadGame();
}
private void OnApplicationQuit()
{
DataPersistenceManager.instance.SaveGame();
}
}
DataPersistenceManager script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class DataPersistenceManager : MonoBehaviour
{
[Header("File Storage Config")]
[SerializeField] private string fileName;
[SerializeField] private bool useEncryption;
private GameData gameData;
private List<IDataPersistence> dataPersistenceObjects;
private FileDataHandler dataHandler;
public static DataPersistenceManager instance { get; private set; }
private void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Debug.LogError("Found more than one data persistence manager in the scene");
Destroy(gameObject);
}
}
private void Start()
{
this.dataHandler = new FileDataHandler(Application.persistentDataPath, fileName, useEncryption);
this.dataPersistenceObjects = FindAllDataPersistenceObjects();
// Try to load game data
this.gameData = dataHandler.Load();
// If no data is found, initialize default data
if (this.gameData == null)
{
Debug.Log("No data was found. Initializing to default data.");
NewGame();
}
// Ensure gameData is not null before loading the game
if (this.gameData == null)
{
Debug.LogError("Failed to initialize gameData in Start().");
return;
}
// Now safely load game data into persistence objects
LoadGame();
}
public void NewGame()
{
this.gameData = new GameData();
if (this.gameData == null)
{
Debug.LogError("Failed to initialize a new GameData object.");
}
}
public void LoadGame()
{
if (gameData == null)
{
Debug.LogError("GameData is null in LoadGame(). This should not happen.");
return;
}
foreach (IDataPersistence dataPersistenceObj in dataPersistenceObjects)
{
dataPersistenceObj.LoadData(gameData);
}
Debug.Log("LOADED sticks = " + gameData.stickCount);
}
public void SaveGame()
{
if (gameData == null)
{
Debug.LogError("Cannot save game because gameData is null.");
return;
}
foreach (IDataPersistence dataPersistenceObj in dataPersistenceObjects)
{
dataPersistenceObj.SaveData(ref gameData);
}
Debug.Log("Saved sticks = " + gameData.stickCount);
dataHandler.Save(gameData);
}
private void OnApplicationQuit()
{
SaveGame();
}
private List<IDataPersistence> FindAllDataPersistenceObjects()
{
IEnumerable<IDataPersistence> dataPersistenceObjects = FindObjectsOfType<MonoBehaviour>().OfType<IDataPersistence>();
return new List<IDataPersistence>(dataPersistenceObjects);
}
}
Inventory Item Data script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class InventoryItemData
{
public string itemName;
public string itemType; // e.g., "Stick", "Stone"
public string prefabPath;
public string spritePath; // Path to the item's sprite
public int quantity; // Optional: For stackable items
public string itemID;
public Vector3 position;
public Quaternion rotation;
}
file data handler script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
public class FileDataHandler
{
private string dataDirPath = "";
private string dataFileName = "";
private bool useEncryption = false;
private readonly string encryptionCodeWord = "BlueJaysLoveCardinals";
public FileDataHandler(string dataDirPath, string dataFileName, bool useEncryption)
{
this.dataDirPath = dataDirPath;
this.dataFileName = dataFileName;
this.useEncryption = useEncryption;
}
public void Save(GameData data)
{
string fullPath = Path.Combine(dataDirPath, dataFileName);
try
{
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
string dataToStore = JsonUtility.ToJson(data, true);
if (useEncryption)
{
dataToStore = EncryptDecrypt(dataToStore);
}
using (FileStream stream = new FileStream(fullPath, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(dataToStore);
}
}
}
catch (Exception e)
{
Debug.LogError("Error occured when trying to save data to file: " + fullPath + "\n" + e);
}
}
public GameData Load()
{
string fullPath = Path.Combine(dataDirPath, dataFileName);
GameData loadedData = null;
if(File.Exists(fullPath))
{
try
{
string dataToLoad = "";
if (useEncryption)
{
dataToLoad = EncryptDecrypt(dataToLoad);
}
using (FileStream stream = new FileStream(fullPath, FileMode.Open))
{
using (StreamReader reader = new StreamReader(stream))
{
dataToLoad = reader.ReadToEnd();
}
}
loadedData = JsonUtility.FromJson<GameData>(dataToLoad);
}
catch(Exception e)
{
Debug.LogError("Error occured when trying to load data from file: " + fullPath + "\n" + e);
}
}
return loadedData;
}
private string EncryptDecrypt(string data)
{
string modifiedData = "";
for (int i = 0; i < data.Length; i++)
{
modifiedData += (char)(data[i] ^ encryptionCodeWord[i % encryptionCodeWord.Length]);
}
return modifiedData;
}
}