In the following code I check to see if an item exists in my inventory list, and if not then add the item. This works for the most part, except for when I exit and press play again. When my list is loaded from Json inventory.Contains is always returning false, even if the item does exist. But if I try to add the same item twice without exiting the game first I get the Debug.Log (“Item already owned”) correctly. What could be causing this issue?
P.S The deserialized list is working, and I can access the list elements and debug them accordingly so I don’t think this is where the problem lies.
private void Awake ()
{
itemDatabase = GameObject.FindGameObjectWithTag ("ItemDatabase").GetComponent<ItemDatabase> ();
if (File.Exists (Application.dataPath + "/inventory.json"))
{
LoadInventory ();
} else
{
inventory = new List<Item> ();
}
}
public void LoadInventory ()
{
var settings = new JsonSerializerSettings ();
settings.TypeNameHandling = TypeNameHandling.Auto;
string json = File.ReadAllText (Application.dataPath + "/inventory.json");
inventory = JsonConvert.DeserializeObject<List<Item>> (json, settings);
foreach (Item i in inventory)
{
i.itemIcon = Resources.Load<Sprite> ("Items/Icons/" + i.itemSlug);
i.itemModel = Resources.Load<GameObject> ("Items/Models/" + i.itemSlug);
}
}
public void SaveInventory ()
{
var settings = new JsonSerializerSettings ();
settings.TypeNameHandling = TypeNameHandling.Auto;
settings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject (inventory, Formatting.Indented, settings);
File.WriteAllText (Application.dataPath + "/inventory.json", json);
}
public void AddItemToInventoryList (int id)
{
Item itemToAdd = itemDatabase.GetItemByID (id); //Grab item from DB
if (!inventory.Contains (itemToAdd)) //Always returning false IF the item pre-exists in Json
{
inventory.Add (itemToAdd);
SaveInventory ();
} else
{
Debug.Log ("Item already owned!");
}
}
It’s a reference equality issue. The items in your item database are the same reference when you serialize them, but when deserialization happens, Unity has no way of knowing the items it’s deserializing in your inventory are supposed to be references to ones in your item database. Instead, it creates a new object, which will no longer be equal to the one in your item database, even though the values are the same. Rather than using Contains, which checks for reference equality, you need to check to see if your list contains an item with the same ID.
Thank you, that clears that up. How would I check that the list contains an item of the same ID without using List.Contains? I’m having the same reference equality issue when trying to remove an item from a list after it gets loaded via json, so if I can fix this I imagine I can work somethings similar for my other bugs.
EDIT: After playing around this is what I came up with. Not sure if this is ‘good code’ but it works for now… Thank you for your help!
public void AddItemToInventoryList (int id)
{
Item itemToAdd = itemDatabase.GetItemByID (id); //Grab item from DB
if (inventory.Count != 0)
{
bool exists = false;
for (int i = 0; i < inventory.Count; i++)
{
if (inventory [i].itemID == itemToAdd.itemID)
{
exists = true;
Debug.Log ("Item already owned!");
}
}
if (exists == false)
{
inventory.Add (itemToAdd);
AddSingleItem (itemToAdd);
}
} else if (inventory.Count == 0)
{
inventory.Add (itemToAdd);
AddSingleItem (itemToAdd);
}
SaveInventory ();
}