-2

I'm working on a game that uses a grid of hex-shaped tiles. The tiles are saved as this class:

[System.Serializable]
public class Tile
{
    public Hex location;

    public TerrainType terrainType;

    public Color color { get { return terrainType.color; } }

    public int distance;

    public string label;

    public int cost { get { return terrainType.baseMPCost; } }

    public int new_cost;
}

Hex is this struct, used to mark the coordinates of the tile in the hex grid:

public struct Hex
{
    //private int _q, _r; originally this used a getter/setter for some reason


    public int q;

    public int r;


    public Hex (int Q, int R)
    {
        q = Q;
        r = R;
    }

    public int s
    {
        get { return -q - r; }
    }

    public float x
    {
        get { return (3f / 2f) * HexMetrics.outerRadius * q; }
    }

    public float y
    {
        get { return (Mathf.Sqrt(3f) / 2f * HexMetrics.outerRadius * q + Mathf.Sqrt(3f) * HexMetrics.outerRadius * r); }
    }
}

Finally, TerrainType is this struct:

[System.Serializable]
public struct TerrainType
{
    public TerrainType(string Name, int BaseMPCost, Color Color)
    {
        name = Name;
        baseMPCost = BaseMPCost;
        color = Color;
    }
    public string name;
    public int baseMPCost;
    public Color color;
}

All of the tiles are saved as a list in my map script. I'm using the JsonHelper Script from the top comment on this thread, which writes the list to an array, producing this file.

However, loading the file with the same script gives this error:

ArgumentException: JSON parse error: Invalid value.
UnityEngine.JsonUtility.FromJson (System.String json, System.Type type) (at <1a491ffb1c7c42349a050cc1542277fb>:0)
UnityEngine.JsonUtility.FromJson[T] (System.String json) (at <1a491ffb1c7c42349a050cc1542277fb>:0)
JsonHelper.FromJson[T] (System.String json) (at Assets/Scripts/JsonHelper.cs:9)
InputStateMapEdit.HandleInput () (at Assets/Scripts/StateMachine/InputStates/InputStateMapEdit.cs:57)
InputManager.Update () (at Assets/Scripts/InputManager.cs:40)

When I paste the file into json2csharp.com, it interprets it like this:

 // Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
    public class Color
    {
        public double r { get; set; }
        public double g { get; set; }
        public double b { get; set; }
        public double a { get; set; }
    }

    public class Grid
    {
        public Location location { get; set; }
        public TerrainType terrainType { get; set; }
        public int distance { get; set; }
        public string label { get; set; }
        public int new_cost { get; set; }
    }

    public class Location
    {
        public int q { get; set; }
        public int r { get; set; }
    }

    public class Root
    {
        public int Width { get; set; }
        public int Height { get; set; }
        public List<Grid> Grid { get; set; }
    }

    public class TerrainType
    {
        public string name { get; set; }
        public int baseMPCost { get; set; }
        public Color color { get; set; }
    }

I'm not exactly sure why it can't convert this back into the structs and classes I wrote originally, but a lot of them seem to be renamed, are missing some data, etc. Also, the entire list of tiles doesn't appear at all, just their basic components. Is there something preventing them from being properly serialized and written to the JSON file? I think I could probably create another class that stores all the relevant data points as normal floats and integers, then create all new tiles based on them, but I don't want to do that for everything I try to save (especially scenarios, which will include units and such with lots of data) in the future.

Edit - Here is the actual code that writes the Json file:

var m = map.grid.ToArray();
string grid = JsonHelper.ToJson<Tile>(m);
File.WriteAllText("C:/SG/Strategy Game/Assets/test.json", grid);

And the code that reads it:

var m = JsonHelper.FromJson<Tile>("C:/SG/Strategy Game/Assets/test.json");
map.grid = m.ToList();
Augie
  • 11
  • 1
  • Could you include your code actually invoking the JsonUtility methods? You could be calling `FromJson` with the wrong type. (ex, serialized a list object, but trying to deserialize it as a Tile object) – ipodtouch0218 Aug 17 '22 at 18:17
  • @ipodtouch0218 Sure. The JsonHelper script seems to make objects into arrays, so if I make the type into a list or array, it gives me an error. I put the actual code at the bottom of the main post. – Augie Aug 17 '22 at 18:39

1 Answers1

1

The problem is that the JsonUtility doesn't support serializing just an array..

... Similarly, passing an array to this method will not produce a JSON array containing each element, but an object containing the public fields of the array object itself (of which there are none). To serialize the actual content of an array or primitive type, it is necessary to wrap it in a class or struct.


To serialize the array properly, we just need a small wrapper class:

[System.Serializable]
public class TileListWrapper {
    public Tile[] tiles;
}

and then we create a new TileListWrapper and serialize that instead:

var m = map.grid.ToArray();
var wrapper = new TileListWrapper() {
    tiles = m,
};
string grid = JsonUtility.ToJson<TileListWrapper>(wrapper);
File.WriteAllText("C:/SG/Strategy Game/Assets/test.json", grid);

and also deserialize into TileListWrapper:

var wrapper = JsonUtility.FromJson<TileListWrapper>("C:/SG/Strategy Game/Assets/test.json");
map.grid = wrapper.tiles.ToList();
ipodtouch0218
  • 674
  • 1
  • 2
  • 13
  • Thanks. I was under the impression that this is what the JsonHelper script I was already using did, but I'll try this as well. – Augie Aug 17 '22 at 19:14
  • Alright, I just tried this code (editing it slightly to use the default Unity JsonUtility since the JsonHelper script gave an error, as it automatically makes a wrapper with an array in it), but it gives me the same error (`JSON parse error: Invalid value`) as before. The [result](https://pastebin.com/Qfzen7WZ) is interpreted the same way as the one from my original post. I think I'm going to try some different JSON libraries on the asset store, since they might have somewhat better functionality than the inbuilt unity one anyway. – Augie Aug 17 '22 at 19:22
  • I wonder if your use of `"x, y"` for your label is messing with the JsonUtility... maybe it's messing up parsing in some edge case bug? – ipodtouch0218 Aug 17 '22 at 19:50