Saving Highscore in Json

Hey. I’m trying to save the Time and the Name of a player in a json file so i can make a highscore list with it. Everything seems to be going well but it doesnt actually save the data in the file. I dont really know what seems to be the problem and i would appreciate any help.

Here is the Manager Script. The Debug log says that: “Highscore data to be saved: {}”. But i do know that the “highscores” List isnt empty.

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

public class HighscoreManager : MonoBehaviour
{
    public List<HighscoreEntry> highscores = new List<HighscoreEntry>();

    string highscoreFileName;

    static HighscoreManager instance;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
            return;
        }

        highscoreFileName = Path.Combine(Application.persistentDataPath, "highscoresNew.json");
    }

    public void LoadHighscoresFromJSON()
    {
        if (File.Exists(highscoreFileName))
        {
            string highscoreData = File.ReadAllText(highscoreFileName);
            highscores = JsonUtility.FromJson<List<HighscoreEntry>>(highscoreData);
        }
        else
        {
            Debug.LogWarning("Highscore file does not exist: " + highscoreFileName);
        }
    }


    private void Start()
    {
        DontDestroyOnLoad(gameObject);
        LoadHighscores();     
    }


    public void UpdateHighscore(string playerName, float newTime)
    {
        if (newTime > 0)
        {
            Debug.Log("Player Name: " + playerName);
            Debug.Log("New Time: " + newTime);

            highscores.Add(new HighscoreEntry { playerName = playerName, timeSpent = newTime });

            highscores.Sort((x, y) => x.timeSpent.CompareTo(y.timeSpent));

            if (highscores.Count > 10)
            {
                highscores.RemoveRange(10, highscores.Count - 10);
            }

            SaveHighscores();

            Debug.Log("Highscore updated: " + playerName + " with time " + newTime);
            Debug.Log("Current highscores:");
            foreach (var entry in highscores)
            {
                Debug.Log(entry.playerName + ": " + entry.timeSpent);
            }
        }
    }



    public void SaveHighscores()
    {

        Debug.Log("Before serialization: " + JsonUtility.ToJson(highscores));
        string highscoreData = JsonUtility.ToJson(highscores);
        Debug.Log("After serialization: " + highscoreData);

        Debug.Log("Highscore data to be saved: " + highscoreData);
        Debug.Log("Saving highscores to file: " + highscoreFileName);

        try
        {
            File.WriteAllText(highscoreFileName, highscoreData);
            Debug.Log("Highscores saved to file: " + highscoreFileName);
        }
        catch (IOException e)
        {
            Debug.LogError("Error saving highscores: " + e.Message);
        }
    }


    public void LoadHighscores()
    {
        if (File.Exists(highscoreFileName))
        {
            Debug.Log("Loading highscores from file: " + highscoreFileName);
            string highscoreData = File.ReadAllText(highscoreFileName);
            highscores = JsonUtility.FromJson<List<HighscoreEntry>>(highscoreData);
        }
        else
        {
            Debug.LogWarning("Highscore file does not exist: " + highscoreFileName);
        }
    }
}

And here is the script that Dispays the Data

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;

public class HighscoreDisplay : MonoBehaviour
{
    public HighscoreManager highscoreManager;
    public Text highscoreText;

    private void Start()
    {
        highscoreManager = FindObjectOfType<HighscoreManager>();
        if (highscoreManager == null)
        {
            Debug.LogError("HighscoreManager not found.");
        }

        if (highscoreManager != null)
        {
            highscoreManager.LoadHighscoresFromJSON();
        }

        DisplayHighscores();
    }


    public void DisplayHighscores()
    {
        if (highscoreManager != null)
        {
            string scoreText = "Highscores:\n\n";
            List<HighscoreEntry> highscores = highscoreManager.highscores;

            for (int i = 0; i < highscores.Count; i++)
            {
                float time = highscores[i].timeSpent;

                int minutes = Mathf.FloorToInt(time / 60);
                int seconds = Mathf.FloorToInt(time % 60);
                int milliseconds = Mathf.FloorToInt((time * 100) % 100);

                if (highscores[i].timeSpent > 0)
                {
                    scoreText += highscores[i].playerName + ": " + string.Format("{0:00}:{1:00}:{2:00}", minutes, seconds, milliseconds) + "\n\n";
                }
            }

            highscoreText.text = scoreText;
        }
        else
        {
            Debug.LogError("HighscoreManager is not set.");
        }
    }
}

JsonUtility has some quirks. Specifically:

Read “array” as equivalent to “any collection type”.

Means you cannot save a collection type directly. You’d have to wrap it in a serializable class, and serialize that class rather than the list:

[System.Serializable]
public class Highscores
{
    public List<HighscoreEntry> scores = new();
}

var highscores = new Highscores();
// now use highscores.scores instead of your existing highscores field

// to save, save the container object, not the scores list:
var highscoresJson = JsonUtility.ToJson(highscores);

As @CodeSmile points out above…

Problems with Unity “tiny lite” built-in JSON:

In general I highly suggest staying away from Unity’s JSON “tiny lite” package. It’s really not very capable at all and will silently fail on very common data structures, such as bare arrays/Lists, tuples, Dictionaries and Hashes and ALL properties.

Instead grab Newtonsoft JSON .NET from the Unity Package Manager (Window → Package Manager).

If you want to avoid the Package Mangler’s UI, just add this to your Packages/manifest.json file:

"com.unity.nuget.newtonsoft-json": "3.0.2",

The former asset store package is now deprecated, as you can see here:

Also, always be sure to leverage sites like:

https://csharptojson.com

Thank you so much, now it actually works