Trying to use unity JsonUtility to serialize a multidimentional array - c#

I'm trying to save a generic multidimensional array as json (this is not the main functionality, just the end goal) I want to keep the original location in the multidimensional array, so I can parse it back.
here's my code:
[Serializable]
public class Serializable2DArray<T>
{
public Serializable2DObject<T>[] data;
public Serializable2DArray(T[,] t)
{
List<Serializable2DObject<T>> tt = new List<Serializable2DObject<T>>();
for (int x = 0; x < t.GetLength(0); x++)
{
for (int y = 0; y < t.GetLength(1); y++)
{
Serializable2DObject<T> td = new Serializable2DObject<T>(t[x, y], x, y);
tt.Add(td);
}
}
data = tt.ToArray();
}
}
[Serializable]
public class Serializable2DObject<T>
{
public int x;
public int y;
public T obj;
public Serializable2DObject(T d, int _x, int _y)
{
obj = d;
x = _x;
y = _y;
}
}
Thank you for your assistance!
Edit:
I have this on the other end actually using the functions:
Serializable2DArray<TileData> md = new Serializable2DArray<TileData>(Mapdata);
string a = JsonUtility.ToJson(md, true);
File.WriteAllText(Application.persistentDataPath + "/map.json", a);
Tiledata Class:
[System.Serializable]
public class TileData
{
public int tileNumber;
public Vector3 position;
public int toughness;
public int health;
}
this all is returning "{ }"
and I want it to return the proper array of objects
Sorry if my question was unclear.

Related

Cast changing generic type

I have the following classes:
public class Grid<T>
{
public int Width { get; }
public int Height { get; }
public float CellSize { get; }
public Vector2 GridOffset { get; }
public T[,] GridObjects { get; }
public Grid(int width, int height, float cellSize, Vector3 gridOffset, Func<Grid<T>, int, int, T> createGridObjectMethod)
{
this.Width = width;
this.Height = height;
this.CellSize = cellSize;
this.GridOffset = gridOffset;
GridObjects = new T[width, height];
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
GridObjects[x, y] = createGridObjectMethod(this, x, y);
}
}
}
}
public interface IPathNode
{
PathNode GetPathNode();
}
public class PathNode : IPathNode
{
private readonly Grid<IPathNode> grid;
public int X { get; }
public int Y { get; }
public PathNode PreviousNode;
public PathNode(Grid<IPathNode> grid, int x, int y)
{
this.grid = grid;
this.X = x;
this.Y = y;
}
}
Now, I'm trying to create a Grid instance with the following line:
grid = new Grid<PathNode>(10, 10, 1, new Vector3(-5, -5, 0), (g, x, y) =>
{
Grid<IPathNode> test = (Grid<IPathNode>)g;
return new PathNode(g, x, y);
});
The problem is that PathNode asks for a Grid and my grid is made of PathNodes (or any other type that implements that interface).
How can I cast it, or instantiate it?
Tried casting the grid object, but it will fail to compile.
Also adding generics to the PathNode class but I don't like that
I ended up adding a restriction to the PathNode and the interface (and adding generics to it). I had to edit some of the code but it works. Don't really like this option since I only use the generics for it to work but yeah.
public class PathNode<T> : IPathNode<T> where T : IPathNode<T>
public interface IPathNode<T> where T : IPathNode<T>

How do I add an already instantiated gameobject to a grid?

I am following multiple tutorials and I don't understand all of the code, but basically, I'm instantiating a series of game objects along an L-System. Then I'm creating a Grid like this:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj is Point)
{
Point p = obj as Point;
return this.X == p.X && this.Y == p.Y;
}
return false;
}
public override int GetHashCode()
{
unchecked
{
int hash = 6949;
hash = hash * 7907 + X.GetHashCode();
hash = hash * 7907 + Y.GetHashCode();
return hash;
}
}
public override string ToString()
{
return "P(" + this.X + ", " + this.Y + ")";
}
}
public enum CellType
{
Empty,
Road,
Structure,
SpecialStructure,
None
}
public class Grid
{
private CellType[,] _grid;
private int _width;
public int Width { get { return _width; } }
private int _height;
public int Height { get { return _height; } }
private List<Point> _roadList = new List<Point>();
private List<Point> _specialStructure = new List<Point>();
private List<Point> _houseStructure = new List<Point>();
public Grid(int width, int height)
{
_width = width;
_height = height;
_grid = new CellType[width, height];
}
// Adding index operator to our Grid class so that we can use grid[][] to access specific cell from our grid.
public CellType this[int i, int j]
{
get
{
return _grid[i, j];
}
set
{
if (value == CellType.Road)
{
_roadList.Add(new Point(i, j));
}
if (value == CellType.SpecialStructure)
{
_specialStructure.Add(new Point(i, j));
}
if (value == CellType.Structure)
{
_houseStructure.Add(new Point(i, j));
}
_grid[i, j] = value;
}
}
After the game objects are instantiated, I want to add each instantiated gameobject into into the grid and assign each of them a type. I have a script on a my gameobjects which basically stores the type as a string, and I know how to pass it as an enum. But how do I set each game object into the grid with the type, and point?

A class to help access a chunk of memory

I need a class to help me access a chunk of memory
So far I have this
class ABSet
{
private byte[] _raw;
public ABSet(byte[] RawData)
{
_raw=RawData;
}
public double A
{
get
{
return BitConverter.ToDouble(_raw, 2);
}
}
public double B
{
get
{
return BitConverter.ToDouble(_raw, 10);
}
}
}
Now I would like to do something like this
class ABSetCollection
{
private byte[] _raw;
public ABSetCollcetion(byte[] RawData)
{
_raw=RawData;
}
public ABSet this[int index]
{
get
{
// This Part Is What I Want To Figure Out
}
}
}
I know I could put return new ABSet(_raw); but I feel like there must be a solution that requires less dynamic allocation.
P.S. The reason I want to use properties is because I am binding to them in my GUI
Rather than just accepting an array of bytes, change it so you get an offset too. Then you'll be able to get that to work.
class ABSet
{
public const int ABSetSize = 20; // or whatever the size
private readonly byte[] _data;
private readonly int _offset;
public ABSet(byte[] data, int offset = 0)
{
_data = data;
_offset = offset;
}
const int AOffset = 2;
public double A => BitConverter.ToDouble(_data, _offset + AOffset);
const int BOffset = 10;
public double B => BitConverter.ToDouble(_data, _offset + BOffset);
}
class ABSetCollection
{
private readonly byte[] _data;
private readonly int _offset;
public ABSetCollection(byte[] data, int offset = 0)
{
_data = data;
_offset = offset;
}
public ABSet this[int index] => new ABSet(_data, _offset + index * ABSet.ABSetSize);
}

serializing an object in C#

I have a serializable class named DataSource:
namespace GraphLib
{
public struct cPoint
{
public float x;
public float y;
}
[Serializable]
public class DataSource
{
public delegate String OnDrawXAxisLabelEvent(DataSource src, int idx);
public delegate String OnDrawYAxisLabelEvent(DataSource src, float value);
public OnDrawXAxisLabelEvent OnRenderXAxisLabel = null;
public OnDrawYAxisLabelEvent OnRenderYAxisLabel = null;
private cPoint[] samples = null;
private int length = 0;
private String name = String.Empty;
private int downSample = 1;
private Color color = Color.Black;
public float VisibleDataRange_X = 0;
public float DY = 0;
public float YD0 = -200;
public float YD1 = 200;
public float Cur_YD0 = -200;
public float Cur_YD1 = 200;
public float grid_distance_y = 200; // grid distance in units ( draw a horizontal line every 200 units )
public float off_Y = 0;
public float grid_off_y = 0;
public bool yFlip = true;
public bool Active = true;
private bool YAutoScaleGraph = false;
private bool XAutoScaleGraph = false;
public float XAutoScaleOffset = 100;
public float CurGraphHeight = 1.0f;
public float CurGraphWidth = 1.0f;
public float InitialGraphHeight = 0;
public float InitialGraphWidth = 0;
public bool AutoScaleY
{
get
{
return YAutoScaleGraph;
}
set
{
YAutoScaleGraph = value;
}
}
public bool AutoScaleX
{
get
{
return XAutoScaleGraph;
}
set
{
XAutoScaleGraph = value;
}
}
public cPoint[] Samples
{
get
{
return samples;
}
set
{
samples = value;
length = samples.Length;
}
}
public float XMin
{
get
{
float x_min = float.MaxValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.x < x_min) x_min=p.x;
}
}
return x_min;
}
}
public float XMax
{
get
{
float x_max = float.MinValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.x > x_max) x_max = p.x;
}
}
return x_max;
}
}
public float YMin
{
get
{
float y_min = float.MaxValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.y < y_min) y_min = p.y;
}
}
return y_min;
}
}
public float YMax
{
get
{
float y_max = float.MinValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.y > y_max) y_max = p.y;
}
}
return y_max;
}
}
public void SetDisplayRangeY(float y_start, float y_end)
{
YD0 = y_start;
YD1 = y_end;
}
public void SetGridDistanceY( float grid_dist_y_units)
{
grid_distance_y = grid_dist_y_units;
}
public void SetGridOriginY( float off_y)
{
grid_off_y = off_y;
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(string), "")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public String Name
{
get { return name; }
set { name = value; }
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(Color), "")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Color GraphColor
{
get { return color; }
set { color = value; }
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(int), "0")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Length
{
get { return length; }
set
{
length = value;
if (length != 0)
{
samples = new cPoint[length];
}
else
{
// length is 0
if (samples != null)
{
samples = null;
}
}
}
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(int), "1")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Downsampling
{
get { return downSample; }
set { downSample = value; }
}
}
}
and i want to serialize it in a form like this:
public partial class Form1 : Form
{
public GraphLib.PlotterDisplayEx display;
private void serialize()
{
System.IO.Stream TestFileStream = System.IO.File.Create(#"C:\Users\Public\Documents\test.txt");
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
serializer.Serialize(TestFileStream, display.DataSources[0]);
TestFileStream.Close();
}
not that DataSource class that i want to serialize in Form1, is one of the attributes in GraphLib.PlotterDisplayEx class
but when i run the program it gives me the following error:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
Additional information: Type 'KTK.Form1' in Assembly 'KTK, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
UPDATE
I updated the code for DataSource class.now it's complete code guys.
You probably didn't show the complete code of the DataSource class. It directly or indirectly holds a reference to an object of type KTK.Form1.
This might be through an event to which the form is subscribed.
In this case you probably don't want to serialize it an should mark it as NonSerialized:
[field:NonSerialized]
public event ...;
Now that you updated the question. Change
public OnDrawXAxisLabelEvent OnRenderXAxisLabel = null;
public OnDrawYAxisLabelEvent OnRenderYAxisLabel = null;
to
[NonSerialized]
public OnDrawXAxisLabelEvent OnRenderXAxisLabel;
[NonSerialized]
public OnDrawYAxisLabelEvent OnRenderYAxisLabel;
The delegates may hold references to non-serializable classes.

How to add array of objects to List in c#

Let me explain
I have a class X
public class X
{
private List<Y> y;
}
I have another class Y
public class Y
{
int a ;
Private List<Z> z;
}
Now i want to mannually assign some values to class Y object whitch is an array of obejcts of size 2. Now i have added the values. How can i add this to the object of class X, in which a propery of type List of Class Y exists.
Hope am able to explain it correctly.
i have
Y [] y1= new Y[2];
y1[0] = new Y();
y1[0].a=1;
y1[1]=new Y();
y1[0].a=2;
How can i assign y1[0] and y1[1] to object of X.
X x1=new X();
x1.y.add(y1[0]);
x1.y.add(y1[1]);
Its failing...
Please help me .
you can use AddRange
x1.y.AddRange(y1);
x1.y.AddRange(y1.GetRange(0,2)); // Adds first two elements
Although if its only a couple elements, its probably just as efficient to add them on their own
Since your list is private you may wish to add a method to do this
public void AddRangeToList(List<Y> items)
{
y.AddRange(items);
}
x.AddRangeToList(y1);
x.AddRangeToList(y1.GetRange(0,2));
It appears you never initialise your arrays I would make constructors to do this
public X()
{
y = new List<Y>();
}
public Y()
{
z = new List<Z>();
}
if you want to access properties of the class you need to make them public
X x1=new X();
x1.y = new List<Y>(); // need create instant of y before add items
x1.y.Add(y1[0]);
x1.y.Add(y1[1]);
I would change the classes as below
public class X
{
public List<Y> y { get; set; }
}
public class Y
{
public int a;
public List<Z> z { get; set; }
}
You should make your list property public instead of private.
Accessibility Levels (C# Reference) http://msdn.microsoft.com/en-us/library/ba0a1yw2.aspx
-
I would create a constructor that creates an instance of the List< Y>.
classes:
public class X
{
public X()
{
Y = new List<Y>();
}
public List<Y> Y { get; private set; }
}
public class Y
{
public Y()
{
Z = new List<Z>();
}
public int A { get; set; }
public List<Z> Z { get; private set; }
}
public class Z
{
public int V { get; set; }
}
Usage:
Y[] y1 = new Y[2];
y1[0] = new Y();
y1[0].A = 1;
y1[1] = new Y();
y1[1].A = 2;
X x1 = new X();
x1.Y.Add(y1[0]);
x1.Y.Add(y1[1]);
// or
X x2 = new X();
x2.Y.AddRange(y1);
// or
X x3 = new X();
foreach (Y y in y1)
x3.Y.Add(y);

Categories