Загрузка текстур из ссылки на встроенный контент в 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;
}
}