-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3fa1946
commit 76ea26a
Showing
29 changed files
with
1,550 additions
and
4 deletions.
There are no files selected for viewing
131 changes: 131 additions & 0 deletions
131
articles/getting_to_know/howto/content_pipeline/HowTo_Add_XML.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
--- | ||
title: How to add a custom XML Content File to a Project? | ||
description: Describes how to add custom game data as an XML file through the Content Pipeline. | ||
requireMSLicense: true | ||
--- | ||
|
||
Custom game data that is expressed in an XML format can be easily integrated into your game through the MonoGame Content Pipeline. | ||
|
||
This example demonstrates the procedure for integrating custom XML data into the content project of a simple game for the Windows platform. | ||
|
||
> [!IMPORTANT] | ||
> This tutorial assumes you are using Visual Studio as your IDE, for VSCode, follow [this guide from Microsoft](https://learn.microsoft.com/en-us/dotnet/core/tutorials/library-with-visual-studio-code?pivots=dotnet-8-0) for creating multi-project solutions from the command-line utilizing the MonoGame Project and MonoGame Class library templates. | ||
### To define game data | ||
|
||
Within the MonoGame solution, you create a new Windows Game Library project. | ||
|
||
1. Right-click the solution node, point to `Add`, click `New Project`, and then select the `MonoGame Game Library` template. | ||
|
||
> [!TIP] | ||
> A `MonoGame Game Library` project is created instead of a Content Pipeline Extension Library project so that the class we will define can be used by both the [Content Importer](https://docs.monogame.net/api/Microsoft.Xna.Framework.Content.Pipeline.ContentImporter-1.html) that runs at build-time and the [Content Loader](xref:Microsoft.Xna.Framework.Content.ContentManager#Microsoft_Xna_Framework_Content_ContentManager_Load__1_System_String_) at game runtime. | ||
> [!IMPORTANT] | ||
> For MonoGame `3.8.2` and below, make sure to keep the project at `.NET 6` or below. The MGCB tool for 3.8.2 CANNOT understand or read .NET 8 libraries as it is compiled with .NET 6. The Game project can use a higher version, but library projects must stay at `.NET 6` else they cannot be read. | ||
2. In the `Name` box, type `MyDataTypes`, and then click `OK`. | ||
|
||
3. In the `Solution Explorer`, delete the existing `Game1.cs` as it is not needed. | ||
|
||
4. `right-click` and select `Add -> Add New Item` to add a new class, call it `PetData.cs` | ||
|
||
5. Double click on `PetData.cs` and replace its contents with the following code to define the `PetData` class. | ||
|
||
```csharp | ||
namespace MyDataTypes | ||
{ | ||
public class PetData | ||
{ | ||
public string Name; | ||
public string Species; | ||
public float Weight; | ||
public int Age; | ||
} | ||
} | ||
``` | ||
|
||
6. Build the `MyDataTypes` project for debug or release to generate the library's dll file (note which profile you used). | ||
|
||
### Add an XML file using the custom data to the game content | ||
|
||
In this procedure, the `MyDataTypes` library is added as a reference in the content project. | ||
|
||
1. Build the `MyDataTypes` project, making not of whether it is a `Debug` or `Release` build. | ||
|
||
> [!NOTE] | ||
> It is recommended to always use the same built type for building library projects, as they normally only contain "types" it is safe to just build them as `Release`. The reason being that you cannot CHANGE the reference once made in the MGCB editor and it is not affected by the `Build Type` used to generate the project. | ||
|
||
2. In the `Solution Explorer` or your game project, `right-click` the game content folder, point to `Add`, and then click `New Item`. | ||
|
||
3. In the `Add New Item` dialog box, type `pets.xml` as the file name, and then click `OK`. | ||
|
||
4. Replace the contents of the template file with the following XML code: | ||
|
||
```xml | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<XnaContent> | ||
<Asset Type="MyDataTypes.PetData[]"> | ||
<Item> | ||
<Name>Fifi</Name> | ||
<Species>Dog</Species> | ||
<Weight>11</Weight> | ||
<Age>6</Age> | ||
</Item> | ||
<Item> | ||
<Name>Bruno</Name> | ||
<Species>Dog</Species> | ||
<Weight>21</Weight> | ||
<Age>12</Age> | ||
</Item> | ||
<Item> | ||
<Name>Chloe</Name> | ||
<Species>Cat</Species> | ||
<Weight>6</Weight> | ||
<Age>3</Age> | ||
</Item> | ||
<Item> | ||
<Name>Pickles</Name> | ||
<Species>Hamster</Species> | ||
<Weight>0.4</Weight> | ||
<Age>1</Age> | ||
</Item> | ||
</Asset> | ||
</XnaContent> | ||
``` | ||
|
||
> [!TIP] | ||
> TO learn how to generate the custom MonoGame XML content from your own classes, refer to the [How to Generate custom XML](HowTo_GenerateCustomXML.md) guide. | ||
|
||
5. Open the `MGCB Editor` from the `Game` project (not the library) by selecting the `.mgcb` file and either Double-clicking it (Visual Studio) or Right-clicking it and selecting `Open` (VSCode). | ||
|
||
> [!TIP] | ||
> If you have any issues opening the MGCB content project, please refer to the [How to load content](HowTo_GameContent_Add.md) guide. | ||
|
||
6. In the `MGCB Editor`, select the "Content" node and the top and then locate the `References` section in the `Properties` window, as shown below: | ||
|
||
[MGCB Editor window properties](./images/mgcb_editor_content_properties_referencesSelected.png) | ||
|
||
7. Click the `References` VALUE field and a new window should pop up allowing you to manage the references for the MGCB project: | ||
|
||
[MGCB editor references window](./images/mgcb_editor_references_window.png) | ||
|
||
8. In the `Reference Editor` window, click `Add`, and navigate to the `MyDataTypes` project and locate the built `dll`, normally under `bin/release/net8.0` (or DEBUG if you use the debug build). Once selected, click `Open` and the reference should be added to the Reference Editor as shown above. | ||
|
||
> [!TIP] | ||
> If the folder is empty, return to visual studio and build the `MyDataTypes` project, if it is not built, there is no dll. | ||
> And make sure to choose either the `debug` or `release` folder depending on how the class library is built. | ||
|
||
9. Click on `Add Existing` from the `Edit -> Add` options in the menu (or the `Add Existing` toolbar button) and select the `pets.xml` file. | ||
|
||
When you press `F6` to build the solution, it should build successfully, including the custom game content imported from the XML file. | ||
|
||
> [!IMPORTANT] | ||
> Adding the the class library of the data types project to the Content project is critical, else the Content Pipeline does not know how to serialize or deserialize the custom data you have defined. | ||
> Although it is possible to simply serialize `value types` or `value type arrays` without this step. | ||
|
||
To load the data at runtime, see the tutorial [Loading XML Content at Runtime](HowTo_Load_XML.md). | ||
|
||
## See Also | ||
|
||
- [Using an XML File to Specify Content](HowTo_UseCustomXML.md) | ||
- [Adding Content to a Game](HowTo_GameContent_Add.md) |
206 changes: 206 additions & 0 deletions
206
articles/getting_to_know/howto/content_pipeline/HowTo_ExtendFontProcessor.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
--- | ||
title: How to Extend the Font Description Processor to Support Additional Characters? | ||
description: Describes the process of developing a custom content processor needed to add additional characters to a FontDescription object based on the text that is required by the game. | ||
requireMSLicense: true | ||
--- | ||
|
||
In a font description (.spritefont) file, the `<CharacterRegions>` area can be used to add additional characters to a font description. This enables you to use a [SpriteFont](xref:Microsoft.Xna.Framework.Graphics.SpriteFont) to render an additional range of characters. | ||
|
||
For some languages, this approach is not ideal. For example, Chinese and Japanese both have many thousands of characters. Adding the full range of characters to `<CharacterRegions>` dramatically increases the size of the font asset and the time required to build the font asset. A better solution adds individual characters whenever the specific characters are needed. You can create a custom content processor to implement this solution. | ||
|
||
In this example, a file called _messages.txt_ contains all the text rendered by the game. The custom processor adds all the characters contained in the text in this file to a [FontDescription](xref:Microsoft.Xna.Framework.Content.Pipeline.Graphics.FontDescription). Then it processes the object in the standard way using the base [FontDescriptionProcessor](xref:Microsoft.Xna.Framework.Content.Pipeline.Processors.FontDescriptionProcessor) functionality. All the characters in messages.txt will then be available to the [SpriteFont](xref:Microsoft.Xna.Framework.Graphics.SpriteFont) object at run time. | ||
|
||
> [!IMPORTANT] | ||
> This tutorial assumes you are using Visual Studio as your IDE, for VSCode please adapt the IDE interactions appropriately. | ||
## Using the Font Description Processor | ||
|
||
1. create a new MonoGame project called `FontGame` using the MonoGame template of your choice (for simplicity choose a desktop template) | ||
|
||
2. Add a new `SpriteFont` called `DefaultFont` to a game project by opening the MGCB Editor, then right-click the `Content` node, click **Add**, and then click **New Item**. | ||
|
||
3. Add the new SpriteFont to the game by selecting the **SpriteFont Description (.spritefont)** template, name the font `DefaultFont` and then click **Add**. | ||
|
||
![Adding the `DefaultFont` SpriteFont](./images/mgcg_editor_new_spritefont.png) | ||
|
||
4. Modify this file to use an existing font and any additional characteristics you prefer. | ||
|
||
For more information, see [Sprite Font XML Schema Reference](../../whatis/Content_Pipeline/CP_SpriteFontSchema.md). | ||
|
||
5. Add a new text file named `messages.txt` to the game project by right-clicking on the FontGame project node in Solution Explorer, click **Add**, and then click **New Item**. | ||
|
||
6. Select the **Text File** template, enter **messages.txt** for the file name, and then click **Add** to add the text file to the game. | ||
|
||
7. In the new text file, enter any messages that will be printed by the font described in the Sprite Font file. | ||
|
||
> We will use the method [File.ReadAllText](http://msdn.microsoft.com/en-us/library/ms143369.aspx) to read the text in this file. This method requires a carriage return ("\\r") or line feed ("\\n") after the last string, so be sure to follow the last line of text in the file with a carriage return or line feed. | ||
### To create the new content processor project | ||
|
||
The Content Pipeline is part of the build process and it is separate from your game code, therefore you need to create a new assembly that contains the code developed in this topic. Creating this new assembly project is the first step in developing a new processor. | ||
|
||
1. To add the new processor project to the game solution, go to Solution Explorer, right-click the **Solution** node, click **Add**, and then click **New Project**. | ||
|
||
2. In the dialog box, select the template **MonoGame Content Pipeline Extension (MonoGame Team))**, enter `MyFontProcessor` in the **Name** field, and then click **OK**. The new project automatically contains references to the MonoGame Framework run-time and design-time Content Pipeline assemblies. | ||
|
||
### To extend the font processor | ||
|
||
1. Open the `Processor1.cs` which is the template Content Processor example. | ||
|
||
1. Add the following lines of code, after the last `using` statement: | ||
|
||
```csharp | ||
using System.IO; | ||
using System.ComponentModel; | ||
``` | ||
|
||
1. Remove the placeholder code that assigns the processor input (`TInput`) and output (`TOutput`) types, including the `Process" method. They will not be needed. | ||
|
||
1. Change the base class of `Processor1` from [ContentProcessor<TInput, TOutput>](xref:Microsoft.Xna.Framework.Content.Pipeline) to [FontDescriptionProcessor](xref:Microsoft.Xna.Framework.Content.Pipeline.Processors.FontDescriptionProcessor), which identifies it as a SpriteFont processor. | ||
|
||
> [NOTE] | ||
> You can read all about the different types of built-in processors in the API docs [Content.Pipeline.Processors](xref:Microsoft.Xna.Framework.Content.Pipeline.Processors) | ||
|
||
1. Change the class name and the Processor display name to something a little more unique, so that we know which processor we are selecting, from "Processor1" to "**MyFontProcessor**". | ||
|
||
```csharp | ||
[ContentProcessor(DisplayName = "MyFontProcessor")] | ||
internal class MyFontProcessor : FontDescriptionProcessor | ||
``` | ||
|
||
1. Add a new processor parameter (property) to the the class declaration and adorn it with [C# Attributes](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/reflection-and-attributes/) to state additional processing parameters for the property. | ||
|
||
This parameter stores the name of the text file that stores the messages displayed by the game. | ||
|
||
```csharp | ||
[DefaultValue("messages.txt")] | ||
[DisplayName("Message File")] | ||
[Description("The characters in this file will be automatically added to the font.")] | ||
public string MessageFile | ||
{ | ||
get { return messageFile; } | ||
set { messageFile = value; } | ||
} | ||
private string messageFile = @"../messages.txt"; | ||
``` | ||
|
||
> [!NOTE] | ||
> As the "messages.txt" file is not in our content project, we need to supply a path "relative" to the "Content" project where the Content Processor is running from. | ||
> Hence the path to the file is denoted as `@"../messages.txt"`. | ||
|
||
1. Add a new [Process](xref:Microsoft.Xna.Framework.Content.Pipeline.Processors.FontTextureProcessor) method override to match the following code: | ||
|
||
```csharp | ||
public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) | ||
{} | ||
``` | ||
|
||
This modification replaces the template parameter and return types with the proper types needed for the extended font processor. | ||
|
||
1. Inside the `Process` method, register a Content Pipeline dependency on `messages.txt`, which will read specifically from a file by that name from the Game Project. | ||
|
||
This dependency tells the Content Pipeline that if messages.txt changes, the font must be rebuilt. | ||
|
||
```csharp | ||
string fullPath = Path.GetFullPath(MessageFile); | ||
|
||
context.AddDependency(fullPath); | ||
``` | ||
|
||
1. Next, we add functionality to read the contents of the file and add each letter to the input font one by one. Note that the [Characters](xref:Microsoft.Xna.Framework.Content.Pipeline.Graphics.FontDescription) collection keeps track of duplicates automatically, it is not necessary for the user to make sure that each letter is added only once. The **Characters** collection will contain only one instance of each character, no matter how many times **Add** has been called. | ||
|
||
```csharp | ||
string letters = File.ReadAllText(fullPath, System.Text.Encoding.UTF8); | ||
|
||
foreach (char c in letters) | ||
{ | ||
input.Characters.Add(c); | ||
} | ||
``` | ||
|
||
> [!NOTE] | ||
> In this example, messages.txt has been saved with Unicode UTF-8 encoding, which is the default encoding format that is specified in the call to [File.ReadAllText](http://msdn.microsoft.com/en-us/library/ms143369.aspx). However, the default file encoding format for text files that have been added to a Visual Studio project is `Western European (Windows) encoding`, corresponding to code page `1252`. If your text file uses a different encoding, specify the character encoding as follows: | ||
```csharp | ||
string letters = File.ReadAllText( fullPath, System.Text.Encoding.GetEncoding( 1252 ) ); | ||
``` | ||
|
||
1. Finally, call the `Base` **Process** method of the [FontDescriptionProcessor](xref:Microsoft.Xna.Framework.Content.Pipeline.Processors.FontDescriptionProcessor) to build the font with the newly requested characters. | ||
|
||
```csharp | ||
return base.Process(input, context); | ||
``` | ||
|
||
Done. If your txt file is located elsewhere, make sure to update the path to the file appropriately, FROM the content project folder in the Processor project. | ||
|
||
Final code: | ||
|
||
```csharp | ||
using Microsoft.Xna.Framework.Content.Pipeline; | ||
using Microsoft.Xna.Framework.Content.Pipeline.Graphics; | ||
using Microsoft.Xna.Framework.Content.Pipeline.Processors; | ||
using System.ComponentModel; | ||
using System.IO; | ||
|
||
namespace FontProcessor | ||
{ | ||
[ContentProcessor(DisplayName = "MyFontProcessor")] | ||
internal class MyFontProcessor : FontDescriptionProcessor | ||
{ | ||
public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) | ||
{ | ||
string fullPath = Path.GetFullPath(MessageFile); | ||
|
||
context.AddDependency(fullPath); | ||
string letters = File.ReadAllText(fullPath, System.Text.Encoding.UTF8); | ||
|
||
foreach (char c in letters) | ||
{ | ||
input.Characters.Add(c); | ||
} | ||
return base.Process(input, context); | ||
} | ||
|
||
[DefaultValue("messages.txt")] | ||
[DisplayName("Message File")] | ||
[Description("The characters in this file will be automatically added to the font.")] | ||
public string MessageFile | ||
{ | ||
get { return messageFile; } | ||
set { messageFile = value; } | ||
} | ||
private string messageFile = @"../messages.txt"; | ||
} | ||
} | ||
``` | ||
|
||
### Associate the custom font processor with the sprite font in the MGCB tool | ||
|
||
1. Compile the solution to build **MyFontProcessor**, as you need to add your custom font processor as an available content processor for the content pipeline. | ||
|
||
1. Open the MGCB tool for your `Content` project, click (select) the **Content** node, navigate down to the properties section and then click in the **References** property. | ||
|
||
[MGCB Editor window properties](./images/mgcb_editor_content_properties_referencesSelected.png) | ||
|
||
1. Navigate to the `dll` for the built `MyFontProcessor` project (which by default is in `\FontGame\MyFontProcessor\bin\debug\net6.0`), select it and click "open". | ||
|
||
> [IMPORTANT] | ||
> Ensure that the processor project is always up to date when the main game is built, you need to create a project dependency. Also use either "debug" or "Release" build types for the processor project, the MGCB tool will NOT dynamically select it when you change the Projects build type. | ||
|
||
1. Build the Content Project to ensure everything is connected as it should be. | ||
|
||
1. Select the `.spritefont` file, and then in the **Properties** window change the `processor` to`MyFontProcessor` in the drop-down list associated with the **ContentProcessor** field. | ||
|
||
When you build the solution, the new processor adds the characters in the messages.txt file to the list of characters available to the [SpriteFont](xref:Microsoft.Xna.Framework.Graphics.SpriteFont). | ||
|
||
> [!NOTE] | ||
> To debug a Content Pipeline importer or processor, add the following line to the processor code to launch the debugger. | ||
> | ||
> ```csharp | ||
> System.Diagnostics.Debugger.Launch(); | ||
> ``` | ||
|
||
## See Also | ||
|
||
[Extending a Standard Content Processor](./HowTo_Extend_Processor.md) | ||
[Adding New Content Types](../../whatis/Content_Pipeline/CP_Content_Advanced.md) |
Oops, something went wrong.