Custom Content Pipeline with Automatic Serialization Load Error

Posted by Direweasel on Game Development See other posts from Game Development or by Direweasel
Published on 2012-11-05T21:23:42Z Indexed on 2012/11/06 5:20 UTC
Read the original article Hit count: 438

I'm running into this error:

Error loading "desert". Cannot find type TiledLib.MapContent, TiledLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.

at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.InstantiateTypeReader(String readerTypeName, ContentReader contentReader, ContentTypeReader& reader) at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.GetTypeReader(String readerTypeName, ContentReader contentReader, List1& newTypeReaders)
at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.ReadTypeManifest(Int32 typeCount, ContentReader contentReader) at Microsoft.Xna.Framework.Content.ContentReader.ReadHeader() at Microsoft.Xna.Framework.Content.ContentReader.ReadAsset[T]() at Microsoft.Xna.Framework.Content.ContentManager.ReadAsset[T](String assetName, Action
1 recordDisposableObject) at Microsoft.Xna.Framework.Content.ContentManager.Load[T](String assetName) at TiledTest.Game1.LoadContent() in C:\My Documents\Dropbox\Visual Studio Projects\TiledTest\TiledTest\TiledTest\Game1.cs:line 51 at Microsoft.Xna.Framework.Game.Initialize() at TiledTest.Game1.Initialize() in C:\My Documents\Dropbox\Visual Studio Projects\TiledTest\TiledTest\TiledTest\Game1.cs:line 39 at Microsoft.Xna.Framework.Game.RunGame(Boolean useBlockingRun) at Microsoft.Xna.Framework.Game.Run() at TiledTest.Program.Main(String[] args) in C:\My Documents\Dropbox\Visual Studio Projects\TiledTest\TiledTest\TiledTest\Program.cs:line 15

When trying to run the game. This is a basic demo to try and utilize a separate project library called TiledLib. I have four projects overall:

  1. TiledLib (C# Class Library)
  2. TiledTest (Windows Game)
  3. TiledTestContent (Content)
  4. TMX CP Ext (Content Pipeline Extension Library)

TiledLib contains MapContent which is throwing the error, however I believe this may just be a generic error with a deeper root problem.

EMX CP Ext contains one file: MapProcessor.cs

    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;
using TiledLib;

namespace TMX_CP_Ext
{
    // Each tile has a texture, source rect, and sprite effects.
    [ContentSerializerRuntimeType("TiledTest.Tile, TiledTest")]
    public class DemoMapTileContent
    {
        public ExternalReference<Texture2DContent> Texture;
        public Rectangle SourceRectangle;
        public SpriteEffects SpriteEffects;
    }

    // For each layer, we store the size of the layer and the tiles.
    [ContentSerializerRuntimeType("TiledTest.Layer, TiledTest")]
    public class DemoMapLayerContent
    {
        public int Width;
        public int Height;
        public DemoMapTileContent[] Tiles;
    }

    // For the map itself, we just store the size, tile size, and a list of layers.
    [ContentSerializerRuntimeType("TiledTest.Map, TiledTest")]
    public class DemoMapContent
    {
        public int TileWidth;
        public int TileHeight;
        public List<DemoMapLayerContent> Layers = new List<DemoMapLayerContent>();
    }

    [ContentProcessor(DisplayName = "TMX Processor - TiledLib")]
    public class MapProcessor : ContentProcessor<MapContent, DemoMapContent>
    {
        public override DemoMapContent Process(MapContent input, ContentProcessorContext context)
        {
            // build the textures
            TiledHelpers.BuildTileSetTextures(input, context);

            // generate source rectangles
            TiledHelpers.GenerateTileSourceRectangles(input);

            // now build our output, first by just copying over some data
            DemoMapContent output = new DemoMapContent
            {
                TileWidth = input.TileWidth,
                TileHeight = input.TileHeight
            };

            // iterate all the layers of the input
            foreach (LayerContent layer in input.Layers)
            {
                // we only care about tile layers in our demo
                TileLayerContent tlc = layer as TileLayerContent;
                if (tlc != null)
                {
                    // create the new layer
                    DemoMapLayerContent outLayer = new DemoMapLayerContent
                    {
                        Width = tlc.Width,
                        Height = tlc.Height,
                    };

                    // we need to build up our tile list now
                    outLayer.Tiles = new DemoMapTileContent[tlc.Data.Length];
                    for (int i = 0; i < tlc.Data.Length; i++)
                    {
                        // get the ID of the tile
                        uint tileID = tlc.Data[i];

                        // use that to get the actual index as well as the SpriteEffects
                        int tileIndex;
                        SpriteEffects spriteEffects;
                        TiledHelpers.DecodeTileID(tileID, out tileIndex, out spriteEffects);

                        // figure out which tile set has this tile index in it and grab
                        // the texture reference and source rectangle.
                        ExternalReference<Texture2DContent> textureContent = null;
                        Rectangle sourceRect = new Rectangle();

                        // iterate all the tile sets
                        foreach (var tileSet in input.TileSets)
                        {
                            // if our tile index is in this set
                            if (tileIndex - tileSet.FirstId < tileSet.Tiles.Count)
                            {
                                // store the texture content and source rectangle
                                textureContent = tileSet.Texture;
                                sourceRect = tileSet.Tiles[(int)(tileIndex - tileSet.FirstId)].Source;

                                // and break out of the foreach loop
                                break;
                            }
                        }

                        // now insert the tile into our output
                        outLayer.Tiles[i] = new DemoMapTileContent
                        {
                            Texture = textureContent,
                            SourceRectangle = sourceRect,
                            SpriteEffects = spriteEffects
                        };
                    }

                    // add the layer to our output
                    output.Layers.Add(outLayer);
                }
            }

            // return the output object. because we have ContentSerializerRuntimeType attributes on our
            // objects, we don't need a ContentTypeWriter and can just use the automatic serialization.
            return output;
        }
    }
}

TiledLib contains a large amount of files including MapContent.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
using Microsoft.Xna.Framework.Content.Pipeline;

namespace TiledLib
{
    public enum Orientation : byte
    {
        Orthogonal,
        Isometric,
    }

    public class MapContent
    {
        public string Filename;
        public string Directory;

        public string Version = string.Empty;
        public Orientation Orientation;
        public int Width;
        public int Height;
        public int TileWidth;
        public int TileHeight;
        public PropertyCollection Properties = new PropertyCollection();

        public List<TileSetContent> TileSets = new List<TileSetContent>();
        public List<LayerContent> Layers = new List<LayerContent>();

        public MapContent(XmlDocument document, ContentImporterContext context)
        {
            XmlNode mapNode = document["map"];

            Version = mapNode.Attributes["version"].Value;
            Orientation = (Orientation)Enum.Parse(typeof(Orientation), mapNode.Attributes["orientation"].Value, true);
            Width = int.Parse(mapNode.Attributes["width"].Value, CultureInfo.InvariantCulture);
            Height = int.Parse(mapNode.Attributes["height"].Value, CultureInfo.InvariantCulture);
            TileWidth = int.Parse(mapNode.Attributes["tilewidth"].Value, CultureInfo.InvariantCulture);
            TileHeight = int.Parse(mapNode.Attributes["tileheight"].Value, CultureInfo.InvariantCulture);

            XmlNode propertiesNode = document.SelectSingleNode("map/properties");
            if (propertiesNode != null)
            {
                Properties = new PropertyCollection(propertiesNode, context);
            }

            foreach (XmlNode tileSet in document.SelectNodes("map/tileset"))
            {
                if (tileSet.Attributes["source"] != null)
                {
                    TileSets.Add(new ExternalTileSetContent(tileSet, context));
                }
                else
                {
                    TileSets.Add(new TileSetContent(tileSet, context));
                }
            }

            foreach (XmlNode layerNode in document.SelectNodes("map/layer|map/objectgroup"))
            {
                LayerContent layerContent;

                if (layerNode.Name == "layer")
                {
                    layerContent = new TileLayerContent(layerNode, context);
                }
                else if (layerNode.Name == "objectgroup")
                {
                    layerContent = new MapObjectLayerContent(layerNode, context);
                }
                else
                {
                    throw new Exception("Unknown layer name: " + layerNode.Name);
                }

                // Layer names need to be unique for our lookup system, but Tiled
                // doesn't require unique names.
                string layerName = layerContent.Name;
                int duplicateCount = 2;

                // if a layer already has the same name...
                if (Layers.Find(l => l.Name == layerName) != null)
                {
                    // figure out a layer name that does work
                    do
                    {
                        layerName = string.Format("{0}{1}", layerContent.Name, duplicateCount);
                        duplicateCount++;
                    } while (Layers.Find(l => l.Name == layerName) != null);

                    // log a warning for the user to see
                    context.Logger.LogWarning(string.Empty, new ContentIdentity(), "Renaming layer \"{1}\" to \"{2}\" to make a unique name.", layerContent.Type, layerContent.Name, layerName);

                    // save that name
                    layerContent.Name = layerName;
                }

                Layers.Add(layerContent);
            }
        }
    }
}

I'm lost as to why this is failing. Thoughts?


-- EDIT --

After playing with it a bit, I would think it has something to do with referencing the projects. I'm already referencing the TiledLib within my main windows project (TiledTest). However, this doesn't seem to make a difference. I can place the dll generated from the TiledLib project into the debug folder of TiledTest, and this causes it to generate a different error:

Error loading "desert". Cannot find ContentTypeReader for Microsoft.Xna.Framework.Content.Pipeline.ExternalReference`1[Microsoft.Xna.Framework.Content.Pipeline.Graphics.Texture2DContent].

at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.GetTypeReader(Type targetType, ContentReader contentReader) at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.GetTypeReader(Type targetType) at Microsoft.Xna.Framework.Content.ReflectiveReaderMemberHelper..ctor(ContentTypeReaderManager manager, FieldInfo fieldInfo, PropertyInfo propertyInfo, Type memberType, Boolean canWrite) at Microsoft.Xna.Framework.Content.ReflectiveReaderMemberHelper.TryCreate(ContentTypeReaderManager manager, Type declaringType, FieldInfo fieldInfo) at Microsoft.Xna.Framework.Content.ReflectiveReader1.Initialize(ContentTypeReaderManager manager) at Microsoft.Xna.Framework.Content.ContentTypeReaderManager.ReadTypeManifest(Int32 typeCount, ContentReader contentReader) at Microsoft.Xna.Framework.Content.ContentReader.ReadHeader() at Microsoft.Xna.Framework.Content.ContentReader.ReadAsset[T]() at Microsoft.Xna.Framework.Content.ContentManager.ReadAsset[T](String assetName, Action1 recordDisposableObject) at Microsoft.Xna.Framework.Content.ContentManager.Load[T](String assetName) at TiledTest.Game1.LoadContent() in C:\My Documents\Dropbox\Visual Studio Projects\TiledTest\TiledTest\TiledTest\Game1.cs:line 51 at Microsoft.Xna.Framework.Game.Initialize() at TiledTest.Game1.Initialize() in C:\My Documents\Dropbox\Visual Studio Projects\TiledTest\TiledTest\TiledTest\Game1.cs:line 39 at Microsoft.Xna.Framework.Game.RunGame(Boolean useBlockingRun) at Microsoft.Xna.Framework.Game.Run() at TiledTest.Program.Main(String[] args) in C:\My Documents\Dropbox\Visual Studio Projects\TiledTest\TiledTest\TiledTest\Program.cs:line 15

This is all incredibly frustrating as the demo doesn't appear to have any special linking properties. The TiledLib I am utilizing is from Nick Gravelyn, and can be found here: https://bitbucket.org/nickgravelyn/tiledlib.

The demo it comes with works fine, and yet in recreating I always run into this error.

© Game Development or respective owner

Related posts about XNA

Related posts about xna-4.0