diff --git a/DuckGame/DuckGame.csproj b/DuckGame/DuckGame.csproj
index 0477a467..c9e2faba 100644
--- a/DuckGame/DuckGame.csproj
+++ b/DuckGame/DuckGame.csproj
@@ -232,6 +232,9 @@
False
lib\MonoMod.exe
+
+ ..\packages\Microsoft.NETFramework.ReferenceAssemblies.net48.1.0.3\build\.NETFramework\v4.8\Facades\netstandard.dll
+
lib\NAudio.dll
@@ -244,8 +247,12 @@
lib\NVorbis.NAudioSupport.dll
-
-
+
+ ..\packages\Microsoft.NETFramework.ReferenceAssemblies.net48.1.0.3\build\.NETFramework\v4.8\PresentationCore.dll
+
+
+ ..\packages\Microsoft.NETFramework.ReferenceAssemblies.net48.1.0.3\build\.NETFramework\v4.8\PresentationFramework.dll
+
..\packages\SixLabors.Fonts.1.0.1\lib\netstandard2.0\SixLabors.Fonts.dll
@@ -256,6 +263,10 @@
..\packages\SixLabors.ImageSharp.Drawing.1.0.0\lib\net472\SixLabors.ImageSharp.Drawing.dll
+
+ False
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
..\packages\System.Collections.Immutable.7.0.0\lib\net462\System.Collections.Immutable.dll
@@ -268,7 +279,7 @@
False
- ..\deps\System.Memory.4.5.5\lib\net461\System.Memory.dll
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
@@ -277,9 +288,11 @@
False
- ..\deps\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\Microsoft.NETFramework.ReferenceAssemblies.net48.1.0.3\build\.NETFramework\v4.8\System.Speech.dll
-
..\packages\System.Text.Encoding.CodePages.7.0.0\lib\net462\System.Text.Encoding.CodePages.dll
@@ -290,7 +303,9 @@
-
+
+ ..\packages\Microsoft.NETFramework.ReferenceAssemblies.net48.1.0.3\build\.NETFramework\v4.8\WindowsBase.dll
+
@@ -2489,18 +2504,18 @@
-
+
-
-
+
+
-
+
This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.
-
-
+
+
-
-
\ No newline at end of file
+
+
diff --git a/README.md b/README.md
index b2dbfed7..9f02d989 100644
--- a/README.md
+++ b/README.md
@@ -42,3 +42,13 @@ Note: your IDE will scream at you with 200+ warnings when building, which is nor
* `msbuild -m -p:Configuration=Debug`
* Run the game (will crash unless Steam is currently running)
* `mono ./bin/DuckGame.exe`
+
+### Building on macOS (Mono)
+
+* Install build dependencies with Homebrew
+ * `brew install mono mono-libgdiplus nuget cmake sdl2`
+* Build the game and native macOS libraries
+ * `./scripts/build-macos.sh Release`
+* Run the game from the build output
+ * `./bin/DuckGame.sh -nosteam`
+ * Omit `-nosteam` when Steam is running and `steam_api` is available
diff --git a/scripts/build-macos.sh b/scripts/build-macos.sh
new file mode 100755
index 00000000..a68d87a8
--- /dev/null
+++ b/scripts/build-macos.sh
@@ -0,0 +1,104 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+CONFIGURATION="${1:-Debug}"
+CPU_COUNT="$(sysctl -n hw.ncpu)"
+CMAKE_POLICY_VERSION_MINIMUM="${CMAKE_POLICY_VERSION_MINIMUM:-3.5}"
+
+require_command() {
+ if ! command -v "$1" >/dev/null 2>&1; then
+ echo "Missing required command: $1" >&2
+ exit 1
+ fi
+}
+
+copy_sdl2_dylib() {
+ local sdl2_dylib=""
+ local brew_prefix=""
+
+ if command -v brew >/dev/null 2>&1; then
+ brew_prefix="$(brew --prefix sdl2 2>/dev/null || true)"
+ if [[ -n "$brew_prefix" && -f "$brew_prefix/lib/libSDL2-2.0.0.dylib" ]]; then
+ sdl2_dylib="$brew_prefix/lib/libSDL2-2.0.0.dylib"
+ fi
+ fi
+
+ if [[ -z "$sdl2_dylib" && -f "/opt/homebrew/lib/libSDL2-2.0.0.dylib" ]]; then
+ sdl2_dylib="/opt/homebrew/lib/libSDL2-2.0.0.dylib"
+ fi
+
+ if [[ -z "$sdl2_dylib" && -f "/usr/local/lib/libSDL2-2.0.0.dylib" ]]; then
+ sdl2_dylib="/usr/local/lib/libSDL2-2.0.0.dylib"
+ fi
+
+ if [[ -z "$sdl2_dylib" ]]; then
+ echo "Could not find libSDL2-2.0.0.dylib. Install sdl2 first (brew install sdl2)." >&2
+ exit 1
+ fi
+
+ cp -f "$sdl2_dylib" "$ROOT_DIR/bin/libSDL2-2.0.0.dylib"
+}
+
+copy_libgdiplus_dylib() {
+ local gdiplus_dylib=""
+ local brew_prefix=""
+
+ if command -v brew >/dev/null 2>&1; then
+ brew_prefix="$(brew --prefix mono-libgdiplus 2>/dev/null || true)"
+ if [[ -n "$brew_prefix" && -f "$brew_prefix/lib/libgdiplus.dylib" ]]; then
+ gdiplus_dylib="$brew_prefix/lib/libgdiplus.dylib"
+ fi
+ fi
+
+ if [[ -z "$gdiplus_dylib" && -f "/opt/homebrew/lib/libgdiplus.dylib" ]]; then
+ gdiplus_dylib="/opt/homebrew/lib/libgdiplus.dylib"
+ fi
+
+ if [[ -z "$gdiplus_dylib" && -f "/usr/local/lib/libgdiplus.dylib" ]]; then
+ gdiplus_dylib="/usr/local/lib/libgdiplus.dylib"
+ fi
+
+ if [[ -z "$gdiplus_dylib" ]]; then
+ echo "Could not find libgdiplus.dylib. Install mono-libgdiplus (brew install mono-libgdiplus)." >&2
+ exit 1
+ fi
+
+ cp -f "$gdiplus_dylib" "$ROOT_DIR/bin/libgdiplus.dylib"
+}
+
+require_command nuget
+require_command xbuild
+require_command cmake
+require_command make
+require_command mono
+
+echo "[1/4] Restoring NuGet packages"
+nuget restore "$ROOT_DIR/DuckGame.sln"
+
+echo "[2/4] Building native macOS libraries"
+cmake -S "$ROOT_DIR/FNA/lib/FAudio" -B "$ROOT_DIR/FNA/lib/FAudio/build" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM="$CMAKE_POLICY_VERSION_MINIMUM"
+cmake --build "$ROOT_DIR/FNA/lib/FAudio/build" --config Release --parallel "$CPU_COUNT"
+
+cmake -S "$ROOT_DIR/FNA/lib/FNA3D" -B "$ROOT_DIR/FNA/lib/FNA3D/build" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MINIMUM="$CMAKE_POLICY_VERSION_MINIMUM"
+cmake --build "$ROOT_DIR/FNA/lib/FNA3D/build" --config Release --parallel "$CPU_COUNT"
+
+make -C "$ROOT_DIR/FNA/lib/Theorafile"
+
+echo "[3/4] Building DuckGame ($CONFIGURATION) with Mono"
+xbuild \
+ /p:Configuration="$CONFIGURATION" \
+ /p:SolutionDir="$ROOT_DIR/" \
+ "$ROOT_DIR/DuckGame/DuckGame.csproj"
+
+echo "[4/4] Copying runtime macOS libraries"
+mkdir -p "$ROOT_DIR/bin"
+cp -f "$ROOT_DIR/FNA/lib/FAudio/build/libFAudio.0.dylib" "$ROOT_DIR/bin/"
+cp -f "$ROOT_DIR/FNA/lib/FNA3D/build/libFNA3D.0.dylib" "$ROOT_DIR/bin/"
+cp -f "$ROOT_DIR/FNA/lib/Theorafile/libtheorafile.dylib" "$ROOT_DIR/bin/"
+copy_sdl2_dylib
+copy_libgdiplus_dylib
+cp -f "$ROOT_DIR/deps/steam_api.bundle/Contents/MacOS/libsteam_api.dylib" "$ROOT_DIR/bin/libsteam_api.dylib"
+
+echo "Build complete."
+echo "Run with: cd \"$ROOT_DIR/bin\" && ./DuckGame.sh"