Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a problem at the moment loading in a texture for a larger model in the content pipeline. Now it seems that I need to make a proxy object, which is fine, however looking at the SpriteSheet example provided by Microsoft they seem to use the ContentSerializerRuntimeType attribute to bind the proxy class to the real class for use at runtime.

The problem is they sprinkle serialization attributes all over the runtime class, so I was wondering if you HAVE to do it this way or if it is just a recommendation, and is there any other way of getting your proxy class to the real instance?

Ideally I dont want to have to put attributes all over my classes and would be more than happy to write the serialization code myself if there was a way to, but it seems to be an unknown as far as the documentation goes for this area...

So anyone know a way round this, or is this just the only way to do it?

share|improve this question
    
Implement ContentTypeReader/Writer. Think you still need the COntentSerializerRuntimeType attribute. –  George Duckett Jan 16 '12 at 8:47
1  
    
@george-duckett I thought maybe this was what I needed, but there was hardly any information on what you should be doing with a ContentTypeReader/Writer, as I presumed it would be a stage after the compile time xnb compilation and you would just take out the data and put it into your object, but it didnt seem to return any meaningful data from the methods you have to override... Will take a look at that page, I had read a few posts from Shawn's blog but I just went to where google directed me, will look through these and see if anything points me in the right direction. –  Grofit Jan 16 '12 at 9:15
1  
There are templates for implementing ContentTypeReaders/Writers in visual studio express when XNA is installed. –  George Duckett Jan 16 '12 at 9:30
    
There is? I just made a default class library and extended the classes from there. Will take a look, but an article or tutorial on the matter would go a long way to giving me and others a better understanding of these more niche/complex usages of the content pipeline. –  Grofit Jan 16 '12 at 9:37
add comment

1 Answer

up vote 5 down vote accepted

If you want to avoid adding attributes to your classes (required for automatic reading/writing) then you'll want to implement a ContentTypeReader and ContentTypeWriter


Here's my runtime class that I want to load:

public class ComponentPropertyGetMathExpression : MathExpression
{
    public Type ComponentType;
    public string PropertyName;

    public ComponentPropertyGetMathExpression()
    {

    }

    // methods removed
}

I have 2 fields I want to get the values for.

One interesting thing here is, one of them has the type Type, which doesn't have a public parameterless constructor. You'd get weird errors if you tried to use the default reader/writer because of this, so this is a real example of when you would need to implement your own.


The first thing, is to create a Content version of this class in a seperate project, that will references the project with the runtime type and will be referenced by the content project:

[ContentSerializerRuntimeType("FuzzyDuckEntertainment.Entities.Templates.Expressions.ComponentPropertyGetMathExpression, FuzzyDuckEntertainment.Entities")]
public class ComponentPropertyGetMathExpressionContent : MathExpressionContent
{
    public string ComponentType;
    public string PropertyName;

    public ComponentPropertyGetMathExpressionContent()
    {
    }

    // Runtime methods not needed - this class is simply a container of fields/properties
}

The ContentSerializerRuntimeType attribute tells the pipeline what type this will represent at runtime.

Note that the ComponentType field was a Type at runtime, but here it's a string. This is because of the lack of public parameterless constructor as noted above. Another time you might have different types is when the runtime type is something GPU related, for example a Texture2D (in which case you might have ExternalReference<Texture2D> and use a ContentProcessor).


Now we have our 2 types.

I'm going to use the built in XML Importer to go from an XML file to a ComponentPropertyGetMathExpressionContent object and no Processor. A case where you might use your own importer is if you have a heightmap BMP and want to generate vertex data. An example of using a processor is the Font Texture Processor that creates a game Font from a Texture.

Now we need to get from the content type, to the runtime type.

First, lets create the class that writes the XNB file at build time:

[ContentTypeWriter]
public class ComponentPropertyGetMathExpressionContentWriter : ContentTypeWriter<ComponentPropertyGetMathExpressionContent>
{
    protected override void Write(ContentWriter output, ComponentPropertyGetMathExpressionContent value)
    {
        output.Write(value.ComponentType);
        output.Write(value.PropertyName);
    }

    public override string GetRuntimeReader(TargetPlatform targetPlatform)
    {
        return typeof(ComponentPropertyGetMathExpressionReader).AssemblyQualifiedName;
    }

    public override string GetRuntimeType(TargetPlatform targetPlatform)
    {
        return typeof(ComponentPropertyGetMathExpression).AssemblyQualifiedName;
    }
}

Hopefully the above should be self explanatory (note the order we write the fields in).


The reader is implemented as below:

public class ComponentPropertyGetMathExpressionReader : ContentTypeReader<ComponentPropertyGetMathExpression>
{
    protected override ComponentPropertyGetMathExpression Read(ContentReader input, ComponentPropertyGetMathExpression existingInstance)
    {
        if (existingInstance == null)
            existingInstance = new ComponentPropertyGetMathExpression();

        existingInstance.ComponentType = Type.GetType(input.ReadString());
        existingInstance.PropertyName = input.ReadString();

        return existingInstance;
    }
}

Note the order we read things in. Also note that the first thing we read is the string that correspond to the ComponentType property. As the runtime type in this case is Type, not string I need to do some simple translation. Ideally you want any translations like this to be as minimal as possible, as unlike anything before, this will run when the game is loading.


See also:

What Is Content? (MSDN)
Using an XML File to Specify Content (MSDN)
Shawn Hargreaves' Blog Index #Content Pipeline

share|improve this answer
    
Thanks for taking the time to write this, I just hope others can find this post if they are in the same position as me. –  Grofit Jan 16 '12 at 10:20
    
Any queries, let me know and i'll edit in. –  George Duckett Jan 16 '12 at 10:24
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.