So im trying to make a content importer for a class in my game and i have managed to solve most issues, however i cant seem to solve this null reference exception.
The game class is empty as i was just testing but here it is
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MagieMonoExtension;
using MagieMonoExtension.Framework.Mapping;
namespace Magie
{
public class Magie : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
TileGrid Map;
public Magie()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Map = Content.Load<TileGrid>("Maps/MapTemplate");
Map.Init(Content);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
#region Update code:
#endregion
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
#region Draw code:
spriteBatch.Begin();
Map.Draw(spriteBatch);
spriteBatch.End();
#endregion
base.Draw(gameTime);
}
}
}
The content importer
using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;
using TInput = System.String;
namespace MagieMonoExtension
{
[ContentImporter(".xml", DisplayName = "Tile map Importer", DefaultProcessor = nameof(TileMapProcessor))]
public class TileMapImporter : ContentImporter<TInput>
{
public override TInput Import(string filename, ContentImporterContext context)
{
return File.ReadAllText(filename);
}
}
}
The processor
using System.Xml;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content.Pipeline;
// TODO: replace these with the processor input and output types.
using TInput = System.String;
using TOutput = MagieMonoExtension.Framework.Mapping.TileGrid;
using MagieMonoExtension.Framework.Mapping;
namespace MagieMonoExtension
{
/// <summary>
/// This class will be instantiated by the XNA Framework Content Pipeline
/// to apply custom processing to content data, converting an object of
/// type TInput to TOutput. The input and output types may be the same if
/// the processor wishes to alter data without changing its type.
///
/// This should be part of a Content Pipeline Extension Library project.
///
/// TODO: change the ContentProcessor attribute to specify the correct
/// display name for this processor.
/// </summary>
[ContentProcessor(DisplayName = "Tile Map Processor")]
public class TileMapProcessor : ContentProcessor<TInput, TOutput>
{
public override TOutput Process(TInput input, ContentProcessorContext context)
{
XmlDocument Doc = new XmlDocument();
Doc.LoadXml(input);
Dictionary<int, string> textures = new Dictionary<int, string>();
XmlNodeList ResNodes = Doc.SelectNodes("//Map/Resources/Texture");
foreach (XmlNode n in ResNodes)
{
textures.Add(int.Parse(n.Attributes["id"].Value), n.Attributes["content"].Value);
}
TOutput.MapResources resources = new TOutput.MapResources(textures);
TOutput.Grid grid = new TOutput.Grid();
XmlNodeList RowNodes = Doc.SelectNodes("//Map/Grid/Row");
foreach (XmlNode n in RowNodes)
{
TOutput.Grid.Row r = new TOutput.Grid.Row();
XmlNodeList TileList = n.SelectNodes("Tile");
foreach (XmlNode t in TileList)
{
r.Tiles.Add(new Tile(int.Parse(t.Attributes["textureid"].Value), Tile.GetTileType(t.Attributes["tiletype"].Value)));
}
grid.Rows.Add(r);
}
/*XmlNodeList EventTileList = Doc.SelectNodes("//Map/EventTiles/OnTile");
foreach (XmlNode n in EventTileList)
{
}*/
int Size = int.Parse(Doc.SelectSingleNode("//Map/Resources/TextureSize").InnerText);
return new TOutput() { MapGrid = grid, Resources = resources, TexSize = Size };
}
}
}
The writer
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
using TWrite = MagieMonoExtension.Framework.Mapping.TileGrid;
namespace MagieMonoExtension
{
[ContentTypeWriter]
public class TileMapWriter : ContentTypeWriter<TWrite>
{
protected override void Write(ContentWriter output, TWrite value)
{
output.Write(value.TexSize);
output.Write(value.Resources.temp.Count);
foreach (var tex in value.Resources.temp)
{
output.Write(tex.Key);
output.Write(tex.Value);
}
output.Write(value.MapGrid.Rows.Count);
output.Write(value.MapGrid.Rows[0].Tiles.Count);
foreach (TWrite.Grid.Row row in value.MapGrid.Rows)
{
foreach (Framework.Mapping.Tile tile in row.Tiles)
{
output.Write(tile.TileTexture);
output.Write(tile.ThisType.ToString());
}
}
}
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return "MagieMonoExtension.Framework.Mapping.TileGrid, MagieMonoExtension";
}
}
}
The reader
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using MagieMonoExtension.Framework.Mapping;
using TRead = MagieMonoExtension.Framework.Mapping.TileGrid;
namespace MagieMonoExtension
{
public class TileMapReader : ContentTypeReader<TRead>
{
protected override TRead Read(ContentReader input, TRead existingInstance)
{
int texsize = input.ReadInt32();
int resources = input.ReadInt32();
Dictionary<int, string> RES = new Dictionary<int, string>();
for (int res = 1; res <= resources; res++)
{
RES.Add(input.ReadInt32(), input.ReadString());
}
int rows = input.ReadInt32();
int TilesPerRow = input.ReadInt32();
TRead.Grid grid = new TRead.Grid();
for (int row = 1; row <= rows; row++)
{
TRead.Grid.Row r = new TRead.Grid.Row();
for (int col = 1; col <= TilesPerRow; col++)
{
r.Tiles.Add(new Tile(input.ReadInt32(), Tile.GetTileType(input.ReadString())));
}
grid.Rows.Add(r);
}
TRead.MapResources Resources = new TRead.MapResources(RES);
return new TRead() { MapGrid = grid, Resources = Resources, TexSize = texsize };
}
}
}
Lastly the class that its meant to create from the imported content
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using MagieMonoExtension.Framework.Exceptions;
namespace MagieMonoExtension.Framework.Mapping
{
public class TileGrid
{
public TileGrid(/*Grid grid, MapResources mapResources, int s*/)
{
//MapGrid = grid;
//Resources = mapResources;
//TexSize = s;
}
public void Init(ContentManager content)
{
if (!Ready)
{
Resources.Init(content);
Rectangle Position = new Rectangle(0, 0, TexSize, TexSize);
foreach (Grid.Row row in MapGrid.Rows)
{
Position.Y = 0;
foreach (Tile tile in row.Tiles)
{
tile.Position = Position;
Position.Y += TexSize;
}
Position.X += TexSize;
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
if (Ready)
{
foreach (Grid.Row row in MapGrid.Rows)
{
foreach (Tile tile in row.Tiles)
{
tile.Draw(spriteBatch, Resources.GetResource(tile.TileTexture));
}
}
}
}
public Grid MapGrid;
public MapResources Resources;
public int TexSize;
private bool Ready = false;
public class MapResources
{
public MapResources(Dictionary<int, string> Res) { temp = Res; }
public void Init(ContentManager content)
{
foreach (var item in temp)
{
Textures.Add(item.Key, content.Load<Texture2D>(item.Value));
}
}
private Dictionary<int, Texture2D> Textures = new Dictionary<int, Texture2D>();
internal Dictionary<int, string> temp;
public Texture2D GetResource(int id)
{
return Textures[id];
}
}
public class Grid
{
public List<Row> Rows = new List<Row>();
public List<TileEvent> EventTiles = new List<TileEvent>();
public class Row
{
public List<Tile> Tiles = new List<Tile>();
}
}
}
}
I am by no means an expert in xna or monogame, so im certain most of this code looks bad.
If anyone can help figure out how to resolve this issue then that would be great.