#!/bin/zsh # Portable local macOS bundle with private Client assets and the validated 2x UI archive. # scripts/package_mac_app.sh [BUILD_DIR] [CLIENT_DIR] [OUT] [HD_UI_PAK] set -euo pipefail repo=${0:A:h:h} build=${1:-$repo/build/release} client=${2:-$repo/build/zh-locale/Client} out=${3:-$repo/dist/Metin2.app} pak=${4:-${MT_HD_UI_PAK:-$repo/build/hd-ui/hd_ui.pak}} bin=$build/src/host/mt_native_render [[ -x "$bin" ]] || { echo "missing native executable: $bin" >&2; exit 1; } [[ -d "$client/pack" ]] || { echo "missing Client/pack: $client" >&2; exit 1; } [[ -f "$pak" ]] || { echo "missing HD UI archive: $pak (run scripts/build_hd_ui.py first)" >&2; exit 1; } python3 "$repo/scripts/verify_hd_ui.py" "$pak" version=$(git -C "$repo" describe --always --dirty 2>/dev/null || echo dev) mkdir -p "${out:A:h}" stage=$(mktemp -d "${out:A}.tmp.XXXXXX") trap 'rm -rf "$stage"' EXIT mkdir -p "$stage/Contents/MacOS" "$stage/Contents/Resources" "$stage/Contents/Frameworks" cp "$bin" "$stage/Contents/MacOS/mt_native_render" cp "$build/src/host/native.vert.spv" "$build/src/host/native.frag.spv" "$build/src/host/python27.zip" "$stage/Contents/Resources/" cp "$repo/branding/icon/macos/AppIcon.icns" "$stage/Contents/Resources/" cp "$pak" "$stage/Contents/Resources/hd_ui.pak" # Clone private assets on APFS; fall back to an ordinary copy on other filesystems. cp -cR "$client" "$stage/Contents/Resources/Client" 2>/dev/null || ditto "$client" "$stage/Contents/Resources/Client" for lib in libvulkan.1.dylib libSDL3.0.dylib; do dependency=$(otool -L "$bin" | awk -v name="$lib" '$1 ~ name "$" {print $1; exit}') [[ -f "$dependency" ]] || { echo "cannot resolve $lib: $dependency" >&2; exit 1; } cp "$dependency" "$stage/Contents/Frameworks/$lib" install_name_tool -change "$dependency" "@rpath/$lib" "$stage/Contents/MacOS/mt_native_render" install_name_tool -id "@rpath/$lib" "$stage/Contents/Frameworks/$lib" done for rpath in ${(f)"$(otool -l "$bin" | awk '/LC_RPATH/ {getline; getline; print $2}')"}; do install_name_tool -delete_rpath "$rpath" "$stage/Contents/MacOS/mt_native_render" done install_name_tool -add_rpath '@executable_path/../Frameworks' "$stage/Contents/MacOS/mt_native_render" molten=${MT_MOLTENVK:-/opt/homebrew/opt/molten-vk/lib/libMoltenVK.dylib} [[ -f "$molten" ]] || molten=/usr/local/opt/molten-vk/lib/libMoltenVK.dylib [[ -f "$molten" ]] || { echo "missing MoltenVK (set MT_MOLTENVK)" >&2; exit 1; } cp "$molten" "$stage/Contents/Frameworks/libMoltenVK.dylib" cat > "$stage/Contents/Resources/MoltenVK_icd.json" <<'JSON' {"file_format_version":"1.0.0","ICD":{"library_path":"../Frameworks/libMoltenVK.dylib","api_version":"1.2.0","is_portability_driver":true}} JSON cat > "$stage/Contents/MacOS/Metin2" <<'SH' #!/bin/sh set -eu CONTENTS_DIR="$(cd "$(dirname "$0")/.." && pwd -P)" RESOURCES_DIR="$CONTENTS_DIR/Resources" export VK_ICD_FILENAMES="$RESOURCES_DIR/MoltenVK_icd.json" # Resource lookup also works when Finder starts us with cwd=/ or Client is overridden. : "${MT_HD_UI_PAK:=$RESOURCES_DIR/hd_ui.pak}" export MT_HD_UI_PAK cd "$RESOURCES_DIR" exec "$CONTENTS_DIR/MacOS/mt_native_render" --interactive \ --live-client "${MT_CLIENT_DIR:-$RESOURCES_DIR/Client}" \ --fake-mobs 24 --width 1280 --height 800 "$@" SH chmod +x "$stage/Contents/MacOS/Metin2" cat > "$stage/Contents/Info.plist" < CFBundleNameMetin2 CFBundleDisplayNameMetin2 CFBundleIdentifierorg.metin2port.client CFBundleExecutableMetin2 CFBundleIconFileAppIcon CFBundlePackageTypeAPPL CFBundleShortVersionString0.1 CFBundleVersion$version LSMinimumSystemVersion12.0 LSApplicationCategoryTypepublic.app-category.role-playing-games NSHighResolutionCapable PLIST for library in "$stage"/Contents/Frameworks/*.dylib; do codesign --force --sign - "$library"; done codesign --force --sign - "$stage/Contents/MacOS/mt_native_render" codesign --force --deep --sign - "$stage" codesign --verify --deep --strict "$stage" # Publish only after validating the complete replacement bundle. rm -rf "$out" mv "$stage" "$out" trap - EXIT echo "$out"