JSon saving system

Hi there,

Was wondering if there was a way to save game objects once being turned off such as gates or portals etc?
I tried adding a different json saveable entity to each npc that “moves” around by dialogue (by being turned off and reappearing in other locations as if saved etc) but when I am loading the original NPC appears.

I have seen this solution however its got the old saving system was wondering if there was something that could be done to convert this to the JsonSaveableEntity.

Appreciate the help.

Thank you.

using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;

namespace GameDevTV.Saving
{
    [ExecuteAlways]
    public class ManagedSaveableEntity : MonoBehaviour
    {
        [SerializeField] string uniqueIdentifier = "";

        // CACHED STATE
        static Dictionary<string, ManagedSaveableEntity> globalLookup = new Dictionary<string, ManagedSaveableEntity>();

        public string GetUniqueIdentifier()
        {
            return uniqueIdentifier;
        }

        public JToken CaptureAsJtoken()
        {
            JObject state = new JObject();
            IDictionary<string, JToken> stateDict = state;
            foreach (IJsonSaveable jsonSaveable in GetComponents<IJsonSaveable>())
            {
                JToken token = jsonSaveable.CaptureAsJToken();
                string component = jsonSaveable.GetType().ToString();
                Debug.Log($"{name} Capture {component} = {token.ToString()}");
                stateDict[jsonSaveable.GetType().ToString()] = token;
            }
            return state;
        }

        public void RestoreFromJToken(JToken s)
        {
            JObject state = s.ToObject<JObject>();
            IDictionary<string, JToken> stateDict = state;
            foreach (IJsonSaveable jsonSaveable in GetComponents<IJsonSaveable>())
            {
                string component = jsonSaveable.GetType().ToString();
                if (stateDict.ContainsKey(component))
                {
                    Debug.Log($"{name} Restore {component} =>{stateDict[component].ToString()}");
                    jsonSaveable.RestoreFromJToken(stateDict[component]);
                }
            }
        }

#if UNITY_EDITOR
        private void Update()
        {
            if (Application.IsPlaying(gameObject)) return;
            if (string.IsNullOrEmpty(gameObject.scene.path)) return;

            SerializedObject serializedObject = new SerializedObject(this);
            SerializedProperty property = serializedObject.FindProperty("uniqueIdentifier");

            if (string.IsNullOrEmpty(property.stringValue) || !IsUnique(property.stringValue))
            {
                property.stringValue = System.Guid.NewGuid().ToString();
                serializedObject.ApplyModifiedProperties();
            }

            globalLookup[property.stringValue] = this;
        }
#endif

        private bool IsUnique(string candidate)
        {
            if (!globalLookup.ContainsKey(candidate)) return true;

            if (globalLookup[candidate] == this) return true;

            if (globalLookup[candidate] == null)
            {
                globalLookup.Remove(candidate);
                return true;
            }

            if (globalLookup[candidate].GetUniqueIdentifier() != candidate)
            {
                globalLookup.Remove(candidate);
                return true;
            }

            return false;
        }
    }
}``` I duplicated the JasonSaveableEntity, created a new script and named it like this. 

Than created a new script and called it SaveableEntityManager 
```using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json.Linq;
using GameDevTV.Saving;

    public class SaveableEntityManager : MonoBehaviour
    {
        private Dictionary<ManagedSaveableEntity, bool> manageableEntities = new Dictionary<ManagedSaveableEntity, bool>();
        private bool stateWasRestored = false;

        private void Awake()
        {
            for (int i = 0; i < transform.childCount; i++)
            {
                if (transform.GetChild(i).TryGetComponent(out ManagedSaveableEntity entity))
                {
                    manageableEntities[entity] = entity.gameObject.activeSelf;
                    entity.gameObject.SetActive(true);  //Set active to ensure Awake() runs!
                }
            }
        }

        void OnEnable()
        {
            if (stateWasRestored) return;
            foreach (KeyValuePair<ManagedSaveableEntity, bool> pair in manageableEntities)
            {
                pair.Key.gameObject.SetActive(pair.Value);
            }
            stateWasRestored = true;
        }

        [System.Serializable]
        public struct ManagedEntity
        {
            public object state;
            public bool isActive;
        }

        public JToken CaptureAsJtoken()
        {
            JObject state = new JObject();
            IDictionary<string, JToken> stateDict = state;
            foreach (KeyValuePair<ManagedSaveableEntity, bool> pair in manageableEntities)
            {
                JToken token = pair.Key.CaptureAsJtoken();
                string component = pair.Key.GetType().ToString();
                Debug.Log($"{pair.Key.name} Capture {component} = {token.ToString()}");
                stateDict[component] = token;
            }
            return state;
        }

        public void RestoreFromJToken(JToken s)
        {
            JObject state = s.ToObject<JObject>();
            IDictionary<string, JToken> stateDict = state;
            foreach (KeyValuePair<ManagedSaveableEntity, bool> pair in manageableEntities)
            {
                string component = pair.Key.GetType().ToString();
                if (stateDict.ContainsKey(component))
                {
                    Debug.Log($"{pair.Key.name} Restore {component} =>{stateDict[component].ToString()}");
                    pair.Key.RestoreFromJToken(stateDict[component]);
                }
            }
        }
    }

Added it to the characters and objects that I may want to store there state. So to explain what I am trying to do here is create an object as part of the character like a exclamation mark to show the players that this NPC has got a quest for them. When I complete the dialogue I am turning this off. All this is ok. When I quick save, and quick reload the exclamation mark is still fine dissapeared. But when I click save and exit. Than return by pressing continue to reload the last save thats when everything sort of resets. Problem is I sometimes want to get a door open if an enemy was killed. If this enemy is killed but the door returns to being closed thats a problem. It kind of hinders the gameplay a little. I dont know if I am explaining it very well. Also same issue with NPCs sometimes I will have a dialogue which moves npcs to safe location. But continuing the game resets it to the original location of the NPC.
Sorry for my bad English.Any help would be appreciated.

I was able to edit the JsonSaveableEntity and this seems to work for my needs.

        public JToken CaptureAsJtoken()
        {
            JObject state = new JObject();
            // Store position and rotation
            state["position"] = new JArray(transform.position.x, transform.position.y, transform.position.z);
            state["rotation"] = new JArray(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z);

            // Store active state
            state["isActive"] = gameObject.activeSelf;
            Debug.Log($"Capturing gate active state: {gameObject.activeSelf}");

            // Capture child's active state
            Transform childTransform = transform.Find("Quest Marker");  // Replace "ChildName" with the name of your child object
            if (childTransform != null)
            {
                state["childActive"] = childTransform.gameObject.activeSelf;
                Debug.Log($"Capturing child active state: {childTransform.gameObject.activeSelf}");
            }

            IDictionary<string, JToken> stateDict = state;
            foreach (IJsonSaveable jsonSaveable in GetComponents<IJsonSaveable>())
            {
                JToken token = jsonSaveable.CaptureAsJToken();
                string component = jsonSaveable.GetType().ToString();
                Debug.Log($"{name} Capture {component} = {token.ToString()}");
                stateDict[jsonSaveable.GetType().ToString()] = token;
            }
            return state;
        }

        public void RestoreFromJToken(JToken s)
        {
            JObject state = s.ToObject<JObject>();
            if (state["isActive"] != null)
            {
                bool isActive = state["isActive"].Value<bool>();
                gameObject.SetActive(isActive);
                Debug.Log($"Restoring gate active state: {isActive}");
            }

            // Restore position and rotation
            if (state["position"] != null && state["rotation"] != null)
            {
                transform.position = new Vector3(state["position"][0].Value<float>(), state["position"][1].Value<float>(), state["position"][2].Value<float>());
                transform.eulerAngles = new Vector3(state["rotation"][0].Value<float>(), state["rotation"][1].Value<float>(), state["rotation"][2].Value<float>());
            }

            // Restore active state
            if (state["isActive"] != null)
            {
                gameObject.SetActive(state["isActive"].Value<bool>());
            }
            // Restore child's active state
            if (state["childActive"] != null)
            {
                Transform childTransform = transform.Find("Quest Marker");  // Replace "ChildName" with the name of your child object
                if (childTransform != null)
                {
                    childTransform.gameObject.SetActive(state["childActive"].Value<bool>());
                    Debug.Log($"Restoring child active state: {state["childActive"].Value<bool>()}");
                }
            }
            IDictionary<string, JToken> stateDict = state;
            foreach (IJsonSaveable jsonSaveable in GetComponents<IJsonSaveable>())
            {
                string component = jsonSaveable.GetType().ToString();
                if (stateDict.ContainsKey(component))
                {

                    Debug.Log($"{name} Restore {component} =>{stateDict[component].ToString()}");
                    jsonSaveable.RestoreFromJToken(stateDict[component]);
                }
            }
        }

I think I found my own solution :slight_smile: sorry for the many replies. It seems to work no errors.

WELL DONE!
Sorry I didn’t get to this sooner, but it appears you nailed this one all on your own.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms