#c# #json #monogame
#c# #json #моногейм
Вопрос:
Я создаю RPG-игру, и мне нужно загрузить карты с помощью Tiled. У меня закрыта фрагментированная часть (я использую MonoGame.Extended
). Но мне нужны дополнительные данные о карте. Мой план состоит в том, чтобы использовать файл JSON, который содержит необходимую информацию. Тем не менее, я хотел бы использовать его через конвейер содержимого, поскольку он напрямую связан с картами листов.
Я попытался использовать пользовательское расширение конвейера контента. Он использовался JSON.Net
для десериализации файла JSON в Dictionary<string, dynamic>
. Однако, когда я компилировал DLL-файл и пытался ссылаться на него в инструменте конвейера, инструмент конвейера всегда выходил из строя.
Импортер контента:
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;
using Newtonsoft.Json;
namespace JsonExtension
{
[ContentImporter(".json", DefaultProcessor = "JsonProcessor")]
public class JsonImporter : ContentImporter<Dictionary<string, dynamic>>
{
public override Dictionary<string, dynamic> Import(string filename, ContentImporterContext context)
{
context.Logger.LogMessage("Importing JSON file: {0}", filename);
using (var streamReader = new StreamReader(filename))
{
JsonSerializer serializer = new JsonSerializer();
return (Dictionary<string, dynamic>)serializer.Deserialize(streamReader, typeof(Dictionary<string, dynamic>));
}
}
}
}
Обработчик содержимого:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content.Pipeline;
namespace JsonExtension
{
[ContentProcessor]
public class JsonProcessor : ContentProcessor<Dictionary<string, dynamic>, Dictionary<string, dynamic>>
{
public override Dictionary<string, dynamic> Process(Dictionary<string, dynamic> input, ContentProcessorContext context)
{
context.Logger.LogMessage("Processing JSON");
return input;
}
}
}
Средство записи типов содержимого:
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
using Newtonsoft.Json;
namespace JsonExtension
{
[ContentTypeWriter]
class JsonTypeWriter : ContentTypeWriter<Dictionary<string, dynamic>>
{
protected override void Write(ContentWriter output, Dictionary<string, dynamic> value)
{
output.Write(JsonConvert.SerializeObject(value));
}
public override string GetRuntimeType(TargetPlatform targetPlatform)
{
return typeof(Dictionary<string, dynamic>).AssemblyQualifiedName;
}
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return "JsonExtension.JsonReader";
}
}
}
Есть ли лучший способ хранить метаданные плиточной карты? Или есть лучший способ импортировать его через конвейер? Или я делаю что-то не так с моим импортером контента?
Комментарии:
1. Какое сообщение об ошибке связано с аварийным завершением работы?
2. Вы можете добавлять пользовательские свойства в Tiled к карте, слоям и даже к каждому объекту, размещенному в Tiled. Я использую TiledSharp вместо Monogame. Расширенный, но я уверен, что он также поддерживает использование пользовательских реквизитов.
3.
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information
Это сообщение об ошибке из конвейера содержимого
Ответ №1:
Ошибка связана с dynamic
типом. Конвейер требует, чтобы все типы разрешались и создавались посредством отражения.
Для универсальных коллекций существует вторичный преобразователь для сериализации и десериализации каждого типа в универсальном. Строка Dictionary<string, dynamic>
имеет два типа и и связанный с ними непознаваемый тип System.Collections.Generic.Dictionary
, System.String
и dynamic
. dynamic
Не содержит подсказок относительно того, какой тип использовать, и не может быть разрешен, что приводит к ошибке.
Простое решение состоит в том, чтобы сохранить данные в виде строки json (что вы уже делаете сейчас, за исключением того, что тип, в котором вы пытаетесь их сохранить, является dynamic
) и десериализовать String
в свой объект после того, как Content.Load
вернет данные.
Другими словами, использовать Dictionary<string, string>
в качестве типа процессора содержимого.
Более простым решением было бы скопировать JSON
файл в выходной каталог. Создайте действие «копировать, если новее» и используйте System.IO.File, чтобы прочитать его и JSON.NET
десериализовать в объект в Initialize
методе Game1.