Skip to content

Instantly share code, notes, and snippets.

@manbeardgames
Last active April 24, 2023 00:33
Show Gist options
  • Save manbeardgames/5d6e4a4a09db56f497d37709fb040194 to your computer and use it in GitHub Desktop.
Save manbeardgames/5d6e4a4a09db56f497d37709fb040194 to your computer and use it in GitHub Desktop.
How to use the MonoGame.Extended Json Import for any custom class

MonoGame.Extended JSON Importing

How to use

Overview

MonoGame.Extended provideds a generic JSON importer as part of the MonoGame.Extended.Content.Pipeline.dll. Taking advantage of this and how it's setup for a generic type <T> can allow you to load content through the MGCB Editor that can be deserialized to any custom class type in you code.

Prerequsites

  • This gist assumes you are using MonoGame 3.8. The steps should be similar for MonoGame 3.7, however, no guarentees are made
  • The steps outlined here are going to be using Visual Studio 2019. You can also do this from Visual Studio Code, however steps will assume Visual Studio 2019.

License

A porition of this gist displays some source code for reference from the MonoGame.Extended project. MonoGame.Extended is licences under the MIT License, which can be view here

For the purposes of copyright for all other code written in this gist, I am releasing it into the public domain under The Unlicense.

Completed Reference

To see the completed project created by this gist for reference, you can find it at https://github.com/manbeardgames/monogame-extended-json-import

Create Example Project

For the purposes of this gist, create a new MonoGame Cross-Platform Desktop Application (OpenGL) project. Name the project JsonImportTest. Information on creating a new project can be found on the official docuemntation.

Obtaining the NuGet Packages.

In our project, we'll need to add two NuGet packages from MonoGame.Extended.To add the NuGet packages, perform the following

  1. Right-click your project in the Solution Explorer panel and select Manage NuGet Packages from the context menu to open the NuGet Package Manager window.
  2. Click the Browse tab in the window
  3. Enter MonoGame.Exteneded into the search bar
  4. Click the MonoGame.Extended result (should be the first one), the select Install from the right hand side of the window.
  5. Next, in the result set, find MonoGame.Extended.Content.Pipeline, click it, then click Install from the right hand side of the window.

Doing this will add download both NuGet pacakges. The MonoGame.Extended pacakge will be automaticaly referenced for your project, however we need to setup the MonoGame.Extended.Content.Pipeline reference manually.

Adding Content Pipeline Reference

In the Solution Explorer panel, locate the Content\Content.mgcb file in your project and open it. This should automatically open it in the MGCB Edtior application window. If instead it opens it as a text file to edit, close the file, then right-click the Content.mgcb file in the Solution Explorer panel, and select Open With from the context menu. Then, locate the mgcb-editor-wpf item in the list, click the Set as Default button, then click the Ok button.

From the MGCB Editor application window, click the Content node in the Project panel. Next, under the Properties panel, scroll down down to the References property and click the empty space beside it to modify it. This will open the Reference Editor window. From here click the Add button.

You'll need to navigate to the location where NuGet placed the MonoGame.Extended.Content.Pipeline.dll file. By default if you haven't adjusted any settings with NuGet, this will be located in the following directory:

C:\Users\[username]\.nuget\packages\monogame.extended.content.pipeline\3.8.0\tools

Where [username] is your window account username. Once you've located the dll file, select it and click Open in the open file dialog window. Then click the Ok button in the Reference Editor window. That's it, we've now added all the references to MonoGame.Extended we need.

Create Actor Class

For the purposes of this gist, we'll create an Actor class in our game project. This will be the class that the JSON we create will be imported and deserialzied into for our game. Right-click the project in the Solution Explorer panel and select Add > Class from the context menu. Name the class file Actor.cs. Add the following to the class file

namespace JsonImportTest
{
    public class Actor
    {
        public string Name { get; set; }
        public int Health { get; set; }
        public int Defense { get; set; }
        public int Attack { get; set; }
    }
}

This is a simple class for the example. It defines an actor in the game that has a Name, Health, Defense, and Attack values. Now that we've created the class we want our imported JSON to deserialize to, we need to create a ContentTypeReader that the ContentManager will use when reading our JSON content file.

Create the ContentTypeReader

The ContentTypeReader that we create will be what the ContentManager calls when we tell it to load the content file using the Content.Load<T>(string) method. Thankfully, MonoGame.Extended has a very generic ContentTypeReader we can utilize to make setting this up super easy. We just need to inherit from it and set the correct type.

To do this, we need to create a new class file in our project. Right-click the project in the Solution Explorer window and select Add > Class. Name it ActorReader.cs. Add the following code to the file.

using MonoGame.Extended.Serialization;

namespace JsonImportTest
{
    public class ActorReader : JsonContentTypeReader<Actor> { }
}

That's it. That's all we need. So what exactly is going on here? Our ActorReader class is inheriting from the JsonContentTypeReader<T> class from the MonoGame.Extended library. We set the <T> type to our Actor class type. Next, let's take a look under the hood at what that class we inherit from is doing.

(don't add the following code to anything, this is just the code reference to the JsonContentTypeReader<T> class from the MonoGame.Extended source code.

public class JsonContentTypeReader<T> : ContentTypeReader<T>
{
    protected override T Read(ContentReader reader, T existingInstance)
    {
        var json = reader.ReadString();

        using (var stringReader = new StringReader(json))
        using (var jsonReader = new JsonTextReader(stringReader))
        {
            var serializer = new JsonSerializer();
            return serializer.Deserialize<T>(jsonReader);
        }
    }
}

From this, we can see that all it is doing is reading the json string from our content file, then uses the JSON.NET library to deserialize the JSON into whatever the type of <T> is, which is Actor in the case of our class we created.

Next, let's add create the JSON file.

Create a JSON file

For the purposes of this gist, create a new JSON file somewhere on your computer named actor.json. Add the following to the file

{
    "Name": "ManBeardGames",
    "Health": 100,
    "Defense": 50,
    "Attack": 20
}

This JSON describes an actor in our game, and the Name, Health, Defense, and Attack values. An important thing to note here is that the json property names need to match the property names from our Actor class, character case and all.

Next we'll add the JSON file as content for our game.

Adding JSON File As Content

If you closed the MGCB Editor application window we opened previously, go ahead and open it again now by double-clicking the Content\Content.mgcb file under the project in the Solution Explorer window. Once opened, locate the Project panel and right-click the Content node, then select Add > Existing Item. Locate and open the actor.json file we just created in the previous section.

Next, select the actor.json item in the project panel. Once selected, in the Properties panel, change the Importer to JSON Importer - MonoGame .Extended. Doing this should automatically change the Processor to JSON Processor - MonoGame.Extended. If not, change it manually yourself.

Finally, in the Properties panel, we need to input a value for the ContentType processor paramater. This value has to be very specific and exact, otherwise when loading the content in game, it will fail. The format value must be the following:

[namespace].[className], [assembly]

The following table describes what each of these values are

Name Description
[namespace] This is the full namespace path of the ContentTypeReader that is used to read the content file.
[className] The name of the ContentTypeReader class that is used to read teh content file.
[assembly] This is the root namespace of the assembly of your project (or of the project assembly that the ContentTypeReader resides in). Typically this is the name of your project unless you have changed this in the class files manually

So, for the purposes of this gist, the example project is called JsonImportTest. This is the [assembly] value we'll use. The ContentTypeReader class we created is the ActorReader class, and the namespace it is in is JsonImportTest. This means the value we need to use for the processor parameter is

JsonImportTest.ActorReader, JsonImportTest

The values have to be exactly the way they are in your project. No extra leading or trailing spaces at the end of the value.

Once you've added the value click on the ContentType label beside it so the value gets set in the textbox, then click the Save button the top of the MGCB Editor window, then close the window.

Loading Content In Game

Now, whenever you need to load the actor.json content file in game, you can do it the same way you would load any content with the ContentManager. To finish off our example, open the Game1.cs class file in the project, located the LoadContent() method and add the following to it:

Actor actor = Content.Load<Actor>("actor");

If you set a breakpoint after it then run the game in Debug, you can look at the values of the instance that's created and confirm that the contents of the json was deserialized properly into it.

Conclusion

In this gist, we went over the steps needed to use the MonoGame.Extended JSON Importer, including adding project and pipeline references, and creating the example ContentTypeReader class needed to read the content.

@neller19
Copy link

Thanks for this, i have been struggling to get this to work for ages, could not find anything in the Monogame.Extended documentation about the ContentType property format, which was my issue.

@jalbr74
Copy link

jalbr74 commented Feb 21, 2023

I've been struggling with this as well. Thank you so much for taking the time to write this!

@wazawoo
Copy link

wazawoo commented Mar 9, 2023

Thanks for this! It takes waaaay too much effort to literally read a json file with Monogame...

@adothelimey
Copy link

Great writeup - thankyou!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment