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.