Десериализация нескольких несвязанных объектов ScriptableObject из одного файла сохранения - PullRequest
3 голосов
/ 02 июля 2019

Я хочу сохранить несколько не связанных ScriptableObjects объектов в один файл сохранения. Таким образом, я могу сохранить / загрузить данные для всего, что я захочу отслеживать. IE. Двери разблокированы, инвентарь, рекорды, найдены сундуки с сокровищами и т. Д. Таким образом, я все еще могу использовать ScriptableObjects, а также сохранять и / или перезагружать в точку, находящуюся под контролем DataManager. Я хотел, чтобы DataManager ничего не делал, кроме сохранения и перезагрузки ScriptableObjects с сохраненными данными.

enter image description here

Сохранение различных ScriptableObjects в один файл, по-моему, работает нормально. Если я открою файл data_editor.sav, я увижу, что данные были сериализованы и помещены в файл.

{"serializedObjects":["{\"GUID\":\"e27e7e59111210141bb70cbdff58f4f6\",\"Prefab\":{\"instanceID\":3648}}","{\"GUID\":\"52abd33f0dd972246b5eaa87a938331e\",\"Prefab\":{\"instanceID\":3190}}","{\"GUID\":\"78d783846b8abb3488ee1e274773aec6\",\"Prefab\":{\"instanceID\":3080}}"]}

Однако чтение данных и попытка заселения моего свойства DataManager managedData - это то, что продолжает ломаться. Я не могу понять, как десериализовать строки JSON обратно в ScriptableObjects.

.

Я получаю ошибку:

ArgumentException: Невозможно десериализовать JSON для новых экземпляров типа 'ScriptableObject.

Я рассмотрел несколько SO вопросов, , включая этот , но я не могу найти ничего, что касается управления несколькими различными ScriptableObjects в одном.

Любая помощь?

Я пробовал варианты JsonUtility.FromJsonOverwrite и JsonUtility.FromJson<ScriptableObject>, но не смог заставить его работать.

DataStore Это класс, который записывается на диск.

[Serializable]
    public class DataStore : ISerializationCallbackReceiver
    {  
        public List<string> serializedObjects;

        public DataStore()
        {
            serializedObjects = new List<string>();
        }

        #region ISerializationCallbackReceiver_Methods
        /// <summary>
        /// Serialization implementation from ISerializationCallbackReceiver
        /// </summary>
        public void OnBeforeSerialize() {}

        /// <summary>
        /// Deserialization implementation from ISerializationCallbackReceiver
        /// </summary>
        public void OnAfterDeserialize()
        {
            Debug.Log("OnAfterDeserialize Loaded Count: " + serializedObjects.Count);
            foreach (string so in serializedObjects)
            {
                Debug.Log(so);
            }
        }

        #endregion

        public void AddSerializedObjects(List<ScriptableObject> scriptableObjects)
        {
            foreach(ScriptableObject so in scriptableObjects)
            {
                serializedObjects.Add(JsonUtility.ToJson(so));
            }

        }


        public List<ScriptableObject> GetStoredSerializedObjects()
        {

            //return JsonUtility.FromJsonOverwrite(serializedObjects.ToString(), new List<ScriptableObject>());

            List<ScriptableObject> temp = new List<ScriptableObject>();

            foreach (string so in serializedObjects)
            {

                //ScriptableObject file = ScriptableObject.CreateInstance(JsonUtility.FromJson<ScriptableObject>(so));
                var json = JsonUtility.FromJson<ScriptableObject>(so);
                //JsonUtility.FromJsonOverwrite(so, stemp);

                ScriptableObject file = ScriptableObject.CreateInstance((ScriptableObject)json);

                temp.Add(file);
            }
            return temp;
        }
    }

После того, как данные будут считаны из файла сохранения, я могу вывести их, чтобы увидеть данные SO.

enter image description here

Вот как выглядит SO

enter image description here enter image description here

DataManager

public class DataManager : MonoBehaviour
{

        public List<ScriptableObject> managedData = new List<ScriptableObject>();

        private DataStore m_Data;

        [NonSerialized]
        private IDataSaver m_Saver;

        private void Awake()
        {       
            m_Saver = new JsonSaver();
            m_Data = new DataStore();
            LoadData();
        }

        public void SaveData()
        {
            m_Data.AddSerializedObjects(managedData);
            m_Saver.Save(m_Data);
        }

        public void LoadData()
        {
            Debug.Log("LoadData()");
            m_Saver.Load(m_Data);
//Here is where I am trying to put the scriptable objects back
            //managedData.Clear();
            //managedData.AddRange(m_Data.GetStoredSerializedObjects()));
            //managedData =  m_Data.GetStoredSerializedObjects();
        }
}

IDataSaver

public interface IDataSaver {
        void Save(DataStore data);
        bool Load(DataStore data);
}

JsonSaver

public class JsonSaver : IDataSaver {

        private static readonly string s_Filename = "data_editor.sav";
    public static string GetSaveFilename()
    {
        return string.Format("{0}/{1}", Application.persistentDataPath, s_Filename);
    }

    protected virtual StreamWriter GetWriteStream() {
        return new StreamWriter(new FileStream(GetSaveFilename(), FileMode.Create));
    }

    protected virtual StreamReader GetReadStream() {
        return new StreamReader(new FileStream(GetSaveFilename(), FileMode.Open));
    }

    public void Save(DataStore data) {
        string json = JsonUtility.ToJson(data);
        using (StreamWriter writer = GetWriteStream()) {
            writer.Write(json);
        }
    }

    public bool Load(DataStore data) {
        string loadFilename = GetSaveFilename();
        if (File.Exists(loadFilename)) {
            using (StreamReader reader = GetReadStream()) {
                JsonUtility.FromJsonOverwrite(reader.ReadToEnd(), data);
            }

            return true;
        }

        return false;
    }
}

1 Ответ

0 голосов
/ 03 июля 2019

Прежде чем говорить о вопросе, я предлагаю, если вы решите использовать json для выполнения (де) сериализации работ, вам лучше использовать пользовательский класс с SerializableAttribte, ScriptableObject содержит данные otiose, как вы можете видеть как GUID .

Я пробовал варианты на JsonUtility.FromJsonOverwrite и JsonUtility.FromJson, но не смог заставить его работать.

Они оба могут работатьпроблема в том, что вы не можете десериализовать текст (строку json) обратно в объект ScriptableObject, поскольку процесс сериализации json не включает информацию о типе, вам нужно записать его самостоятельно.

Примерпишите

foreach(ScriptableObject so in scriptableObjects)
{
    string name = so.GetType().Name;
    serializedObjects.Add(name); // Record the type name
    serializedObjects.Add(JsonUtility.ToJson(so));
}

При прочтении

string name = serializedObjects[0]; // The recorded type name
string json = serializedObjects[1];
ScriptableObject so = ScriptableObject.CreateInstance(name);
JsonUtility.FromJsonOverwrite(json, so);
...