[SOLVED] Avoiding ArgumentOutOfRange when changing list length between versions?

Hi all -

I have a PlayerController.cs class which stores, in the form of a list, instances of a serializable custom class. I use JSON serialization to save and load the status of each item stored in the list. However, when I add list items with an existing save file (e.g., I had 10 candies in the game before, saved it, add 2 more) and then load the game, Unity throws the ArgumentOutOfRange exception. If I ignore the error, save the game, then load it again, the error disappears, which leads me to believe that it is caused by a discrepancy in list lengths between the contents of the save and the contents of the game.

This is obviously not a big deal now, but will certainly become one when the game goes live and when I cannot rely on asking my users to wipe their save games every time a new version is released.

Any ideas how to work around this? Code below:

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

public class PlayerController : MonoBehaviour {

    public class Candy
        {
        public string identity;
        public int id;

        public double baseIncome;
        public double income;

        public int baseRarity;
        public int rarity;

        public float speed;
        public double baseHealth;
        public double health;
        }

    public List<Candy> candies = new List<Candy>();
}
public void Save()

    {
        PlayerData data = new PlayerData();

        for (int i = 0; i < candies.Count; i++) { data.candies.Insert(i, candies[i]); }

        string jsonData = JsonUtility.ToJson(data, true);
        File.WriteAllText(Application.persistentDataPath + "/playerSave.json", jsonData);
    
    }
public void Load()

    {
        if (File.Exists(Application.persistentDataPath + "/playerSave.json"))
            {
                string jsonData = File.ReadAllText((Application.persistentDataPath + "/playerSave.json"));
                PlayerData data = JsonUtility.FromJson<PlayerData>(jsonData);
        
                for (int i = 0; i < candies.Count; i++) { candies[i] = data.candies[i]; }
            }
    }
[Serializable]
class PlayerData

    {
    public List < PlayerController.Candy > candies = new List <PlayerController.Candy> ();
    }
public List<Candy> candies = new List<Candy>();
for (int i = 0; i < candies.[URL='http://unity3d.com/support/documentation/ScriptReference/30_search.html?q=Count']Count[/URL]; i++) { candies[i] = [URL='http://unity3d.com/support/documentation/ScriptReference/30_search.html?q=data']data[/URL].candies[i]; }

The problem is likely because you’re using “candies.Count” during load, but the list is empty, or has fewer default items than what’s in the file. You should probably be using “data.candies.Count” which has the number of items you loaded.

So something like this - note the use of “candies.Add” instead of using the index directly. As long as we start with an empty list you can just add in the loaded items.

candies.Clear();

for (int i = 0; i < data.candies.Count; i++) { candies.Add(data.candies[i]); }

Probably your best option is to just allow the List to create itself from the loaded collection. No need to code up that loop yourself.

candies = new List<Candy>(data.candies);
1 Like

Thanks, Dave, for taking the time to provide an in-depth reply! I’ll give it a shot tonight and write back.

Hi Dave -

Just wanted to report back and let you know that everything’s working swimmingly, and that I now have a truly persistent save system, where making updates no longer breaks saves.

Thanks again!

1 Like