diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7cad46cc1f..ec23d46e82 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -6,6 +6,29 @@ on:
branches: [ bleed ]
jobs:
+ linux:
+ name: Linux (.NET 5.0)
+ runs-on: ubuntu-20.04
+
+ steps:
+ - name: Clone Repository
+ uses: actions/checkout@v2
+
+ - name: Install .NET 5
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: '5.0.x'
+
+ - name: Check Code
+ run: |
+ make check
+
+ - name: Check Mods
+ run: |
+ sudo apt-get install lua5.1
+ make check-scripts
+ make test
+
linux-mono:
name: Linux (mono)
runs-on: ubuntu-20.04
@@ -17,16 +40,15 @@ jobs:
- name: Check Code
run: |
mono --version
- make check
+ make RUNTIME=mono check
- name: Check Mods
run: |
- sudo apt-get install lua5.1
- make check-scripts
- make test
+ # check-scripts does not depend on .net/mono, so is not needed here
+ make RUNTIME=mono test
windows:
- name: Windows (Net 5.0)
+ name: Windows (.NET 5.0)
runs-on: windows-2019
steps:
diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml
index 85d24135a5..b1f9637c3f 100644
--- a/.github/workflows/packaging.yml
+++ b/.github/workflows/packaging.yml
@@ -15,6 +15,11 @@ jobs:
- name: Clone Repository
uses: actions/checkout@v2
+ - name: Install .NET 5
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: '5.0.x'
+
- name: Prepare Environment
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 45108d05e8..db96daaf40 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -3,57 +3,45 @@
"configurations": [
{
"name": "Launch (TD)",
- "type": "clr",
- "linux": {
- "type": "mono"
- },
- "osx": {
- "type": "mono"
- },
+ "type": "coreclr",
"request": "launch",
- "program": "${workspaceRoot}/bin/OpenRA.exe",
+ "program": "${workspaceRoot}/bin/OpenRA.dll",
+ "windows": {
+ "program": "${workspaceRoot}/bin/OpenRA.exe",
+ },
"args": ["Game.Mod=cnc", "Engine.EngineDir=.."],
"preLaunchTask": "build",
},
{
"name": "Launch (RA)",
- "type": "clr",
- "linux": {
- "type": "mono"
- },
- "osx": {
- "type": "mono"
- },
+ "type": "coreclr",
"request": "launch",
- "program": "${workspaceRoot}/bin/OpenRA.exe",
+ "program": "${workspaceRoot}/bin/OpenRA.dll",
+ "windows": {
+ "program": "${workspaceRoot}/bin/OpenRA.exe",
+ },
"args": ["Game.Mod=ra", "Engine.EngineDir=.."],
"preLaunchTask": "build",
},
{
"name": "Launch (D2k)",
- "type": "clr",
- "linux": {
- "type": "mono"
- },
- "osx": {
- "type": "mono"
- },
+ "type": "coreclr",
"request": "launch",
- "program": "${workspaceRoot}/bin/OpenRA.exe",
+ "program": "${workspaceRoot}/bin/OpenRA.dll",
+ "windows": {
+ "program": "${workspaceRoot}/bin/OpenRA.exe",
+ },
"args": ["Game.Mod=d2k", "Engine.EngineDir=.."],
"preLaunchTask": "build",
},
{
"name": "Launch (TS)",
- "type": "clr",
- "linux": {
- "type": "mono"
- },
- "osx": {
- "type": "mono"
- },
+ "type": "coreclr",
"request": "launch",
- "program": "${workspaceRoot}/bin/OpenRA.exe",
+ "program": "${workspaceRoot}/bin/OpenRA.dll",
+ "windows": {
+ "program": "${workspaceRoot}/bin/OpenRA.exe",
+ },
"args": ["Game.Mod=ts", "Engine.EngineDir=.."],
"preLaunchTask": "build",
},
diff --git a/INSTALL.md b/INSTALL.md
index 2600ffd0a0..cf234e5b29 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -17,93 +17,67 @@ Run the game with `launch-game.cmd`. It can be handed arguments that specify the
Linux
=====
-Mono, version 6.4 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient.
+.NET 5 or Mono (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 5 when possible, as Mono is poorly packaged by most Linux distributions (e.g. missing the required `msbuild` toolchain), and has been deprecated as a standalone project.
-To compile OpenRA, run `make` from the command line. After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod.
+The [.NET 5 download page](https://dotnet.microsoft.com/download/dotnet/5.0) provides repositories for various package managers and binary releases for several architectures. If you prefer to use Mono, we suggest adding the [upstream repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version and the `msbuild` toolchain.
+
+To compile OpenRA, run `make` from the command line (or `make RUNTIME=mono` if using Mono). After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod.
The default behaviour on the x86_64 architecture is to download several pre-compiled native libraries using the Nuget packaging manager. If you prefer to use system libraries, compile instead using `make TARGETPLATFORM=unix-generic`.
-If you choose to use system libraries, or your system is not x86_64, you will need to install the following using your system package manager:
-* [SDL 2](http://www.libsdl.org/download-2.0.php)
-* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm)
-* [OpenAL](http://kcat.strangesoft.net/openal.html)
-* [liblua 5.1](http://luabinaries.sourceforge.net/download.html)
+If you choose to use system libraries, or your system is not x86_64, you will need to install [SDL 2](https://www.libsdl.org/download-2.0.php), [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm), [OpenAL](https://openal-soft.org/), and [liblua 5.1](http://luabinaries.sourceforge.net/download.html) before compiling OpenRA.
-Type `sudo make install` for system-wide installation. Run `sudo make install-linux-shortcuts` to get startup scripts, icons and desktop files. You can then run the Red Alert by executing the `openra-ra` command, the Dune 2000 mod by running the `openra-d2k` command and Tiberian Dawn by the `openra-cnc` command. Alternatively, you can also run these mods by clicking on their desktop shortcuts if you ran `sudo make install-linux-shortcuts`.
+These can be installed using your package manager on various distros:
-Arch Linux
-----------
-
-It is important to note there is an unofficial [`openra-git`](https://aur.archlinux.org/packages/openra-git) package in the Arch User Repository (AUR) of Arch Linux. If manually compiling is the way you wish to go the build and runtime dependencies can be installed with:
+Arch Linux
```
-sudo pacman -S mono openal libgl freetype2 sdl2 lua51 xdg-utils zenity
+sudo pacman -S openal libgl freetype2 sdl2 lua51
```
-
-Debian/Ubuntu
--------------
-
-:warning: The `mono` packages in the Ubuntu < 19.04 and Debian < 10 repositories are too old to support OpenRA. :warning:
-
-See the instructions under the *Linux* section above to upgrade `mono` using the upstream releases if needed.
+
+Debian/Ubuntu
```
-sudo apt install mono-devel libfreetype6 libopenal1 liblua5.1-0 libsdl2-2.0-0 xdg-utils zenity wget
+sudo apt install libfreetype6 libopenal1 liblua5.1-0 libsdl2-2.0-0
```
-
-Fedora
-------
-
-:warning: The `mono` packages in the Fedora repositories are too old to support OpenRA. :warning:
-
-See the instructions under the *Linux* section above to upgrade `mono` using the upstream releases.
-
+
+Fedora
```
-sudo dnf install "pkgconfig(mono)" SDL2 freetype "lua = 5.1" openal-soft xdg-utils zenity
+sudo dnf install SDL2 freetype "lua = 5.1" openal-soft
```
-
-Gentoo
-------
+
+Gentoo
```
-sudo emerge -av dev-lang/mono dev-dotnet/libgdiplus media-libs/freetype:2 media-libs/libsdl2 media-libs/openal virtual/jpeg virtual/opengl '=dev-lang/lua-5.1.5*' x11-misc/xdg-utils gnome-extra/zenity
+sudo emerge -av media-libs/freetype:2 media-libs/libsdl2 media-libs/openal virtual/opengl '=dev-lang/lua-5.1.5*'
```
-
-Mageia
-------
+
+Mageia
```
-sudo dnf install "pkgconfig(mono)" SDL2 freetype "lib*lua5.1" "lib*freetype2" "lib*sdl2.0_0" openal-soft xdg-utils zenity
+sudo dnf install SDL2 freetype "lib*lua5.1" "lib*freetype2" "lib*sdl2.0_0" openal-soft
```
-
-openSUSE
---------
+
+openSUSE
```
-sudo zypper in mono-devel openal-soft freetype2 SDL2 lua51 xdg-utils zenity
+sudo zypper in openal-soft freetype2 SDL2 lua51
```
-
-Red Hat Enterprise Linux (and rebuilds, e.g. CentOS)
-----------------------------------------------------
-
+
+Red Hat Enterprise Linux (and rebuilds, e.g. CentOS)
The EPEL repository is required in order for the following command to run properly.
```
-sudo yum install "pkgconfig(mono)" SDL2 freetype "lua = 5.1" openal-soft xdg-utils zenity
+sudo yum install SDL2 freetype "lua = 5.1" openal-soft
```
+
+
+Type `sudo make install` for system-wide installation. Run `sudo make install-linux-shortcuts` to get startup scripts, icons and desktop files. You can then run the Red Alert by executing the `openra-ra` command, the Dune 2000 mod by running the `openra-d2k` command and Tiberian Dawn by the `openra-cnc` command. Alternatively, you can also run these mods by clicking on their desktop shortcuts if you ran `sudo make install-linux-shortcuts`.
macOS
=====
-Before compiling OpenRA you must install the following dependencies:
-* [Mono >= 6.4](https://www.mono-project.com/download/stable/#download-mac)
-
-To compile OpenRA, run `make` from the command line. Run with `./launch-game.sh`.
-
-The default behaviour is to download several pre-compiled native libraries using the Nuget packaging manager. If you prefer to use system libraries, compile instead using `make TARGETPLATFORM=unix-generic`. If you choose to use system libraries you will need to install:
-* [SDL 2](http://www.libsdl.org/download-2.0.php) (`brew install sdl2`)
-* [FreeType](http://gnuwin32.sourceforge.net/packages/freetype.htm) (`brew install freetype`)
-* [OpenAL](http://kcat.strangesoft.net/openal.html) (`brew install openal-soft`)
-* [liblua 5.1](http://luabinaries.sourceforge.net/download.html) (`brew install lua@5.1`)
+[.NET 5](https://dotnet.microsoft.com/download/dotnet/5.0) or [Mono](https://www.mono-project.com/download/stable/#download-mac) (version 6.4 or later) is required to compile OpenRA. We recommend using .NET 5 unless you are running a very old version of macOS (10.9 through 10.12).
+To compile OpenRA, run `make` from the command line (or `make RUNTIME=mono` if using Mono). Run with `./launch-game.sh`.
diff --git a/Makefile b/Makefile
index b6a77509e6..ea23ccd499 100644
--- a/Makefile
+++ b/Makefile
@@ -1,19 +1,22 @@
############################# INSTRUCTIONS #############################
#
# to compile, run:
-# make [DEBUG=true]
+# make
+#
+# to compile using Mono (version 6.4 or greater) instead of .NET 5, run:
+# make RUNTIME=mono
#
# to compile using system libraries for native dependencies, run:
-# make [DEBUG=true] TARGETPLATFORM=unix-generic
+# make [RUNTIME=dotnet] TARGETPLATFORM=unix-generic
#
# to check the official mods for erroneous yaml files, run:
-# make test
+# make [RUNTIME=dotnet] test
#
# to check the engine and official mod dlls for code style violations, run:
-# make check
+# make [RUNTIME=dotnet] check
#
# to compile and install Red Alert, Tiberian Dawn, and Dune 2000, run:
-# make [prefix=/foo] [bindir=/bar/bin] install
+# make [RUNTIME=dotnet] [prefix=/foo] [bindir=/bar/bin] install
#
# to compile and install Red Alert, Tiberian Dawn, and Dune 2000
# using system libraries for native dependencies, run:
@@ -43,12 +46,14 @@ gameinstalldir ?= $(libdir)/openra
# Toolchain
CWD = $(shell pwd)
MSBUILD = msbuild -verbosity:m -nologo
+DOTNET = dotnet
MONO = mono
RM = rm
RM_R = $(RM) -r
RM_F = $(RM) -f
RM_RF = $(RM) -rf
+RUNTIME ?= dotnet
VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || echo git-`git rev-parse --short HEAD`)
# Detect target platform for dependencies if not given by the user
@@ -66,33 +71,43 @@ endif
endif
endif
-OPENRA_UTILITY = ENGINE_DIR=".." $(MONO) --debug bin/OpenRA.Utility.dll
-
##################### DEVELOPMENT BUILDS AND TESTS #####################
#
all:
- @command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.18."; exit 1)
+ifeq ($(RUNTIME), mono)
+ @command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 6.4."; exit 1)
@$(MSBUILD) -t:Build -restore -p:Configuration=Release -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true
+else
+ @$(DOTNET) build -c Release -nologo -p:TargetPlatform=$(TARGETPLATFORM)
+endif
ifeq ($(TARGETPLATFORM), unix-generic)
@./configure-system-libraries.sh
endif
@./fetch-geoip.sh
+# dotnet clean and msbuild -t:Clean leave files that cause problems when switching between mono/dotnet
+# Deleting the intermediate / output directories ensures the build directory is actually clean
clean:
- @-$(RM_RF) ./bin ./*/bin ./*/obj
- @$(MSBUILD) -t:Clean -p:Mono=true
+ @-$(RM_RF) ./bin ./*/obj
@-$(RM_F) IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP
check:
@echo
@echo "Compiling in debug mode..."
+ifeq ($(RUNTIME), mono)
@$(MSBUILD) -t:build -restore -p:Configuration=Debug -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true
+else
+ @$(DOTNET) build -c Debug -nologo -p:TargetPlatform=$(TARGETPLATFORM)
+endif
+ifeq ($(TARGETPLATFORM), unix-generic)
+ @./configure-system-libraries.sh
+endif
@echo
@echo "Checking for explicit interface violations..."
- @$(OPENRA_UTILITY) all --check-explicit-interfaces
+ @./utility.sh all --check-explicit-interfaces
@echo
@echo "Checking for incorrect conditional trait interface overrides..."
- @$(OPENRA_UTILITY) all --check-conditional-trait-interface-overrides
+ @./utility.sh all --check-conditional-trait-interface-overrides
check-scripts:
@echo
@@ -104,16 +119,16 @@ check-scripts:
test: all
@echo
@echo "Testing Tiberian Sun mod MiniYAML..."
- @$(OPENRA_UTILITY) ts --check-yaml
+ @./utility.sh ts --check-yaml
@echo
@echo "Testing Dune 2000 mod MiniYAML..."
- @$(OPENRA_UTILITY) d2k --check-yaml
+ @./utility.sh d2k --check-yaml
@echo
@echo "Testing Tiberian Dawn mod MiniYAML..."
- @$(OPENRA_UTILITY) cnc --check-yaml
+ @./utility.sh cnc --check-yaml
@echo
@echo "Testing Red Alert mod MiniYAML..."
- @$(OPENRA_UTILITY) ra --check-yaml
+ @./utility.sh ra --check-yaml
############# LOCAL INSTALLATION AND DOWNSTREAM PACKAGING ##############
#
@@ -122,7 +137,11 @@ version: VERSION mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mo
@sh -c '. ./packaging/functions.sh; set_mod_version $(VERSION) mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modcontent/mod.yaml mods/all/mod.yaml'
install:
+ifeq ($(RUNTIME), mono)
@sh -c '. ./packaging/functions.sh; install_assemblies_mono $(CWD) $(DESTDIR)$(gameinstalldir) $(TARGETPLATFORM) True True True'
+else
+ @sh -c '. ./packaging/functions.sh; install_assemblies $(CWD) $(DESTDIR)$(gameinstalldir) $(TARGETPLATFORM) True True True'
+endif
@sh -c '. ./packaging/functions.sh; install_data $(CWD) $(DESTDIR)$(gameinstalldir) cnc d2k ra'
install-linux-shortcuts:
@@ -133,23 +152,26 @@ install-linux-appdata:
help:
@echo 'to compile, run:'
- @echo ' make [DEBUG=true]'
+ @echo ' make'
+ @echo
+ @echo 'to compile using Mono (version 6.4 or greater) instead of .NET 5, run:'
+ @echo ' make RUNTIME=mono'
@echo
@echo 'to compile using system libraries for native dependencies, run:'
- @echo ' make [DEBUG=true] TARGETPLATFORM=unix-generic'
+ @echo ' make [RUNTIME=dotnet] TARGETPLATFORM=unix-generic'
@echo
@echo 'to check the official mods for erroneous yaml files, run:'
- @echo ' make test'
+ @echo ' make [RUNTIME=dotnet] test'
@echo
@echo 'to check the engine and official mod dlls for code style violations, run:'
- @echo ' make test'
+ @echo ' make [RUNTIME=dotnet] check'
@echo
@echo 'to compile and install Red Alert, Tiberian Dawn, and Dune 2000 run:'
- @echo ' make [prefix=/foo] [TARGETPLATFORM=unix-generic] install'
+ @echo ' make [RUNTIME=dotnet] [prefix=/foo] [TARGETPLATFORM=unix-generic] install'
@echo
@echo 'to compile and install Red Alert, Tiberian Dawn, and Dune 2000'
@echo 'using system libraries for native dependencies, run:'
- @echo ' make [prefix=/foo] [bindir=/bar/bin] TARGETPLATFORM=unix-generic install'
+ @echo ' make [RUNTIME=dotnet] [prefix=/foo] [bindir=/bar/bin] TARGETPLATFORM=unix-generic install'
@echo
@echo 'to install Linux startup scripts, desktop files, icons, and MIME metadata'
@echo ' make install-linux-shortcuts'
diff --git a/configure-system-libraries.sh b/configure-system-libraries.sh
index 34c0f52583..b046733520 100755
--- a/configure-system-libraries.sh
+++ b/configure-system-libraries.sh
@@ -14,20 +14,39 @@ patch_config()
REPLACE=$4
SEARCH=$5
- # Exit early if the file has already been patched
- grep -q "target=\"${REPLACE}\"" "${CONFIG}" || return 0
+ if command -v mono >/dev/null 2>&1 && [ "$(grep -c .NETCoreApp,Version= bin/OpenRA.dll)" = "0" ]; then
+ # Exit early if the file has already been patched
+ grep -q "target=\"${REPLACE}\"" "${CONFIG}" || return 0
- printf "Searching for %s... " "${LABEL}"
- for DIR in ${SEARCHDIRS} ; do
- for LIB in ${SEARCH}; do
- if [ -f "${DIR}/${LIB}" ]; then
- echo "${LIB}"
- sed "s|target=\"${REPLACE}\"|target=\"${DIR}/${LIB}\"|" "${CONFIG}" > "${CONFIG}.temp"
- mv "${CONFIG}.temp" "${CONFIG}"
- return 0
- fi
+ printf "Searching for %s... " "${LABEL}"
+ for DIR in ${SEARCHDIRS} ; do
+ for LIB in ${SEARCH}; do
+ if [ -f "${DIR}/${LIB}" ]; then
+ echo "${LIB}"
+ sed "s|target=\"${REPLACE}\"|target=\"${DIR}/${LIB}\"|" "${CONFIG}" > "${CONFIG}.temp"
+ mv "${CONFIG}.temp" "${CONFIG}"
+ return 0
+ fi
+ done
done
- done
+ else
+ # NET 5 does not support .config files, so we must use symlinks instead
+ # Exit early if the symlink already exists
+ if [ -L "bin/${REPLACE}" ]; then
+ return 0
+ fi
+
+ printf "Searching for %s... " "${LABEL}"
+ for DIR in ${SEARCHDIRS} ; do
+ for LIB in ${SEARCH}; do
+ if [ -f "${DIR}/${LIB}" ]; then
+ echo "${LIB}"
+ ln -s "${DIR}/${LIB}" "bin/${REPLACE}"
+ return 0
+ fi
+ done
+ done
+ fi
echo "FAILED"
diff --git a/launch-dedicated.sh b/launch-dedicated.sh
index c5931f5dd8..8db56b6485 100755
--- a/launch-dedicated.sh
+++ b/launch-dedicated.sh
@@ -6,6 +6,12 @@
# $ Mod="d2k" ./launch-dedicated.sh # Launch a dedicated server with default settings but override the Mod
# Read the file to see which settings you can override
+if command -v mono >/dev/null 2>&1 && [ "$(grep -c .NETCoreApp,Version= bin/OpenRA.Server.dll)" = "0" ]; then
+ RUNTIME_LAUNCHER="mono --debug"
+else
+ RUNTIME_LAUNCHER="dotnet"
+fi
+
Name="${Name:-"Dedicated Server"}"
Mod="${Mod:-"ra"}"
ListenPort="${ListenPort:-"1234"}"
@@ -25,14 +31,13 @@ ShareAnonymizedIPs="${ShareAnonymizedIPs:-"True"}"
SupportDir="${SupportDir:-""}"
while true; do
- mono --debug bin/OpenRA.Server.dll Engine.EngineDir=".." Game.Mod="$Mod" \
+ ${RUNTIME_LAUNCHER} bin/OpenRA.Server.dll Engine.EngineDir=".." Game.Mod="$Mod" \
Server.Name="$Name" \
Server.ListenPort="$ListenPort" \
Server.AdvertiseOnline="$AdvertiseOnline" \
Server.EnableSingleplayer="$EnableSingleplayer" \
Server.Password="$Password" \
Server.RecordReplays="$RecordReplays" \
- Server.GeoIPDatabase="$GeoIPDatabase" \
Server.RequireAuthentication="$RequireAuthentication" \
Server.ProfileIDBlacklist="$ProfileIDBlacklist" \
Server.ProfileIDWhitelist="$ProfileIDWhitelist" \
diff --git a/launch-game.sh b/launch-game.sh
index 4fbc5236c9..0587a90798 100755
--- a/launch-game.sh
+++ b/launch-game.sh
@@ -1,8 +1,14 @@
#!/bin/sh
-if command -v python3 >/dev/null 2>&1; then
- MODLAUNCHER=$(python3 -c "import os; print(os.path.realpath('$0'))")
+if command -v mono >/dev/null 2>&1 && [ "$(grep -c .NETCoreApp,Version= bin/OpenRA.dll)" = "0" ]; then
+ RUNTIME_LAUNCHER="mono --debug"
else
- MODLAUNCHER=$(python -c "import os; print(os.path.realpath('$0'))")
+ RUNTIME_LAUNCHER="dotnet"
+fi
+
+if command -v python3 >/dev/null 2>&1; then
+ LAUNCHPATH=$(python3 -c "import os; print(os.path.realpath('$0'))")
+else
+ LAUNCHPATH=$(python -c "import os; print(os.path.realpath('$0'))")
fi
# Prompt for a mod to launch if one is not already specified
@@ -25,7 +31,7 @@ then
fi
# Launch the engine with the appropriate arguments
-mono --debug bin/OpenRA.dll Engine.EngineDir=".." Engine.LaunchPath="$MODLAUNCHER" $MODARG "$@"
+${RUNTIME_LAUNCHER} bin/OpenRA.dll Engine.EngineDir=".." Engine.LaunchPath="${LAUNCHPATH}" ${MODARG} "$@"
# Show a crash dialog if something went wrong
if [ $? != 0 ] && [ $? != 1 ]; then
diff --git a/packaging/functions.sh b/packaging/functions.sh
index 37d5260ab8..60c19f226c 100755
--- a/packaging/functions.sh
+++ b/packaging/functions.sh
@@ -82,6 +82,7 @@ install_assemblies_mono() {
# COPY_CNC_DLL: If set to True the OpenRA.Mods.Cnc.dll will also be copied (True, False)
# COPY_D2K_DLL: If set to True the OpenRA.Mods.D2k.dll will also be copied (True, False)
# Used by:
+# Makefile (install target for local installs and downstream packaging)
# Windows packaging
# macOS packaging
# Linux AppImage packaging
diff --git a/utility.sh b/utility.sh
index 49f378a472..dc002d25ce 100755
--- a/utility.sh
+++ b/utility.sh
@@ -1,2 +1,8 @@
#!/bin/sh
-ENGINE_DIR=.. mono --debug bin/OpenRA.Utility.dll $@
+if command -v mono >/dev/null 2>&1 && [ "$(grep -c .NETCoreApp,Version= bin/OpenRA.Utility.dll)" = "0" ]; then
+ RUNTIME_LAUNCHER="mono --debug"
+else
+ RUNTIME_LAUNCHER="dotnet"
+fi
+
+ENGINE_DIR=.. ${RUNTIME_LAUNCHER} bin/OpenRA.Utility.dll "$@"