0

I am almost done with my Text Based Adventure Game and am trying to setup a Save/Load system that works. I can't seem to accomplish this.

I have viewed multiple tutorials and I feel that Json may be what I need. Unfortunately I can't seem to get Json code correct for the 'Load' part. I am also concerned that the amount of data I am trying to save is too much for a simple Serialization process OR I am over-complicating this and there is a simpler solution.

This is the data I am tryin to Save/Load. As you can see I have Dictionaries and Lists, as well as a 'Room' ScriptableObject that I am trying to save, namely, the currentRoom the Player is in when the game is saved. The currentRoom is tracked in the GameController.

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

[System.Serializable]
public class SaveData
{
public Room saveRoomNavigation;
public List<string> saveNounsInInventory = new List<string>();
public List<InteractableObject> saveUseableItemList = new 
List<InteractableObject>();
public Dictionary<string, string> saveExamineDictionary = new 
Dictionary<string, string>();
public Dictionary<string, string> saveTakeDictionary = new 
Dictionary<string, string>();
public List<string> saveNounsInRoom = new List<string>();
public Dictionary<string, ActionResponse> saveUseDictionary = new 
Dictionary<string, ActionResponse>();


public SaveData (GameController controller, InteractableItems 
interactableItems)
{
    saveRoomNavigation = controller.roomNavigation.currentRoom;
    saveNounsInInventory = interactableItems.nounsInInventory;
    saveUseableItemList = interactableItems.useableItemList;
    saveExamineDictionary = interactableItems.examineDictionary;
    saveTakeDictionary = interactableItems.takeDictionary;
    saveNounsInRoom = interactableItems.nounsInRoom;
    saveUseDictionary = interactableItems.useDictionary;

}


}

Then this is my Save System code where I am trying to implement the Serialization with Json and binary.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public static class SaveSystem
{
public static void SaveGame (GameController controller, 
InteractableItems interactableItems)
{
    BinaryFormatter formatter = new BinaryFormatter();

    string path = Application.persistentDataPath + "/savegame.rta";
    FileStream stream = new FileStream(path, FileMode.Create);

    SaveData data = new SaveData(controller, interactableItems);

    var json = JsonUtility.ToJson(data);
    formatter.Serialize(stream, json);
    stream.Close();
}

public static SaveData LoadGame()
{
    string path = Application.persistentDataPath + "/savegame.rta";
    if (File.Exists(path))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        FileStream stream = new FileStream(path, FileMode.Open);

        SaveData data = 
JsonUtility.FromJsonOverwrite((string)formatter.Deserialize(stream, 
????));
        //SaveData data = formatter.Deserialize(stream) as 
SaveData;
        stream.Close();

        return data;

    }
    else
    {
        Debug.LogError("Save file not found in " + path);
        return null;
    }
}
}

Where I put the '????' above is where I can't seem to get it to accept the Object I am trying to overwrite, which I thought was 'SaveData' since that is where I pull the information to put into the game when the Player clicks the 'Load' button. It tell me "'SaveData' is a type, which is not valid in the given context"

Here is the code I call when the 'Save' and 'Load' buttons are used, it is within my GameController Class where most everything is tracked during Game Play.

public void SaveGame()
{
    SaveSystem.SaveGame(this, interactableItems);
}

public void LoadGame()
{
    SaveData data = SaveSystem.LoadGame();

    roomNavigation.currentRoom = data.saveRoomNavigation;

    interactableItems.nounsInInventory = data.saveNounsInInventory;
    interactableItems.useDictionary = data.saveUseDictionary;
    interactableItems.takeDictionary = data.saveTakeDictionary;
    interactableItems.examineDictionary = 
    data.saveExamineDictionary;
    interactableItems.useableItemList = data.saveUseableItemList;
    interactableItems.nounsInRoom = data.saveNounsInRoom;


    DisplayRoomText();
    DisplayLoggedText();

}

When used in game, I get "SerializationException" errors, so that is when I attempted to try Json. I read where it can serialize a lot more than the basic Unity Serializer. The errors went away and it seems to save OK with Json, but now I am unable to get the Load syntax correct.

I am a novice so maybe I am making this harder then it has to be... I also looked into Userprefs, but I don't think I can convert the Scriptable Object, Room, into a type String.

Thanks in advance!

[UPDATE] Here is what I am able to have it save in .txt format. This proves that it is saving, just not sure "instanceIDs" will give me the Load that I need.

ˇˇˇˇö{"saveRoomNavigation": {"instanceID":11496},"saveNounsInInventory": ["sword"],"saveUseableItemList":[{"instanceID":11212}, {"instanceID":11588},{"instanceID":10710},{"instanceID":11578}, {"instanceID":10718},{"instanceID":11388}, {"instanceID":11276}],"saveNounsInRoom":["rocks","hole"]}

Brantley
  • 33
  • 7
  • You don't need to use the second parameter of the deserialize for BinaryFormatter, that is a HeaderHandler it can be null or you can simple omit it. Would be useful you add the exact error(full message) you get when loading the file as well. what do you get if you do `var test = (string)formatter.Deserialize(stream);`? breakpoint at it, and walk in. Have you also ensured you're saving something and that your save file is not empty? – Prix Aug 16 '19 at 18:42
  • Is `JsonUtility.FromJsonOverwrite((string)formatter.Deserialize(stream, ????));` a typo? Are you asking about the second parameter of `BinaryFormatter.Deserialize` or the second parameter of `JsonUtility.FromJsonOverwrite`? – Joe Aug 16 '19 at 18:45
  • @Prix Thanks! I should have clarified this better. The errors I am getting are for 'Saving'. I only asked the question for the Load code because I have Syntax errors on it. I will try putting Null or omit the Object in the code and see what that does. – Brantley Aug 16 '19 at 18:51
  • @Joe no it is not a typo, I just can't seem to get the right Object for the JsonUtility.FromJsonOverwrite, which I thought was my SaveData class that I pull the information from when the player Loads a game. – Brantley Aug 16 '19 at 18:53
  • @Brantley I'm getting confused, your question clearly states you're having issues on the load side but you've just commented that you have errors for saving instead. Could you update your question to clarify this? – Joe Aug 16 '19 at 19:06
  • @Prix I did a Debug.Log to get to the saved file and it is indeed saving items... Now I just need to get the Load syntax fixed... – Brantley Aug 16 '19 at 19:13
  • @Joe yes, sorry. I am getting errors with the Load syntax and the Save errors have cleared, I should of re-worded it to just Load and the possibility of a better Save/Load method as a whole if I am going about this in a difficult manner. – Brantley Aug 16 '19 at 19:15
  • @Joe I am asking the second parameter of 'JsonUtility.FromJsonOverwrite' the syntax will not allow me to put my SaveData class in as the object to Overwrite, nor will it work with Prix's suggestion of putting it as null or omitting it. – Brantley Aug 16 '19 at 19:35

1 Answers1

1

Take a look at the documentation for Unity's built-in JsonUtility:

https://docs.unity3d.com/Manual/JSONSerialization.html

It says types such as "Dictionaries" are not supported. Seeing as though you have several Dictionaries in your SaveData example, might I suggest using a more robust JSON library such as JSON.NET, which is free on the asset store:

https://assetstore.unity.com/packages/tools/input-management/json-net-for-unity-11347

jfish
  • 81
  • 1
  • 4
  • thanks for this suggestion! I had not heard of JSON.NET from the asset store. I will look into that now. – Brantley Aug 16 '19 at 19:18