MonoGame - загрузка JSON через конвейер контента

Я создаю ролевую игру, и мне нужно загрузить карты с помощью 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";
        }
    }
}

Есть ли лучший способ хранить метаданные тайловой карты? Или есть лучший способ импортировать его через конвейер? Или я что-то не так делаю с моим импортером контента?


person minebolt    schedule 01.04.2019    source источник
comment
Какое сообщение об ошибке связано с падением?   -  person Strom    schedule 01.04.2019
comment
Вы можете добавить настраиваемые свойства в Tiled на карту, на слои и даже на каждый объект, размещенный в Tiled. Я использую TiledSharp вместо Monogame.Extended, но уверен, что он также поддерживает использование настраиваемых свойств.   -  person Pavel Slesinger    schedule 01.04.2019
comment
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information Это сообщение об ошибке из конвейера содержимого.   -  person minebolt    schedule 01.04.2019


Ответы (1)


Ошибка связана с типом dynamic. Конвейер требует, чтобы все типы были разрешаемыми и создаваемыми через Reflection.

Для универсальных коллекций существует вторичный преобразователь для сериализации и десериализации каждого типа в Generic. Строка 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.

person Strom    schedule 02.04.2019