Загрузка текстур из ссылки на встроенный контент в XML-файл

цель

я пытаюсь загрузить пользовательский класс, который содержит Texture2D из xml-файла, использующего импортер по умолчанию (содержимое XML), без процессора.


подход

много исследований в интернете и много работы с другими ошибками приводят меня к этому 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 SettingsGDuckettMy DocumentsVisual Studio 2010ProjectsGravitronGravitronGravitronbinx86DebugContentBullet.xnb</ExternalReference>
  </ExternalReferences>
</XnaContent>

Да, мне тоже не нравится жестко закодированный путь, но если я могу заставить это работать без пользовательского читателя и / или писателя для каждого типа, содержащего Texture2D i может жить с этим.

ниже приведена моя версия содержимого класса (используется конвейером):

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

    public EntityTemplateContent()
    {

    }
}

ниже приведена моя версия выполнения:

public class EntityTemplate
{
    public string Name;
    public Texture2D TestTexture;

    public EntityTemplate()
    {

    }
}

1 ответов


точное сообщение об ошибке было вызвано наличием другого Texture2D поле в объекте контент.

общая проблема получения ссылки на тип среды выполнения из ExternalReference<T> в типе контента было решено с помощью ниже.

в настоящее время это действительно концептуальный класс, как таковой, он работает для классов, которые я бросил на него до сих пор, но, вероятно, столкновение с чем-то более сложным.

он использует отражение для преобразования любых полей или свойств входные данные, которые ExternalReference<T> ' s в встроенные версии типа, запрошенного путем создания соответствующей версии ContentProcessorContext.BuildAsset<T,T> и ссылающегося на него. Это повторяется вниз по дереву объектов, чтобы сделать то же самое для ссылки на другие объекты.

[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;
    }
}