Loading textures from an embedded content link in an XML file

goal

I am trying to load a custom class containing Texture2D from an XML file using the default importer (XML content) without a processor.


An approach

A lot of research on the Internet and a lot of problems with other errors lead me to this XML:

 <?xml version="1.0" encoding="utf-16"?> <XnaContent xmlns:Components="Entities.Components"> <Asset Type="EntitiesContentPipeline.EntityTemplateContent"> <Name>entity name</Name> <TestTexture> <Reference>#External1</Reference> </TestTexture> </Asset> <ExternalReferences> <ExternalReference ID="#External1" TargetType="Microsoft.Xna.Framework.Graphics.Texture2D">C:\Documents and Settings\GDuckett\My Documents\Visual Studio 2010\Projects\Gravitron\Gravitron\Gravitron\bin\x86\Debug\Content\Bullet.xnb</ExternalReference> </ExternalReferences> </XnaContent> 

Yes, I also don’t like the hard-coded path, but if I can make it work without a custom reader and / or record for each type containing Texture2D , I can live with it.

Below is my version of the contents of the class (used by the pipeline):

 [ContentSerializerRuntimeType("Entities.Content.EntityTemplate, Entities")] public class EntityTemplateContent { public string Name; public ExternalReference<Texture2D> TestTexture; public EntityTemplateContent() { } } 

Below is my version of execution:

 public class EntityTemplate { public string Name; public Texture2D TestTexture; public EntityTemplate() { } } 

Problem

If I try to do var test = Content.Load<EntityTemplate>("BulletTemplate"); below, this is the error I get:

Error loading "Bullet". ContentTypeReader Microsoft.Xna.Framework.Content.Texture2DReader, Microsoft.Xna.Framework.Graphics, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553 conflicts with the existing Microsoft.Xna.Framework.Content.ReflectiveReader`1 [[Microsoft .Xna.Framework.Graphics.Texture2D, Microsoft.Xna.Framework.Graphics, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553]], Microsoft.Xna.Framework, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 842cf8be1de50553 for type Microsoft.Xna.Framework.Graphics.Texture2D.

It seems that the reader during operation found 2 readers to work with the Texture2D asset, the ReflectiveReader<Texture2D> Texture2DReader and Texture2DReader .


Question

How can I solve this problem, so I get a properly populated object, with the Texture2D property referring to the loaded texture?

Note. I don't want to add another row property and create a method for my object named LoadContent or something like that. I would like Content.Load be the only thing I needed to call.

I also want not to write my own readers / writers for each type containing the Texture2D property.

Ideally, I want to avoid creating a wrapper class for Texture2D or a subclass, but if there is no alternative, I will be happy for the solution that does this.

+6
source share
1 answer

The exact error message was caused by the presence in the object of the contents of another field Texture2D .

The general problem of getting a runtime type reference from an ExternalReference<T> in a content type has been resolved using below.

This is currently really a concept proof class, as it works for the classes that I have sketched so far on it, but it will probably work with something more complex.

It uses reflection to convert any input fields or properties that ExternalReference<T> into inline versions of the type requested by creating the appropriate version of ContentProcessorContext.BuildAsset<T,T> and invoking it. It recurses down the tree of objects to do the same for references to other objects.

 [ContentProcessor(DisplayName = "ExternalRefObjectContentProcessor")] public class ExternalRefObjectContentProcessor : ContentProcessor<object, object> { private void ReplaceReferences(object input, ContentProcessorContext context) { Func<ExternalReference<object>, string, object> BuildAssetMethodTemplate = context.BuildAsset<object, object>; var BuildAssetMethod = BuildAssetMethodTemplate.Method.GetGenericMethodDefinition(); foreach (var field in input.GetType().GetFields().Where(f => !f.IsStatic && !f.IsLiteral)) { Type fieldType = field.FieldType; object fieldValue = field.GetValue(input); if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(ExternalReference<>)) { var GenericBuildMethod = BuildAssetMethod.MakeGenericMethod(fieldType.GetGenericArguments().First(), fieldType.GetGenericArguments().First()); object BuiltObject; try { BuiltObject = GenericBuildMethod.Invoke(context, new object[] { fieldValue, null }); } catch (Exception Ex) { throw Ex.InnerException; } field.SetValue(input, BuiltObject); } else if (fieldValue is IEnumerable && !(fieldValue is string)) { foreach (var item in (fieldValue as IEnumerable)) { ReplaceReferences(item, context); } } else if (fieldValue != null && !(fieldValue is string)) { ReplaceReferences(fieldValue, context); } } foreach (var property in input.GetType().GetProperties().Where(p => p.CanRead && p.CanWrite)) { Type propertyType = property.PropertyType; object propertyValue = property.GetValue(input, null); if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(ExternalReference<>)) { var GenericBuildMethod = BuildAssetMethod.MakeGenericMethod(propertyType.GetGenericArguments().First(), propertyType.GetGenericArguments().First()); object BuiltObject; try { BuiltObject = GenericBuildMethod.Invoke(context, new object[] { property.GetValue(input, null), null }); } catch (Exception Ex) { throw Ex.InnerException; } property.SetValue(input, BuiltObject, null); } else if (propertyValue is IEnumerable && !(propertyValue is string)) { foreach (var item in (propertyValue as IEnumerable)) { ReplaceReferences(item, context); } } else if (propertyValue != null && !(propertyValue is string)) { ReplaceReferences(propertyValue, context); } } } public override object Process(object input, ContentProcessorContext context) { ReplaceReferences(input, context); return input; } } 
0
source

Source: https://habr.com/ru/post/903358/


All Articles