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 --self-contained
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 and PublishTrimmed
The PublishAot
option optimises your game code "Ahead of Time" for performance. It allows you to ship your game without the need to JIT (Just In Time compile), and will basically natively compile your game.
PublishAot
binaries are much faster, which is typically desired for games. It however comes with limitations, like the inability to use runtime reflection and runtime code generation (IL emition).
PublishAot
makes use of PublishTrimmed
, which is another option that strip binaries of unused code to make much lighter executables and assemblies. Trimming can be aggressive and might remove types if the compiler can't detect if they are used (e.g. if you are using reflection or generics).
MonoGame is mostly compatible with PublishAot
and PublishTrimmed
, and will just work in most cases. It may however crash at runtime if you are using custom content importers that use generic collections. If you are using PublishAot
and you are running into runtime exceptions occuring when loading content saying that a type is missing, the solution is to call ContentTypeReaderManager.AddTypeCreator()
on that type before trying to load your content. This will tell the AOT compiler to include that type.
Besides MonoGame itself, it may happen that the third party libraries that you are using are not compatible with AOT or trimming. In that case, you should refer to those libraries maintainers for workarounds, or replace them with compatible libraries.
Overall, AOT and trimming have similar limitations you need to watchout for:
- 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 theDeserialize
method, you write your own custom deserializer usingXDocument
orXmlReader
. Alternatively you can use the Content Pipeline and create a customProcessor
andReader
to convert the Xml into a binary format that can be loaded via the usualContent.Load<T>
method. - Dynamically loading assemblies via
Assembly.LoadFile
. - No run-time code generation, for example, System.Reflection.Emit.
You can also refer to the Preparing for consoles documentation, which leverage AOT and has the same limitations. If your game runs with PublishAot
, you'll be well ahead into porting your game to consoles.
For more information, please see Native AOT deployment and Trim self-contained deployments.
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.
If you need to reduce the footprint of your game, please refer to PublishAot
and PublishTrimmed
instead.
Mobile games
Please refer to the Xamarin documentation: