Now, I now the title is really obscure, but I have tried to solve the following problem for so long and most of it is integrated into my game so far that I can't just copy & paste it here, so this is as simple as I can explain it:
I'm saving my data using NewtonSoft Json.
I basically have a singleton manager script that stores all quests in the game (quests
), and all completed quests (completedQuests
).
I use a property for getting all quests, since I don't want the base collection of every quest to ever change.
The SaveData
class is what I am saving in Json.
public class GameStatistics : MonoBehaviour
{
[Header("Settings:")]
[SerializeField] private QuestTemplate[] quests;
public QuestTemplate[] Quests
{
get { return quests; }
private set { quests = value; }
}
public List<QuestTemplate> completedQuests { get; set; } = new List<QuestTemplate>();
public static GameStatistics Instance { get; private set; }
private void Awake()
{
if(Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
DontDestroyOnLoad(gameObject);
}
[System.Serializable]
public class SaveData
{
[SerializeField] public List<QuestTemplate.QuestData> questDatas = new List<QuestTemplate.QuestData>();
[JsonConstructor]
public SaveData(List<QuestTemplate.QuestData> questDatas)
{
this.questDatas = questDatas ;
}
public SaveData()
{
questDatas = new List<QuestTemplate.QuestData>();
}
}
}
Every QuestTemplate
also contains 2 other classes, one for messages that are shown once the quest is completed (QuestMessage
), and one for all data that needs to be saved (QuestData
).
As you can see there are 2 QuestMessage
lists in total, this is because it isn't possible to save Dictionaries with complex keys properely with NewtonSoft Json, but I still need to know which message I am storing, so I put a whole list of QuestMessage
s in there.
public class QuestTemplate : ScriptableObject
{
[Header("Settings:")]
public QuestData questData;
public float timeLimit;
public List<QuestMessage> messages = new List<QuestMessage>();
[System.Serializable]
public class QuestData
{
public string saveName;
[HideInInspector] public float completionTime;
[HideInInspector] public List<QuestMessage> messages = new List<QuestMessage>();
}
[System.Serializable]
public class QuestMessage
{
public string headline;
public string sender;
[public string text;
[HideInInspector] public bool read = false;
}
}
This is my script I use for saving / loading:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
using Newtonsoft.Json;
public static class SavingSystem
{
private static readonly string SaveFileFolder = Application.persistentDataPath + "/Saves/";
public static void Save(GameStatistics.SaveData data)
{
if(Directory.Exists(SaveFileFolder) == false)
{
Directory.CreateDirectory(SaveFileFolder);
}
string _savePath = SaveFileFolder + "Data.json";
string _data = JsonConvert.SerializeObject(data, formatting: Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore});
File.WriteAllText(SaveFileFolder + "Data.json", _data);
}
public static GameStatistics.SaveData Load()
{
string _savePath = SaveFileFolder + "Data.json";
if(File.Exists(_savePath) == true)
{
string _data = File.ReadAllText(_savePath);
return (JsonConvert.DeserializeObject<GameStatistics.SaveData>(_data));
}
else
{
return(null);
}
}
public static void DeleteData()
{
string _savePath = SaveFileFolder + "Data.json";
if(File.Exists(_savePath) == true)
{
File.Delete(_savePath);
}
else
{
Debug.LogWarning("File doesn't exist.");
}
}
}
The Problem:
The saving to Json and loading from Json itself seems to be working alright, the problem is that whenever I am changing read
(e.g. to true
when the message has been read) the value seems to be persistent even when deleting the Data.json
file, even restarting the game doesn't reset it, the only thing that managed to do that was restarting my PC completely.
I did some checks with Debug.Log
s and it seems that whenever a message.read in the completedQuests
' questData
s is changed, that also changes the base array quests
, which is then persistent until I restart my PC.
I have absolutely no idea what to do, I tried so many thing and I have literally spend like 3 days in total working on some sort of fix.
If you have any idea what could be the problem, be it some strange behaviour of a list or array or the way my save structure is set up, please post it, at this point I am willing to try anything.