Parsing JSON with 2D arrays in Unity C# - c#

I am working with Unity and Python and sending data over UDP to my Unity client. I am sending a JSON which reaches my Unity application successfully. I can't figure out how to properly parse this JSON. I have tried :
JsonUtility.FromJson<T>(...)
but the result wasn't correct. I implemented a [System.Serializable] class which contained data types
List<List<int>> landmarks;
List<double> eulerAngles;
List<List<double>> boxPoints;
And initialized these in my constructor using
landmarks = new List<List<int>>();
...
Every time I try to print the result, all my variables are empty.
My JSON looks like this -
{
"eulerAngles": [6.2255, -15.8976, -0.5881],
"boxPoints": [
[194.05965, 194.15782],
[182.35829, 189.05042],
[6 more...]
],
"landmarks": [
[196, 225],
[197, 242],
[199, 258],
[65 more..]
]
}
Any help appreciated.

Your JSON is still strangly formatted and I don't understand your data structure.
Why are you storing everything in List<int[]> while the values you get are clearly float (or double) values?
If something it should probably be
[Serializable]
public class JsonData
{
// here maybe int is ok at least from your data it seems so
public List<int[]> landmarks = new List<int[]>();
// for those you clearly want floats
public List<float[]> eulerAngles = new List<float[]>();
public List<float[]> boxPoints = new List<float[]>();
}
Have a look at this JSON to c# converter!
BUT anyway Unity's JsonUtility seems not to support the deserialization of nested arrays and lists! I guess the reason is that while other primitive data types have a default value that is different from null, List and arrays are null be default and have to be initialized before filling them. JsonUtility seems to not support that. I think it is related to
Note that while it is possible to pass primitive types to this method, the results may not be what you expect; instead of serializing them directly, the method will attempt to serialize their public instance fields, producing an empty object as a result. 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. (JsonUtility.ToJson)
and
a field of type T will have value default(T) - it will not be given any value specified as a field initializer, as the constructor for the object is not executed during deserialization (JsonUtility.FromJson)
However, why even take them as arrays where every of your arrays only has one element anyway when it seems (and your names and title say) you rather want to store tuples of allways 2 and 3 numbers?
In case you can change the JSON format it seems like you rather would want something like
[Serializable]
public class JsonData
{
// here maybe int is ok at least from your data it seems so
public List<Vector2Int> landmarks = new List<Vector2Int>();
// for those you clearly want floats
public List<Vector3> eulerAngles = new List<Vector3>();
public List<Vector2> boxPoints = new List<Vector2>();
}
And your JSON should than rather look like
{
"eulerAngles": [
{"x":6.2255, "y":-15.8976, "z":-0.5881},
...
],
"boxPoints": [
{"x":194.05965, "y":194.15782},
{"x":182.35829, "y":189.05042},
...
],
"landmarks": [
{"x":196, "y":225},
{"x":197, "y":242},
{"x":199, "y":258},
...
]
}
The simplest way to see how your JSON should actually look like would be to take your JsonData class and serialize it once so you see what Unity expects as JSON.
var testData = new JsonData();
// fill it with example values
testData.eulerAngles = new List<Vector3>()
{
new Vector3(6.2255f, -15.8976f, -0.5881f)
};
testData.boxPoints = new List<Vector2>()
{
new Vector2(194.05965f, 194.15782f),
new Vector2(182.35829f, 189.05042f)
};
testData.landmarks = new List<Vector2Int>()
{
new Vector2Int(196, 225),
new Vector2Int(197, 242),
new Vector2Int(199, 258)
}
var result = JsonUtility.ToJson(testData);
If changing the JSON format is not an option you could instead have a look at SimpleJSON which doesn't deserialize directly into a class instance but rather to a JSONNode which can contain nested lists and arrays e.g.
var jsonData = JSON.Parse(yourJson);
var firstEuerAngles = jsonData["eulerAngles"][0];

Related

Why does deserialization append to an initialized `List<T>` instead of overwriting it?

I have a configuration-related data model which is required to have default values for all properties to ensure proper execution of consuming operations. Take for example this very simple model:
public class Sample {
public List<int> Integers { get; set; }
public Sample() =>
Integers = new List<int> { 1 };
}
This model is expected to contain at least one value so we specify a default processing value based on predefined requirements. However, the value doesn't have to be 1 specifically and if a client specifies a different value or many different values, our process should respect their input. Assume the client specifies the following json configuration to be deserialized into the model:
{
"integers": [ 2, 3 ]
}
During runtime, we load the configuration directly, but let's use a local string variable for the sake of this question:
using Newtonsoft.Json
...
string configuration = "{ \"integers\": [ 2, 3 ] }";
var sample = JsonConvert.DeserializeObject<Sample>(configuration);
Console.WriteLine(string.Join(",", sample.Integers));
The above code snippet should produce an output of:
1,2,3
As you can see in my screenshot below, that is the case:
However, my question is why... Why does the deserialization process append to the collection instead of overwriting it?
You can point how to deserialize the json
var serializerSettings = new JsonSerializerSettings {
ObjectCreationHandling = ObjectCreationHandling.Replace};
var sample = JsonConvert.DeserializeObject<Sample>(configuration,serializerSettings);
Console.WriteLine(string.Join(",", sample.Integers)); // [2,3]
by default it is auto, and if there is something it tries to add.

C# Unity JsonUtility, how can I turn this simple json into some kind of useful c# object?

I'm very confused about the Unity JsonUtility, mainly due to lack of c# understanding.
All their examples are with very non generic classes, but I need flexibility, and havent been able to find a good e2e example that worked for me.
I have this simple json data that I need to work with:
"{
1: 987,
2: 123,
3: 001,
4: 157,
}"
It's a key value object where both key and value are integers.
My problem is that the size of the object is unknow, the index could be ever increasing, and I do not understand how I can define a generic object (class?) in c# that JsonUtility can convert. Do I need to define a class, or can I do it inline? Do I need to define getters and setter, or are there some convenient wildcard dictionary like thingy that would be suitable?
I'm trying to achieve something like this:
string jsonString = "{1:987,2:123,3:001,4:157}":
var object = JsonUtility.FromJson<??????>(jsonString);
Debug.Log(object[1]) // 987
Debug.Log(object[99]) // undefined
And then I would like to be able to add new pair to the object and at last turn it into json again something like:
object[100] = 999;
const jsonString = JsonUtility.ToJson<??????>(object);
Debug.Log(jsonString) // "{1:987,2:123,3:001,4:157,100:999}":
KeyValuePairs or Dictionary is not supported by the built-in JsonUtility.
You can use Newtonsoft .Net JSON (there is a wrapper Package for Unity) where this would be a simple Dictionary<int, int>
var json = "{1:987,2:123,3:001,4:157}":
var values = JsonConvert.DeserializeObject<Dictionary<int, int>>(json);
Debug.Log(values [2]);
and
var values = new Dictionary<int, int>{ { 2, 123 }, {7, 345} };
var json = JsonConvert.SerializeObject(values);
Debug.Log(json);

C#'s version of JS's JSON [duplicate]

This question already has answers here:
Serialize and Deserialize Json and Json Array in Unity
(9 answers)
Closed 3 years ago.
I recently got into C# using Unity. I previously worked with JavaScript and know that they defiantly have their differences, but still have some similarities. I have used JSON with JS and it works great. Now with Unity, I want to store data of upcoming "stages" in JSON in an infinite runner game. But from my experience, JSON does not work nearly as well with C# as it does with JS. I have looked at Unity's JSON Utility but haven't figured out if it's possible to simply have a string and then convert it into an object which you could access like object.item.array[0].item which is how you'd do it in JS. Another thing that I looked at was this but as a novice to C#, I couldn't make heads or tails of it. So does C# have something like JSON, but its more integrated? I've used C# lists, can you get 3D lists with items and not just arrays? I know that they are very different languages, and what works well on one, might not on another.
I think closest to what you describe in your questions and the comments as
simply convert a JSON string into a JSONObject
would maybe be the good old SimpleJSON. Simply copy the SimpleJSON.cs and depending on your needs maybe SimpleJSONUnity.cs(provides some extensions for directly parsing to and from Vector2, Vector3, Vector4, Quaternion, Rect, RectOffset and Matrix4x4) somewhere into your Assets folder.
Then given the example json
{
"version": "1.0",
"data": {
"sampleArray": [
"string value",
5,
{
"name": "sub object"
}
]
}
}
you can simply access single fields like
using SimpleJSON;
...
var jsonObject = JSON.Parse(the_JSON_string);
string versionString = jsonObject["version"].Value; // versionString will be a string containing "1.0"
float versionNumber = jsonObject["version"].AsFloat; // versionNumber will be a float containing 1.0
string val = jsonObject["data"]["sampleArray"][0]; // val contains "string value"
string name = jsonObject["data"]["sampleArray"][2]["name"]; // name will be a string containing "sub object"
...
Using this you don't have to re-create the entire c# class representation of the JSON data which might sometimes be a huge overhead if you just want to access a single value from the JSON string.
However if you want to serialze and deserialize entire data structures you won't get happy using SimpleJSON. Given the example above this is how you would use Unity's JsonUtility
Create the c# class representation of the data yu want to store. In this case e.g. something like
[Serializable]
public class RootObject
{
public string version = "";
public Data data = new Data();
}
[Serializable]
public class Data
{
public List<object> sampleArray = new List<object>();
}
[Serializeable]
public class SubData
{
public string name = "";
}
Then fill it with values and parse it to JSON like
var jsonObject = new RootObject()
{
version = "1.0",
data = new Data()
{
sampleArray = new List<object>()
{
"string value",
5,
new SubData(){ name = "sub object" }
}
}
};
var jsonString = JsonUtility.ToJson(jsonObject);
And to convert it back to c# either if jsonObject was not created yet
jsonObject = JsonUtility.FromJson<RootObject>(jsonString);
otherwise
JsonUtility.FromJsonOverwrite(jsonString, jsonObject);
JSON is just how objects are represented in JavaScript. While C# can use JSON, you'll probably have a much easier time defining your own custom classes. Using classes, you can define all the properties you'll need, string them together into a list, etc.. Hope this helps.

Why should I take List<> instead of array in JSON deserialization ?

First of all let me tell you one thing that I am posting this question is just for eagerness and to increase my knowledge. Hope you can clear my doubts !
Now lets come to the point
I got this question from my previous question-answer
Actually the problem is if I use
List<oodleListings> listings;
instead of
oodleListings[] listings;
It works fine !! I can deserialize my json string easily.
Now the problem is why array is not supported while deserializing json ?
What is the actual reason to use List instead of array ?
Your problem is not related with Arrays or Lists.
See the example classes below
public class TestClassList
{
public List<User> users;
}
public class TestClassArray
{
public User[] users;
}
public class User
{
public string user;
}
and assume your input string is
string json1 = "{ users:[{user:'11'},{user:'22'}] }";
var obj1= ser.Deserialize<TestClassList>(json1);
var obj2 = ser.Deserialize<TestClassArray>(json1);
both deserializations will work..
But if you try to deserialize this string string json2 = "{ users:{user:'11'} }";
var obj3 = ser.Deserialize<TestClassList>(json2);
var obj4 = ser.Deserialize<TestClassArray>(json2); //<--ERROR
you will get error in the second line (Althoug first line doesn't give an error, it doesn't return a valid object either).
As a result: The second json string does not contain an array of users, this is why you get No parameterless constructor defined for type of 'User[]'.
List<T> does not have a fixed length, so you are free to Add items to that object, without knowing its size. List is definitely the more flexible/functional class, but as a side-effect, it has a larger memory footprint.
Also, an object of type List<oodleListing> will have a method AddRange method that takes a parameter of oodleListing[] so you could always deserialize and then add to your generic class.
There is nothing wrong with Array or List. I just tried your code and it works without any issue for both Array and List.
In your previous question you didn't give the JSON serialized string, other wise it would have been solved there it self. You can check this post from ASP.Net.

How to add different types of objects in a single array in C#?

I am planning to rewrite my Python Tile Engine in C#. It uses a list of all the game objects and renders them on the screen. My problem is that unlike in Python where you can add almost anything to an array (e.g x = ["jj" , 1, 2.3, 'G', foo]) you can add only one type of objects
in a C# array (int[] x = {1,2,3};) . Are there any dynamic arrays (similar to the ArrayList() class) or something which allows you to pack different types into a single array? because all the game objects are individual classes.
Very simple—create an array of Object class and assign anything to the array.
Object[] ArrayOfObjects = new Object[] {1,"3"}
you can use an object array. strings, int, bool, and classes are all considered objects, but do realize that each object doesn't preserve what it once was, so you need to know that an object is actually a string, or a certain class. Then you can just cast the object into that class/data type.
Example:
List<object> stuff = new List<object>();
stuff.add("test");
stuff.add(35);
Console.WriteLine((string)stuff[0]);
Console.WriteLine((int)stuff[1]);
Though, C# is a strongly typed language, so I would recommend you embrace the language's differences. Maybe you should look at how you can refactor your engine to use strong typing, or look into other means to share the different classes, etc. I personally love the way C# does this, saves me a lot of time from having to worry about data types, etc. because C# will throw any casting (changing one data type to another) errors I have in my code before runtime.
Also, encase you didn't know, xna is C#'s game framework (didn't have it as a tag, so I assume you aren't using it).
You can write an abstract base class called GameObject, and make all gameObject Inherit it.
Edit:
public abstract class GameObject
{
public GameObject();
}
public class TileStuff : GameObject
{
public TileStuff()
{
}
}
public class MoreTileStuff : GameObject
{
public MoreTileStuff()
{
}
}
public class Game
{
static void Main(string[] args)
{
GameObject[] arr = new GameObject[2];
arr[0] = new TileStuff();
arr[1] = new MoreTileStuff();
}
}
C# has an ArrayList that allows you to mix types within an array, or you can use an object array, object[]:
var sr = new ArrayList() { 1, 2, "foo", 3.0 };
var sr2 = new object[] { 1, 2, "foo", 3.0 };
In c# we use an object[] array to store different types of data in each element location.
object[] array1 = new object[5];
//
// - Put an empty object in the object array.
// - Put various object types in the array.
// - Put string literal in the array.
// - Put an integer constant in the array.
// - Put the null literal in the array.
//
array1[0] = new object();
array1[1] = new StringBuilder("Initialized");
array1[2] = "String literal";
array1[3] = 3;
array1[4] = null;
You can use object[] (an object array), but it would be more flexible to use List<object>. It satisfies your requirement that any kind of object can be added to it, and like an array, it can be accessed through a numeric index.
The advantage of using a List is you don't need to know how items it will hold when you create it. It can grow and shrink dynamically. Also, it has a richer API for manipulating the items it contains.
Here is how you can do it
Use List<object> (as everything is derived from object in C#):
var list = new List<object>();
list.Add(123);
list.Add("Hello World");
Also dynamic might work for you (and your python background)
var list = new List<dynamic>();
list.Add(123);
list.Add(new
{
Name = "Lorem Ipsum"
});
If you wan't to use dynamic you really need to know what you're doing. Please read this MSDN article before you start.
But do you need it?
C# is a strongly-typed and very solid programming language. It is very flexible and great for building apps using object-oriented and functional paradigms. What you want to do may be acceptable for python, but looks pretty bad on C#. My recommendation is: use object oriented programming and try to build model for your problem. Never mix types together like you tried. One list is for a single data-type. Would you like to describe your problem in depth so that we can suggest you a better solution?
In C# 4 and later you can also use dynamic type.
dynamic[] inputArray = new dynamic[] { 0, 1, 2, "as", 0.2, 4, "t" };
Official docu
You can mix specific types doing the following:
(string, int)[] Cats = { ("Tom", 20), ("Fluffy", 30), ("Harry", 40), ("Fur Ball", 40) };
foreach (var cat in Cats)
{
Console.WriteLine(string.Join(", ", cat));
}
You have to declare your array with the datatype object:
object[] myArray = { };
myArray[0] = false;
myArray[1] = 1;
myArray[2] = "test";
You can use an array of object class and all it possible to add different types of object in array.
object[] array = new object[3];
array[0] = 1;
array[1] = "string";
array[3] = 183.54;

Categories

Resources