Ok, now I am running into a very weird error. I am trying to deserialize a GameEvent object which is like this:
public class GameEvent {
public Location eventLocation = Location.NoLocation;
public Location targetLocation = Location.NoLocation;
public string eventTriggerName = ""; // Who (Piece or tactic) triggers this event
public string targetTriggerName = ""; // Target name
public int eventPlayerID = -1;
public int targetPlayerID = -1;
public string result = ""; // Piece, Tactic, Trap, Freeze, Move, Kill, Flag
public int amount = 0;
public GameEvent() { Debug.Log("Fuck"); }
public static string ClassToJson(GameEvent gameEvent)
{
return JsonConvert.SerializeObject(gameEvent);
}
}
When I deserialize it by doing this, however, it is changed weirdly.
public static GameEvent JsonToClass(string json)
{
Debug.Log(json);
GameEvent gameEvent = JsonConvert.DeserializeObject<GameEvent>(json);
Debug.Log(ClassToJson(gameEvent));
return JsonConvert.DeserializeObject<GameEvent>(json);
}
As you can see from the picture below the eventLocation should be (7,2) but after deserialization it becomes (4,2). And the eventLocation is the only thing that's changed.
string json = "{\"eventLocation\": {\"x\": 7, \"y\": 2}, \"targetLocation\": {\"x\": 4, \"y\": 2} }";
var x = GameEvent.JsonToClass(json);
I have no clue why. This is my Location class
public class Location
{
public int x = -1;
public int y = -1;
public Location(){}
public Location(int X, int Y)
{
x = X;
y = Y;
}
public Location(Location location)
{
x = location.x;
y = location.y;
}
public static bool operator !=(Location a, Location b)
{
UnityEngine.Debug.Log(a + " " + b);
return a.x != b.x || a.y != b.y;
}
public static Location NoLocation = new Location(-1, -1);
}
I didn't post all the functions of GameEvent and Location class but I posted all the variables they have.
By the way I also met another weird problem with the Location. When I do if(eventLocation != Location.NoLocation), the != operator that I override is actually not comparing eventLocation with Location.NoLocation but eventLocation(yeah itself). So the a and b will always be the same and != will always return me false. I also have no clue why.
Thanks in advance!!!
Your problem comes from these two line:
public Location eventLocation = Location.NoLocation;
public Location targetLocation = Location.NoLocation;
It is happening because you are binding both objects to an specific object which is NoLocation. It means both of the eventLocation and targetLocation are pointing to the same object in the heap memory and changing one of them changes the other one as well.
Changing NoLocation to something like this can solve your issue:
public static Location NoLocation { get { return new Location(-1, -1); } }
Related
I'm trying to Copy and Paste part of my list. Unfortunately, when pasting from the clipboard, the condition finds the stored data, but when assigned to the variable it is still equal to null.
This is my code for List and List Item.
public class ListCanvasBlocks : List<MyBlock>
{
public List<MyBlock> MyCopySelectedObj()
{
var x = new List<MyBlock>();
x.AddRange(this.Where(z => z.IsSelected));
return x;
}
}
[Serializable]
public class MyBlock
{
public MyBlock(Rectangle rect, BlocksData.Shape shape,int id)
{
Rect = rect;
Shape = shape;
Text = BlocksData.Text(Shape);
ID = id;
}
public string Text;
public bool IsSelected { get; set; } = false;
public bool IsLocked = false;
public int ID{ get; set; }
public Point PointInput;
public Point PointOutput1, PointOutput2;
public Rectangle Rect;
public SolidBrush BackColor;
public Color FontColor;
public int FontSize;
public BlocksData.Shape Shape{get;set;}
}
and this is what i do when i press ctrl+c/v
public void Copy()
{
Clipboard.Clear();
Clipboard.SetData("ListCanvasBlocks", _canvObj.MyCopySelectedObj());
}
public void Paste()
{
if (Clipboard.ContainsData("ListCanvasBlocks"))
{var test = (ListCanvasBlocks)Clipboard.GetData("ListCanvasBlocks");}
}
Condition in Paste method return true but variable test is still null after assigment
i'm trying use this solution
and this and few others
BlockData.Shape is enum
You are trying to cut and paste a ListCanvasBlocks but the MyCopySelectedObj() method returns a List<MyBlock>, which is a supertype. The runtime can't automatically cast from a general to specific.
Try changing this:
public class ListCanvasBlocks : List<MyBlock>
{
public ListCanvasBlocks MyCopySelectedObj()
{
var x = new ListCanvasBlocks();
x.AddRange(this.Where(z => z.IsSelected));
return x;
}
}
At the moment when I tried to individually add variables to the clipboard, it turned out that the problem was serialization. The problem was solved in SolodBrush because its attribute is Color, and only variables without attributes can be serialized.
There i found solution when i found what is real problem
Looks like MyCopySelectedObj() returns a List of MyBlock which gets assigned to the name "ListCanvasBlocks" on the Copy(), but when you call Paste(), you cast the List in the Clipboard to Object (ListCanvasBlocks). It is inherited from List, but still not object type ListCanvasBlocks. Try casting directly to List to that var test when you call your Paste().
EDIT: Updated to include actual code.
I am having an issue with some custom generic interfaces and I am not entirely sure what to do. The error I'm getting is:
Cannot convert from Map to IMap<ICell>
That error pops up when I try to pass Map as a parameter to a method that accepts IMap<ICell>. I have pasted sample code below. Just to be clear, FieldOfView doesn't use anything that hasn't been defined in ICell or IMap.
public class Map : IMap<Cell>
{
private FieldOfView _fieldOfView;
public int Width { get; }
public int Height { get; }
public Map(int width, int height)
{
Width = width;
Height = height;
_fieldOfView = new FieldOfView(this as IMap<ICell>);
_fieldOfView = new FieldOfView((IMap<ICell>)this);
}
public IEnumerable<Cell> GetAllCells()
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
yield return GetCell(x, y);
}
}
}
public Cell GetCell(int x, int y)
{
return new Cell(x, y);
}
public void Copy(IMap<Cell> sourceMap)
{
// ...
}
public override string ToString()
{
var sb = new StringBuilder();
foreach (var cell in GetAllCells())
{
sb.Append(cell.ToString());
}
return sb.ToString();
}
}
public interface IMap<T> where T : ICell
{
int Width { get; }
int Height { get; }
IEnumerable<T> GetAllCells();
T GetCell(int x, int y);
void Copy(IMap<T> sourceMap);
}
public class Cell : ICell
{
public int X { get; }
public int Y { get; }
public Cell(int x, int y)
{
X = x;
Y = Y;
}
public override string ToString()
{
return "overloaded";
}
}
public interface ICell
{
int X { get; }
int Y { get; }
}
public class FieldOfView
{
private readonly IMap<ICell> _map;
public FieldOfView(IMap<ICell> map)
{
_map = map;
}
public void DoStuff()
{
foreach (var cell in _map.GetAllCells())
{
// ...
}
}
}
This is similar to this stack overflow question, but a little different. I tried implementing an interface IMap as well as IMap<T> : IMap where T : ICell, but am having issues with that as well.
Lastly, I'm not sure if this is solvable with co/contravariance, but I am using C#3.0 so that is out of the picture for me (unless switching versions is the only way).
I think it would be fine with an implicit / direct cast?
_fieldOfView = new FieldOfView(this as IMap<ICell>); // or
_fieldOfView = new FieldOfView((IMap<ICell>)this);
But if there is a better way, I would like to do that. Resharper does throw me a warning when I cast Map to IMap<ICell> saying:
Suspicious cast: there is no type in the solution which is inherited from both Map and IMap<ICell>.
EDIT2: Look's like neither of the casts worked. I've decided instead to make Map be derived from IMap and just create the Cell objects where needed in the code.
Thanks #Rob and #MK87 for your help!
No, IMap<Cell> is not the same as IMap<ICell>, so this line:
_fieldOfView = new FieldOfView(this as IMap<ICell>);
will always pass null as parameter.
Yes, this is definitely solvable with variance.
For example, you can have:
IEnumerable<object> list = new List<string>();
since list is IEnumerable<outT>, that means that every IEnumerable<TT> with TT that derives from T is a valid value for list. So the List doesn't have to be of object, it can be of any derived type.
But because you can't use variance, we need another hack.
Possible solution: instead of deriving Map from IMap<Cell>, derive it from IMap<ICell>. You'll have only to correct some points, for example the return type of GetCell() must become ICell instead of Cell. Is it feasable for you?
I want to learn how to create an object hierarchy (like that of excel vba).
I have written some code and want to ask if this is the right way to go. Also, I want to know if creating this type of object structure will have any significant effect on performance. I will access the objects as for e.g. this way :
Hotel hotel = new Hotel();
int x = hotel.Rooms[1].Count; // just an example
int y = hotel.Rooms.Room.Count; // just an example
class Hotel
{
private int i;
public Hotel()
{
i = 10; // some prossessing to give the value of i. Lets say 10
}
public _Rooms Rooms
{
get { return new _Rooms(i); }
}
}
class _Rooms
{
private int _i;
public _Rooms(int i)
{
this._i = i;
}
public _Room this[int i]
{
get { return new _Room(_i); }
}
public _Room Room // _Room Property
{
get { return new _Room(this._i); }
}
}
class _Room
{
private int _i;
public _Room(int i)
{
// some prossessing to give the value of i. Lets say :
_i = i + 10;
}
public int Count
{
get { _i = 15; return _i; }
}
}
This is just a simple example of the model that I want to achieve.
I have this same code on two places:
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
x = amount[0].Trim();
y = amount[1].Trim();
}
else
{
x = "1";
y = amountUnit.Trim();
}
//
unit = textInBrackets.Replace(amountUnit, "");
name = "";
for (int z = 0; z < i; z++)
{
name += someArray[z];
name += " ";
}
name = name.Trim();
The exact code is repeated twice. How to fix it? If i extract it in a new method, I'll have a lot of ref input parameters. Is there another way?
If it's not possible, just the part untill the comments?
Like:
public struct Parameters
{
public int X {get; set;}
public int Y {get; set;}
}
public Parameters ExtractParameters(string amountUnit)
{
var parameters = new Parameters();
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
parameters.X = int.Parse(amount[0].Trim());
parameters.Y = int.Parse(amount[1].Trim());
}
else
{
parameters.X = 1;
parameters.Y = int.Parse(amountUnit.Trim());
}
return parameters;
}
Usage:
var parameters = ExtractParameters(amountUnit);
var x = parameters.X;
var y = parameters.Y;
You can also make it an extension method on string.
And of course you best add some exception handling too.
The code seems to have two, separate blocks, logically.
One that deals with x and y - the other with name. These should probably be separate methods.
Now, you can create a type (class or structure) that encapsulates x and y, meaning that you only need to pass in one parameter. Instead of passing it by ref you can simply return it and in the caller replace what you passed in.
Combine your code and your data into a class ;-)
public class Point
{
public Point(string amountUnit)
{
if (amountUnit == null)
{
throw new ArgumentNullException("amountUnit");
}
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
this.X = amount[0].Trim();
this.Y = amount[1].Trim();
}
else
{
this.X = "1";
this.Y = amountUnit.Trim();
}
}
string X { get; private set; }
string Y { get; private set; }
}
If you don't need anything very dynamic, how about splitting it into two methods, and doing something as simple as this:
public static string GetX(string amountUnit)
{
return amountUnit.ToLower().Contains("x") ?
amountUnit.Split('x')[0].Trim() :
"1";
}
public static string GetY(string amountUnit)
{
return amountUnit.ToLower().Contains("x") ?
amountUnit.Split('x')[1].Trim() :
amountUnit.Trim();
}
I'm getting this error in C# while trying to build an importer for a tilemap. It's supposed to read files formatted like this;
DatMapName!
6|4
SpritePageID:SpriteID:OffsetX:OffsetY|SpritePageID:SpriteID:OffsetX:OffsetY SpritePageID:SpriteID:OffsetX:OffsetY
SpritePageID:SpriteID:OffsetX:OffsetY|SpritePageID:SpriteID:OffsetX:OffsetY SpritePageID:SpriteID:OffsetX:OffsetY
into a data structure built up like this;
map
MapTile[MapSizeX, MapSizeY]
Tile[Sprites on tile]
- string SpritePageID
- int SpriteID
- Vector2 Offset
Basically it has the map name on the first line, X/Y size on the second, and then it has SpritePageID, spriteID, offsetx, offsetY separated by :, and multiple sprites per tile separated by |. Spaces delimit the different tiles.
However, during processing I get the following error;
Error 1 Building content threw NullReferenceException: Object reference not set to an instance of an object.
at LibTilePipelineExtension.LevelProcessor.Process(String input, ContentProcessorContext context) in C:\Projects\C#\XNA1\TileWorld\LibTilePipelineExtension\LevelProcessor.cs:line 45
at Microsoft.Xna.Framework.Content.Pipeline.ContentProcessor`2.Microsoft.Xna.Framework.Content.Pipeline.IContentProcessor.Process(Object input, ContentProcessorContext context)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.BuildAssetWorker(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.BuildAsset(BuildItem item)
at Microsoft.Xna.Framework.Content.Pipeline.BuildCoordinator.RunTheBuild()
at Microsoft.Xna.Framework.Content.Pipeline.Tasks.BuildContent.RemoteProxy.RunTheBuild(BuildCoordinatorSettings settings, TimestampCache timestampCache, ITaskItem[] sourceAssets, String[]& outputContent, String[]& rebuiltContent, String[]& intermediates, Dictionary`2& dependencyTimestamps, KeyValuePair`2[]& warnings)
C:\Projects\C#\XNA1\TileWorld\TileWorld\TileWorldContent\tileworldtest1.tilemap TileWorld
Here's the code that's throwing this error.
string[] lines = input.Split(new char[] { '\n' });
// ------
// Clear out commented lines from the array. Turn it to a list, remove indices, turn back to array.
List<string> derp1 = new List<string>(lines);
for (int derp2 = 0; derp2 < derp1.Count; derp2++) {
if (derp1[derp2][0] == ' ' || derp1[derp2][0] == ';') {
derp1.RemoveAt(derp2);
derp2--;
}
}
lines = derp1.ToArray();
// ------
int rows = Convert.ToInt32(lines[1].Split('|')[0]);
int columns = Convert.ToInt32(lines[1].Split('|')[1]);
MapTile[,] res = new MapTile[rows, columns];
for (int i0 = 2; i0 < (rows + 2); i0++) {
string[] tiles = lines[i0].Split(' ');
for (int i1 = 0; i1 < columns; i1++) {
string[] tileSprites = tiles[i1].Split('|');
--> res[i0 - 2, i1].sprites = new Tile[tileSprites.Length]; <-- Exception
for (int i2 = 0; i2 < tileSprites.Length; i2++) {
string[] spriteData = tileSprites[i2].Split(':');
res[i0 - 2, i1].sprites[i2] = new Tile(spriteData[0], Convert.ToInt32(spriteData[1]), new Vector2(Convert.ToInt32(spriteData[2]), Convert.ToInt32(spriteData[3])));
}
}
}
return new Map(res, lines[0]);
These are the classes I use to make this tree. I removed the using statements to shorten this question.
//Map.cs
namespace LibTile {
public class Map {
public MapTile[,] grid { get; set; }
public string MapName { get; set; }
public Map(MapTile[,] value) {
grid = value;
}
public Map(MapTile[,] value, string name) {
grid = value;
MapName = name;
}
public MapTile GetTile(int row, int col) {
return grid[row, col];
}
public int Rows {
get {
return grid.GetLength(0);
}
}
public int Columns {
get {
return grid.GetLength(1);
}
}
}
}
.
//MapTile.cs
namespace LibTile {
public class MapTile {
public Tile[] sprites { get; set; }
public MapTile(Tile[] value) {
sprites = value;
}
}
}
.
//Tile.cs
namespace LibTile {
public class Tile {
public String SpritePageID;
public int SpriteID;
public Vector2 Offset;
public Tile(String spid, int sid, int ox, int oy) {
SpritePageID = spid;
SpriteID = sid;
Offset = new Vector2(ox,oy);
}
public Tile(String spid, int sid, Vector2 o) {
SpritePageID = spid;
SpriteID = sid;
Offset = o;
}
}
}
You create a new array of MapTile but you never initialize the individual elements. Try this:
res[i0 - 2, i1] = new MapTile(new Tile[tileSprites.Length]);
This will create a new MapTile object in each poition of the array. Not doing this was causing your null reference exception. I would also consider changing the constructor of MapTile to be parameterless and then just set MapTile.sprites as you were doing before.