Skip to content

Commit 031b75a

Browse files
Merge branch 'main' into patch-1
2 parents 3ec4711 + 56e6932 commit 031b75a

File tree

2 files changed

+231
-30
lines changed

2 files changed

+231
-30
lines changed

articles/getting_started/packaging_games.md

Lines changed: 93 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,17 @@ To publish desktop games, it is recommended that you build your project as a [se
1313

1414
From the .NET CLI:
1515

16-
`dotnet publish -c Release -r win-x64 /p:PublishReadyToRun=false /p:TieredCompilation=false --self-contained`
16+
`dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=false -p:TieredCompilation=false -p:PublishAot=true --self-contained`
17+
18+
> [!IMPORTANT]
19+
> 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.
1720
1821
You can then zip the content of the publish folder and distribute the archive as-is.
1922

2023
If you are targeting WindowsDX, note that players will need [the DirectX June 2010 runtime](https://www.microsoft.com/en-us/download/details.aspx?id=8109) to be installed on their machine for audio and gamepads to work properly.
2124

2225
### [macOS](#tab/macos)
2326

24-
From the .NET CLI:
25-
26-
```cli
27-
dotnet publish -c Release -r osx-x64 /p:PublishReadyToRun=false /p:TieredCompilation=false --self-contained
28-
dotnet publish -c Release -r osx-arm64 /p:PublishReadyToRun=false /p:TieredCompilation=false --self-contained
29-
```
30-
3127
We recommend that you distribute your game as an [application bundle](https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html). Application bundles are directories with the following file structure:
3228

3329
```text
@@ -37,23 +33,41 @@ YourGame.app                    (this is your root folder)
3733
            - Content           (this is where all your content and XNB's should go)
3834
            - YourGame.icns     (this is your app icon, in ICNS format)
3935
        - MacOS
40-
- amd64 (this is where your game executable for amd64 belongs, place files from the osx-x64/publish directory here)
41-
- arm64 (this is where your game executable for arm64 belongs, place files from the osx-arm64/publish directory here)
42-
- YourGame (the entry point script of your app, see bellow for contents)
43-
     - Info.plist            (the metadata of your app, see bellow for contents)
36+
- YourGame (the main executable for your game)
37+
     - Info.plist            (the metadata of your app, see below for contents)
38+
```
39+
40+
So first lets create our directory structure.
41+
42+
```cli
43+
mkdir -p bin/Release/YourGame.app/Contents/MacOS/
44+
mkdir -p bin/Release/YourGame.app/Contents/Resources/Content
45+
```
46+
47+
Next we need to publish our application for both `arm64` (Apple Silicon) and `x64` (Intel). From the .NET CLI:
48+
49+
```cli
50+
dotnet publish -c Release -r osx-x64 -p:PublishReadyToRun=false -p:TieredCompilation=false -p:PublishAot=true --self-contained
51+
dotnet publish -c Release -r osx-arm64 -p:PublishReadyToRun=false -p:TieredCompilation=false -p:PublishAot=true --self-contained
52+
```
53+
54+
> [!IMPORTANT]
55+
> 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.
56+
57+
Next we need to combine the two binaries into one Universal Binary which will work on both arm64 and x64 machines.
58+
We can do this using the `xcode` utility `lipo`.
59+
60+
```cli
61+
lipo -create bin/Release/net8.0/osx-arm64/publish/YourGame bin/Release/net8.0/osx-x64/publish/YourGame -output bin/Release/YourGame.app/Contents/MacOS/YourGame
4462
```
4563

46-
The contents of the entry point script:
64+
The above command will combine the two output executables into one. It assumes you are using the standard `Output` path for your application.
65+
If you are using a custom `Output` folder, you will need to make adjustments to the above command.
4766

48-
```sh
49-
#!/bin/bash
67+
Copy over your content
5068

51-
cd "$(dirname $BASH_SOURCE)/../Resources"
52-
if [[ $(uname -p) == 'arm' ]]; then
53-
./../MacOS/arm64/YourGame
54-
else
55-
./../MacOS/amd64/YourGame
56-
fi
69+
```cli
70+
cp -R bin/Release/net8.0/Content bin/Release/YourGame.app/Contents/Resources/Content
5771
```
5872

5973
The `Info.plist` file is a standard macOS file containing metadata about your game. Here is an example file with required and recommended values set:
@@ -101,45 +115,94 @@ The `Info.plist` file is a standard macOS file containing metadata about your ga
101115
</plist>
102116
```
103117

104-
For more information about Info.plist files, see the [documentation](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html).
118+
> [!NOTE]
119+
> For more information about `Info.plist` files, see the Apple [documentation](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html).
105120
106-
After completing these steps, your .app folder should appear as an executable application on macOS.
121+
After completing these steps, your `.app` folder should appear as an executable application on macOS.
122+
However it does need an icon. So we need to create an `.icns` file. We can use online tools to do this or you can use the following:
107123

108-
For archiving, we recommend using the .tar.gz format to preserve the execution permissions (you will likely run into permission issues if you use .zip at any point).
124+
```cli
125+
mkdir -p bin/Release/YourGame.iconset
126+
sips -z 16 16 Icon.png --out bin/Release/YourGame.iconset/icon_16x16.png
127+
sips -z 32 32 Icon.png --out bin/Release/YourGame.iconset/[email protected]
128+
sips -z 32 32 Icon.png --out bin/Release/YourGame.iconset/icon_32x32.png
129+
sips -z 64 64 Icon.png --out bin/Release/YourGame.iconset/[email protected]
130+
sips -z 128 128 Icon.png --out bin/Release/YourGame.iconset/icon_128x128.png
131+
sips -z 256 256 Icon.png --out bin/Release/YourGame.iconset/[email protected]
132+
sips -z 256 256 Icon.png --out bin/Release/YourGame.iconset/icon_256x256.png
133+
sips -z 512 512 Icon.png --out bin/Release/YourGame.iconset/[email protected]
134+
sips -z 512 512 Icon.png --out bin/Release/YourGame.iconset/icon_512x512.png
135+
sips -z 1024 1024 Icon.png bin/Release/YourGame.iconset/[email protected]
136+
iconutil -c icns bin/Release/YourGame.iconset --output bin/Release/YourGame.app/Contents/Resources/YourGame.icns
137+
```
138+
139+
> [!NOTE]
140+
> This code is expecting an `Icon.png` file to be in the same directory. This file should be `1024` x `1024` pixels.
141+
142+
For archiving, we recommend using the `.tar.gz` format to preserve the execution permissions (you will likely run into permission issues if you use `.zip` at any point).
109143

110144
### [Ubuntu](#tab/ubuntu)
111145

112146
From the .NET CLI:
113147

114-
`dotnet publish -c Release -r linux-x64 /p:PublishReadyToRun=false /p:TieredCompilation=false --self-contained`
148+
`dotnet publish -c Release -r linux-x64 -p:PublishReadyToRun=false -p:TieredCompilation=false -p:PublishAot=true --self-contained`
149+
150+
> [!IMPORTANT]
151+
> 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.
115152
116153
You can then archive the content of the publish folder and distribute the archive as-is.
117154

118-
We recommend using the .tar.gz archiving format to preserve the execution permissions.
155+
We recommend using the `.tar.gz` archiving format to preserve the execution permissions.
119156

120157
---
121158

122159
## Special notes about .NET parameters
123160

124161
.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).
125162

163+
### PublishAot
164+
165+
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).
166+
However, you do need to currently add some additional settings to your `.csproj`.
167+
168+
```xml
169+
<ItemGroup>
170+
<TrimmerRootAssembly Include="MonoGame.Framework" />
171+
<TrimmerRootAssembly Include="mscorlib" />
172+
</ItemGroup>
173+
```
174+
175+
The `TrimmerRootAssembly` stops the trimmer removing code from these assemblies. This should allow the game to run without
176+
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.
177+
It is recommended that you publish using AOT as it simplifies the app bundle.
178+
179+
See [Trim self-contained deployments and executables](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained) for more information.
180+
181+
There are some known areas you need to watchout for:
182+
183+
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.
184+
It is recommended that, instead of using the `Deserialize` method, you write your own custom deserializer using `XDocument` or `XmlReader`.
185+
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.
186+
2. Dynamically loading assemblies via `Assembly.LoadFile`.
187+
3. No run-time code generation, for example, System.Reflection.Emit.
188+
126189
### ReadyToRun (R2R)
127190

128-
[ReadyToRun](https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#readytorun-images) 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.
191+
[ReadyToRun](https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#readytorun-images) 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.
129192

130-
Ready2Run code is of low quality and makes the Just-In-Time compiler (JIT) to trigger regularly to promote the code to a higher quality. Whenever the JIT runs, it produces potentially very visible stutters.
193+
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.
131194

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

134-
ReadyToRun is disabled by default. You can configure it by setting the `PublishReadyToRun` property in your csproj file.
197+
ReadyToRun is disabled by default. You can configure it by setting the `PublishReadyToRun` property in your `.csproj` file.
135198

136199
MonoGame templates for .NET projects explicitly set this to `false`.
137200

138201
### Tiered compilation
139202

140203
[Tiered compilation](https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#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.
141204

142-
Tiered compilation is **enabled by default**. To disable it set the `TieredCompilation` property to `false` in your csproj.
205+
Tiered compilation is **enabled by default**. To disable it, set the `TieredCompilation` property to `false` in your `.csproj`.
143206
MonoGame templates for .NET projects explicitly set this to `false`.
144207

145208
### SingleFilePublish
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
---
2+
title: Using the Development Nuget Packages
3+
description: How to use the latest development NuGet packages to use the cutting edge of MonoGame development in your project.
4+
---
5+
6+
## Overview
7+
8+
When the MonoGame develop branch builds, it publishes development NuGet packages to the MonoGame NuGet Feed on GitHub. If you want to test a new feature or just be on the very latest code you can use this Feed to do that.
9+
10+
## Adding a NuGet Source
11+
12+
1. Create a `NuGet.config` in the root or top level directory of your project.
13+
14+
> [!NOTE]
15+
> NuGet will automatically walk up the directory tree to find `NuGet.config` files.
16+
17+
1. Add the following content:
18+
19+
```xml
20+
<?xml version="1.0" encoding="utf-8"?>
21+
<configuration>
22+
<packageSources>
23+
<add key="MonoGameGitHub" value="https://nuget.pkg.github.com/MonoGame/index.json" />
24+
</packageSources>
25+
</configuration>
26+
```
27+
28+
1. Next (in the root or top level directory), create a `Directory.Build.props` file and add the following content.
29+
30+
```xml
31+
<Project>
32+
<PropertyGroup>
33+
<MonoGamePackageVersion>1.0.0.1233-develop</MonoGamePackageVersion>
34+
</PropertyGroup>
35+
</Project>
36+
```
37+
38+
`Directory.Build.props` is an MSBuild file which will be imported by all projects in your game. It is like a file that contains global variables. In this case the version of MonoGame we want to use.
39+
40+
> [!NOTE]
41+
> To find out the latest version number, you can look at one of the packages at [https://github.com/orgs/MonoGame/packages?repo_name=MonoGame](https://github.com/orgs/MonoGame/packages?repo_name=MonoGame). Or to get the information from the GitHub feed, you can run the following command.
42+
>
43+
> ```CLI
44+
> nuget search "MonoGame.Framework" -PreRelease -Source MonoGameGitHub
45+
> ```
46+
47+
This will give you the following output
48+
49+
```text
50+
====================
51+
Source: MonoGameGitHub
52+
--------------------
53+
> MonoGame.Framework.Android | 1.0.0.1278-develop | Downloads: 164
54+
The MonoGame runtime for Android.
55+
--------------------
56+
> MonoGame.Framework.Content.Pipeline | 1.0.0.1278-develop | Downloads: 69
57+
The Monogame Content Pipeline for Windows, Mac and Linux is used to compile raw content to xnb files...
58+
--------------------
59+
> MonoGame.Framework.DesktopGL | 1.0.0.1278-develop | Downloads: 337
60+
The MonoGame runtime supporting Windows, Linux and macOS using SDL2 and OpenGL.
61+
--------------------
62+
> MonoGame.Framework.Native | 1.0.0.1278-develop | Downloads: 1
63+
The MonoGame Native platform.
64+
--------------------
65+
> MonoGame.Framework.WindowsDX | 1.0.0.1278-develop | Downloads: 76
66+
The MonoGame runtime for Windows using DirectX API's.
67+
--------------------
68+
> MonoGame.Framework.WindowsUniversal | 3.8.1.1128-develop | Downloads: 54
69+
The MonoGame runtime for UWP (Universal Windows Platform) which supports Windows 10 and Xbox One.
70+
--------------------
71+
> MonoGame.Framework.iOS | 1.0.0.1278-develop | Downloads: 153
72+
The MonoGame runtime for iOS amd iPadOS.
73+
--------------------
74+
```
75+
76+
The version number you want to use is listed in the output.
77+
78+
> [!NOTE]
79+
> As packages are published, the version number will always change. Unfortunately, due to limitations in the way NuGet works, we cannot
80+
> use a wildcard with a pre-release package (so you cannot do `1.0.0.*-develop`). So this is the best way to find the latest version you want to use.
81+
82+
1. Next update all the `PackageReference` entries in your `csproj`'s which use MonoGame to use `$(MonoGamePackageVersion)` MSBuild property.
83+
For example:
84+
85+
```xml
86+
<ItemGroup>
87+
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="$(MonoGamePackageVersion)" />
88+
<PackageReference Include="MonoGame.Content.Builder.Task" Version="$(MonoGamePackageVersion)" />
89+
</ItemGroup>
90+
```
91+
92+
If you try to build now you will get an error. This is because the NuGet feeds on GitHub are not public. You need to be a valid GitHub user to use them.
93+
94+
## Authentication
95+
96+
You need to create a **Personal Access Token** (PAT) on your GitHub account in order to use the NuGet feed. See the following documentation on how to create your PAT.
97+
98+
[managing-your-personal-access-tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
99+
100+
> [!NOTE]
101+
> You need to create a "PAT (Classic)" token in order for it to work with the Nuget feed. See [creating-a-personal-access-token-classic](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) for details.
102+
103+
Once you have your **PAT**, you can create a new `NuGet.config` file in the directory ABOVE your game project directory.
104+
To be clear, this file should NOT be in your source tree. It should be outside of any directory which is under source control.
105+
106+
```cli
107+
Projects
108+
NuGet.config <-- THIS IS WHERE YOU PUT THE FILE.
109+
MyGame
110+
.git
111+
Directory.Build.props
112+
NuGet.config
113+
MyGame.DesktopGL
114+
MyGame.DesktopGL.csproj
115+
116+
```
117+
118+
> [!IMPORTANT]
119+
> Do Not... **DO NOT** place a `NuGet.config` file with valid `packageSourceCredentials` in your source control.
120+
121+
The contents of the file are as follows, replace `%GITHUB_USER%` with your GitHub username and the `%GITHUB_TOKEN%` with your token.
122+
123+
```xml
124+
<?xml version="1.0" encoding="utf-8"?>
125+
<configuration>
126+
<packageSourceCredentials>
127+
<MonoGameGitHub>
128+
<add key="Username" value="%GITHUB_USER%" />
129+
<add key="ClearTextPassword" value="%GITHUB_TOKEN%" />
130+
</MonoGameGitHub>
131+
</packageSourceCredentials>
132+
</configuration>
133+
```
134+
135+
The really good thing about placing these credentials outside of source control is that they are safe. But also any new projects you create under that folder can also make use of these credentials. So it is a good idea to keep them in one place.
136+
137+
> [!NOTE]
138+
> For more information, you can read [consuming-packages-authenticated-feeds](https://learn.microsoft.com/en-us/nuget/consume-packages/consuming-packages-authenticated-feeds#credentials-in-nugetconfig-files).

0 commit comments

Comments
 (0)