0

a bit long but everything is connected.

I have a script type editor that with right mouse click I can add to a gameobject a script that add to the selected gameobject/s a special id:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class GenerateAutomaticGuid : Editor
{
    [MenuItem("GameObject/Generate Guid", false, 11)]
    private static void GenerateGuid()
    {
        foreach (GameObject o in Selection.gameObjects)
        {
            var g = o.GetComponent<GenerateGuid>();
            if (!g)
            {
                g = o.AddComponent<GenerateGuid>();
                g.GenerateGuidNum();
            }
        }
    }
}

The GenerateGuidNum method:

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

public class GenerateGuid : MonoBehaviour
{
    public string uniqueGuidID;

    private Guid guidID;
   
    public void GenerateGuidNum()
    {
        guidID = Guid.NewGuid();
        uniqueGuidID = guidID.ToString();
    }
}

For example, a gameobject with id:

gameobject with gui id

when I'm saving the game it's creating a text save game and store information including the gameobjects id:

This is part of the saved game text file content:

{"saveObjects":[{"componentsState":[],"gameObjectUniqueID":"b7fbc192-0312-4822-b62d-4a35a212f639","transformSaver":{"position":{"x":-17.84672737121582,"y":1.129213809967

the problem is if someone even me that use this save system delete the object with the unique id or only removed the GenerateGuid script with the unique id from the object.

then when loading the saved game file, it can't find the unique id. the unique id is stored in the text file but not exist in the hierarchy on any object.

how should I handle that case?

example of error:

KeyNotFoundException: The given key 'd9687717-cef7-4e6c-8318-20bcc51e0110' was not present in the dictionary.
System.Collections.Generic.Dictionary`2[TKey,TValue].get_Item (TKey key) (at <1f66344f2f89470293d8b67d71308c07>:0)
SaveLoad.Load (System.String fileName) (at Assets/My Scripts/Save System Scripts/SaveLoad.cs:130)

and this is the SaveLoad script line 130:

zz[keyvalue.Key].SetState(keyvalue.Value);

and the full script:

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

public class SaveLoad : MonoBehaviour
{
    public FadeInOutSaveGameText fadeInOutSaveGame;
    public float timeToStartSaving;
    public float savingFadeInOutTime;
    public int resWidth = 1920;
    public int resHeight = 1080;

    [Tooltip("If true will save manualy only by the left control key.")]
    public bool saveManual = false;

    private List<GameObject> objectsToSave;
    private string saveString;

    private void Awake()
    {
        if (objectsToSave == null)
        {
            objectsToSave = new List<GameObject>();
        }

        var objectsWithGenerateGuid = GameObject.FindObjectsOfType<GenerateGuid>().ToList();
        if (objectsWithGenerateGuid.Count > 0 && objectsToSave.Count == 0)
        {
            for (int i = 0; i < objectsWithGenerateGuid.Count; i++)
            {
                objectsToSave.Add(objectsWithGenerateGuid[i].gameObject);
            }
        }

        Debug.Log("Start");

        for (int i = 0; i < objectsToSave.Count; i++)
        {
            Debug.Log($"{i}");
            Debug.Log($"{objectsToSave[i].name}");
        }

        Debug.Log("End Init");
    }

    public void Save()
    {
        SaveGame saveGame = new SaveGame();
        saveGame.saveObjects = new List<SaveObject>();
        for (int i = 0; i < objectsToSave.Count; i++)
        {
            SaveObject saveObject = new SaveObject();
            saveObject.transformSaver = new TransformSaver();
            
            Debug.Log($"{i}");
            Debug.Log($"{objectsToSave[i].name}");
            saveObject.gameObjectUniqueID = objectsToSave[i].GetComponent<GenerateGuid>().uniqueGuidID;
            var x = objectsToSave[i].GetComponents<Component>();
            var stateQueryComponent = x.Where(component => component is IStateQuery).ToList();
            List<KeyToValue> componentsState = new List<KeyToValue>();
            foreach (var z in stateQueryComponent)
            {
                var w = z as IStateQuery;
                componentsState.Add(new KeyToValue(w.UniqueId.ToString(), w.GetState()));
            }

            saveObject.transformSaver.position = objectsToSave[i].transform.position;
            saveObject.transformSaver.rotation = objectsToSave[i].transform.rotation;
            saveObject.transformSaver.scaling = objectsToSave[i].transform.localScale;

            saveObject.componentsState = componentsState;
            saveGame.saveObjects.Add(saveObject);
        }

        string json = JsonUtility.ToJson(saveGame);
        
        SaveSystem.Save(json, resWidth, resHeight);
    }

    public void Load(string fileName)
    {
        if (objectsToSave.Count > 0)
        {
            // Why objectsToSave here is empty ?
            Dictionary<string, GameObject> uniqueIdToObject = objectsToSave
                .ToDictionary(o => o.GetComponent<GenerateGuid>().uniqueGuidID, o => o);

            saveString = SaveSystem.Load(fileName);

            if (saveString != null)
            {
                SaveGame saveGame = JsonUtility.FromJson<SaveGame>(saveString);

                if (saveGame != null)
                {
                    foreach (var saveObject in saveGame.saveObjects)
                    {
                        List<KeyToValue> loadedComponents = saveObject.componentsState;
                        var objectToSetState = uniqueIdToObject[saveObject.gameObjectUniqueID];

                        objectToSetState.transform.position = saveObject.transformSaver.position;
                        objectToSetState.transform.rotation = saveObject.transformSaver.rotation;
                        objectToSetState.transform.localScale = saveObject.transformSaver.scaling;

                        var y = objectToSetState.GetComponents<Component>();
                        var z = y.Where(component => component is IStateQuery).ToList();
                        Dictionary<string, IStateQuery> zz = z.ToDictionary(sq => (sq as IStateQuery).UniqueId.ToString(), sq => sq as IStateQuery);

                        foreach (KeyToValue keyvalue in loadedComponents)
                        {
                            zz[keyvalue.Key].SetState(keyvalue.Value);
                        }
                    }
                }
            }
        }
    }

    public IEnumerator SaveWithTime()
    {
        yield return new WaitForSeconds(timeToStartSaving);

        if (objectsToSave.Count == 0)
        {
            Debug.Log("No objects selected for saving.");
        }

        if (saveManual == false && objectsToSave.Count > 0)
        {
            Save();
            StartCoroutine(fadeInOutSaveGame.OverAllTime(savingFadeInOutTime));
        }
    }

    public IEnumerator SaveWithTimeManual()
    {
        yield return new WaitForSeconds(timeToStartSaving);

        if (objectsToSave.Count == 0)
        {
            Debug.Log("No objects selected for saving.");
        }

        if (saveManual && objectsToSave.Count > 0)
        {
            Save();
            StartCoroutine(fadeInOutSaveGame.OverAllTime(savingFadeInOutTime));
        }
    }
}
  • Does this answer your question? [Best way to handle a KeyNotFoundException](https://stackoverflow.com/questions/606636/best-way-to-handle-a-keynotfoundexception) – hijinxbassist Apr 26 '23 at 21:52
  • @hijinxbassist that's solving the error, but it does not solve the handling of the problem that the key is still exist in the save game text file. maybe I didn't explain it good enough in my question, but the question is how to solve the error but also how to handle it in the saved game text file. – Sheron Blumental Apr 26 '23 at 22:48
  • 1
    When you save again, it should remove the entry since the object does not exist. Does it matter if the entry is in the save file? If you really want to remove it immediately, you can have a list of game objects, when TryGetValue fails, add the GO to the list and after loading remove those GOs from the saveObjects. But if you are going to save over the file later anyway, it probably doesn't matter. – hijinxbassist Apr 26 '23 at 22:57

0 Answers0