Why can't Unity write the structs/classes I made to JSON? - c#

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();

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();

Related

How to get property value of object which is in object array from another class

I want to get property value of an object which is in object array from another class. I tried to use reflection, but I had to do something wrong...
My code:
//Map.cs
//in BoardTiles i keep objects of classes which have property "Name" and I want to get it.
public class Map
{
public int Rows { get; private set; }
private int Cols { get; set; }
public Object[,] BoardTiles { get; private set; }
private Floor Floor { get; set; }
private PlayerTile PlayerTile { get; set; }
private Sword OldSword { get; set; }
public Map()
{
this.Rows = 10;
this.Cols = 40;
this.BoardTiles = new Object[Rows, Cols];
this.Floor = new Floor();
this.PlayerTile = new PlayerTile();
this.OldSword = new Sword("oldSword", 5);
}
//Sword.cs
//this is what the sword class looks like, object of this class is stored in BoardTiles
{
public class Sword : Tile
{
public override string Type { get; set; }
public string Name { get; set; }
public int Dmg { get; set; }
public Sword(string name, int dmg)
{
this.Type = "sword";
this.Name = name;
this.Dmg = dmg;
}
}
}
//Program.cs
case ConsoleKey.Spacebar:
Console.Clear();
map.getItem(playerPositionX, playerPositionY);
/* map.movefill(playerPositionX, playerPositionY);
*/ map.printBoard();
Console.Write(map.BoardTiles[playerPositionX, playerPositionY]);
**//Place where i need value of property of object from array of objects**
break;
}
}
I'm doing a dungeon crawler and when the player steps over a tile with an item he can pick the item, so the situation is - player is on the item tile which is an index in an array of objects and I want to know the name of this object. 

Removing duplicate lines from a list based on specific columns

I believe that this is similar to this but I was not able to apply the same solution.
I have a list with several columns:
public struct InfoForGraph
{
public float a{ get; set; }
public double b{ get; set; }
public double c { get; set; }
public double d { get; set; }
public double e { get; set; }
public double f { get; set; }
public double g { get; set; }
public double h { get; set; }
public double i { get; set; }
public double j { get; set; }
}
I would like to remove duplicate lines from this list but only if specific fields match. If I do a distinct with the whole table, these lines will not be erased. Also, I don't care with the repeated lines, I just wanna keep one of them.
Input:
2.67|1.84|420|400|1608039|808|3117|1|2|3|4
2.68|1.84|420|401|1608039|808|3269|1|2|3|4
Output expected:
2.67|1.84|420|400|1608039|808|3117|1|2|3|4
So, if columns 1,2,5,6,8,9,10 have the same value, I should keep only the first return (deleting the 2nd, 3rd, where all these fields match.)
Any ideas?
For simplicity, I narrowed down your condition to say that two objects are equal if InfoForGraph.b and InfoForGraph.c are equal. You get the idea and change your comparer as you like.
public class InfoComparer : IEqualityComparer<InfoForGraph>
{
public bool Equals(InfoForGraph x, InfoForGraph y)
{
if (x.b == y.b && x.c == y.c)
return true;
else
return false;
}
public int GetHashCode(InfoForGraph obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + obj.b.GetHashCode();
hash = hash * 23 + obj.c.GetHashCode();
return hash;
}
}
}
Then call Distinct() on it.
var unique = list.Distinct(new InfoComparer());

C# JSON to object (or array)

I'm trying to get pos 'x' and 'y' from JSON file (a part of STL file with coordinates of polygons) to array or object using newtonsoft package but unsuccessfully.
That looks my original file and converted by JSON online
I've read this but gives me a lots of errors.
Would you give me some tips or example ?
Thanks in advance
try
{
using (StreamReader reader = new StreamReader("test.json"))
{
json = reader.ReadToEnd();
List<vertex> items = JsonConvert.DeserializeObject<List<vertex>>(json);
}
dynamic array = JsonConvert.DeserializeObject(json);
foreach (var vert in array)
{
Console.WriteLine("{0} {1}", vert.x, vert.y);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
public class vertex
{
public double x,y;
}
The file for deserializing into the class you're using should be in the format
[{ "x" : 1.3214, "y" : 0.13241},{ "x" : 3.4324, "y" : 0.324}]
For deserializing the file you have, it shoud have a class as:
public class Coordinates {
public decimal Z { get; set; }
public List<Point> Polygons { get; set; }
}
public class Point{
public List<vertex> points { get; set; }
}
public class vertex{
public List<decimal> Vertices { get; set; }
public decimal x { get {return Vertices?[0]} }
public decimal y { get {return Vertices?[1]} }
}
This worked perfectly ;)
public class Polygonn
{
public List<List<double>> points { get; set; }
public string type { get; set; }
}
public class RootObject
{
public double z { get; set; }
public List<Polygonn> polygons { get; set; }
}
string data = System.IO.File.ReadAllText("backup.json");
RootObject json = JsonConvert.DeserializeObject<RootObject>(data);
json.polygons[polygon].points[0].ElementAt(0)
Thanks for everyone!
Regards

FlatBuffers KeyValuePair data type and schema definition

I have an object that I need to send over the network using TCP. I had this working fine, but I have now expanded on my implementation and am having trouble working out how to define my FlatBuffer schema.
The object to be sent is this:
public class Prediction
{
public PredictionMethod PredictionMethod { get; set; }
public NGramPrediction NGramPrediction { get; set; }
public DistancePrediction DistancePrediction { get; set; }
public int NGramOrder { get; set; }
}
PredictionMethod is an enum:
public enum PredictionMethod
{
Distance = 1,
NGram = 2,
}
NGramPrediction looks like this:
public class NGramPrediction
{
public KeyValuePair<char, int> Gram { get; set; }
public double Probability { get; set; }
public string Pattern { get; set; }
private int Total { get; set; }
private int Order { get; set; }
public NGramPrediction(Gram gram)
{
Total = gram.Total();
var orderedKeyPosibilities = gram.Posibilities.OrderByDescending(x => x.Value);
Gram = orderedKeyPosibilities.First();
Pattern = gram.Pattern;
Probability = (double)Gram.Value / Total;
Order = Pattern.Length;
}
}
Gram looks like this:
public class Gram
{
public string Pattern { get; set; }
public Dictionary<char, int> Posibilities { get; set; }
public Gram(List<char> posibilities, int initialValue = 0)
{
Posibilities = new Dictionary<char, int>();
foreach (var posibility in posibilities)
{
Posibilities.Add(posibility, initialValue);
}
}
public int Total()
{
var keys = Posibilities.Keys;
var total = 0;
foreach (var key in keys)
{
var value = Posibilities[key];
total += value;
}
return total;
// return keys.Sum(key => Posibilities[key]);
}
}
DistancePrediction looks like this:
public class DistancePrediction
{
public IIRVector3 Velocity { get; set; }
public float DeltaTime { get; set; }
public IIRVector3 Position { get; set; }
}
and finally, IIRVector3 looks like this:
public class IIRVector3
{
public IIRVector3()
{
X = 0;
Y = 0;
Z = 0;
}
public float X { get; set; }
public float Y { get; set; }
public float Z { get; set; }
}
I'm trying to define my schema for FlatBuffers:
enum FBPredictionMethod
{
Distance = 1,
NGram = 2
}
struct FBIIRVector3
{
X:float;
Y:float;
Z:float;
}
table FBDistancePrediction
{
Velocity:FBIIRVector3;
DeltaTime:float;
Position:FBIIRVector3;
}
table FBGram
{
Pattern:string;
Possibilities: ????
}
table FBNGramPrediction
{
Gram: ????
Probability:float;
Pattern:string;
Total:short;
Order:short;
}
table FBPrediction
{
PredictionMethod:FBPredictionMethod;
NGramPrediction:FBNGramPrediction;
DistancePrediction:FBDistancePrediction;
NGramOrder:short;
}
root_type FlatServerToClientMessage;
I think everything looks correct, but I have no idea what to do for the dictionaries...
FBGram.Possibilities should be a Dictionary<char, int> and FBGram should be KeyValuePair<char, int>.
Note: Gram's constructor takes a List<char> and an int as parameters, while the constructor for NGramPrediction takes a Gram as a parameter.
Could someone help me with my schema, please?
The KeyValuePair should be easy.. either just store them as two seperate fields, or use a struct KeyValuePair { key:byte; value:int; }
The Dictionary could be stored as Possibilities:[KeyValuePair] (using that same struct). If you wanted to save space if Possibilities can be large, then PossibilityKeys:[byte] and PossibilityValues:[int] will be a little bit more compact, but harder to read/write.

Convert meters to kilometers and format the value in Viewmodel

I have the Viewmodel:
public class PartnerSearchResultVM
{
public int Id { get; set; }
public string Name { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
public double Distance { get; set; }
public string Classification { get; set; }
}
I get the distance in meters from the database like this: 2354,58764478263 m
I would like to present 2.35 km
How change the Viewmodel to make the convertion there (if it's the best place to do it)
I'd add a read-only property to your model.
public double Kilometers { get { return this.Distance / 1000; } }
If you want a formatted string back I'd create a second readonly property.
public string KilometerDisplay {
get {
return String.Format("{0:0.00}km", this.Kilometers);
}
}
Although, depending on your use case, a generalized format function might be appropriate. Perhaps as an extension method:
[Extension]
public string FormatDistance(this double distance) {
return distance.FormatDistance("");
}
[Extension]
public string FormatDistance(this double distance, string unitString) {
return return String.Format("{0:0.00}{1}", distance, unitString);
}
// for meters: result.Distance.FormatDistance("m");
// for kilometers: result.Kilometers.FormatDistance("km");
Then add some XML documentation to the Distance property explaining that it is in meters.

Categories