Table of Contents

Package games for distribution

How to package your game for distribution.

Desktop games

To publish desktop games, it is recommended that you build your project as a self-contained .NET application. As such, your game will require absolutely no external dependencies and should run out-of-the-box as-is.

Building and packaging

From the .NET CLI:

dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=false -p:TieredCompilation=false -p:PublishAot=true --self-contained

Important

We are making use of the PublishAot option. Using Aot has some restrictions which may require changes to your game code. Especially if you are using Reflection.

You can then zip the content of the publish folder and distribute the archive as-is.

If you are targeting WindowsDX, note that players will need the DirectX June 2010 runtime to be installed on their machine for audio and gamepads to work properly.

Special notes about .NET parameters

.NET proposes several parameters when publishing apps that may sound helpful, but have many issues when it comes to games (because they were never meant for games in the first place, but for small lightweight applications).

PublishAot

This option optimises your game code "Ahead of Time". It allows you to ship your game without the need to JIT (Just In Time compile). However, you do need to currently add some additional settings to your .csproj.

  <ItemGroup>
    <TrimmerRootAssembly Include="MonoGame.Framework" />
    <TrimmerRootAssembly Include="mscorlib" />
  </ItemGroup>

The TrimmerRootAssembly stops the trimmer removing code from these assemblies. This should allow the game to run without any issues. However if you are using any Third Party or additional assemblies, you might need to add them to this list or fix your code to be Aot compliant. It is recommended that you publish using AOT as it simplifies the app bundle.

You may see some trim and AOT analysis warnings related to MonoGame when using PublishAOT, even after adding TrimmerRootAssembly - these are normal and should not present any issue.

See Trim self-contained deployments and executables for more information.

There are some known areas you need to watchout for:

  1. Using XmlSerializer in your game will probably cause issues. Since it uses reflection it will be difficult for the Trimmer to figure out what needs to be kept. It is recommended that, instead of using the Deserialize method, you write your own custom deserializer using XDocument or XmlReader. Alternatively you can use the Content Pipeline and create a custom Processor and Reader to convert the Xml into a binary format that can be loaded via the usual Content.Load<T> method.
  2. Dynamically loading assemblies via Assembly.LoadFile.
  3. No run-time code generation, for example, System.Reflection.Emit.

ReadyToRun (R2R)

ReadyToRun is advertised as improving application startup time, but slightly increasing binary size. We recommend not using it for games because it produces micro stutters when your game is running.

ReadyToRun code is of low quality and makes the Just-In-Time compiler (JIT) trigger regularly to promote the code to a higher quality. Whenever the JIT runs, it produces potentially very visible stutters.

Disabling ReadyToRun solves this issue (at the cost of a slightly longer startup time, but typically very negligible).

ReadyToRun is disabled by default. You can configure it by setting the PublishReadyToRun property in your .csproj file.

MonoGame templates for .NET projects explicitly set this to false.

Tiered compilation

Tiered compilation is a companion system to ReadyToRun and works on the same principle to enhance startup time. We suggest disabling it to avoid any stutter while your game is running.

Tiered compilation is enabled by default. To disable it, set the TieredCompilation property to false in your .csproj. MonoGame templates for .NET projects explicitly set this to false.

PublishSingleFile

PublishSingleFile packages your game into a single executable file with all dependencies and content integrated.

While it sounds very convenient, be aware that it's not magical and is in fact a hidden self-extracting zip archive. As such, it may make app startup take a lot longer if your game is large, and may fail to launch on systems where user permissions don't allow extracting files (or if there is not enough storage space available).

We highly recommend not using it for better compatibility across systems.

Mobile games

Please refer to the Xamarin documentation: