#!/usr/bin/env bash # Build a Skate 3 recomp release from this checkout and optionally publish it # to a Forgejo/Gitea Release. # # IMPORTANT: the release zip contains ONLY the recompiled binaries # (skate3 + librexruntime.so + ghost_relay + README) - NO game files. Players # bring their own ISO and the in-app installer extracts it. The game dump # (default.xex + data/webkit/EAWebkit.xex) is required at BUILD TIME only, # because codegen translates the actual Xbox 360 binary into C++ source; it # is never included in, or uploaded with, the release. # # Usage: # ./tools/release/release.sh # build this platform, no upload # ./tools/release/release.sh --tag v1.0.0 --upload # build + publish # ./tools/release/release.sh --game-root /path/to/game --tu /path/to/TU_12K2276_... # # Options: # --tag TAG release tag/version (default: last git tag or 'dev') # --game-root DIR extracted game dump (default: $REPO/game) # --tu FILE optional Title Update STFS package for codegen # --os linux|windows|macos override platform (default: host OS) # --cmake-args "..." extra flags appended to every cmake configure # call (e.g. -DCMAKE_C_COMPILER=clang-22 # -DCMAKE_CXX_COMPILER=clang++-22 # -DCMAKE_LINKER=ld.lld on distros without clang-20) # --upload publish the zip to a Forgejo Release # # Env for --upload: # GITEA_TOKEN Forgejo token with write:repository (release) scope # FORGEJO_REPO default "ad3laid3/skate3recomp-multiplayer" # FORGEJO_INSTANCE default "https://git.mithraic.cloud" set -euo pipefail REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" cd "$REPO" UPLOAD=0 TAG="" GAME_ROOT="${SKATE3_GAME_DATA_ROOT:-$REPO/game}" TU="${SKATE3_TITLE_UPDATE_PACKAGE:-}" OS_ARG="" CMAKE_ARGS="" while [ $# -gt 0 ]; do case "$1" in --tag) TAG="${2:?--tag needs a value}"; shift 2;; --game-root) GAME_ROOT="$2"; shift 2;; --tu) TU="$2"; shift 2;; --os) OS_ARG="$2"; shift 2;; --cmake-args) CMAKE_ARGS="$2"; shift 2;; --upload) UPLOAD=1; shift;; -h|--help) sed -n '2,32p' "$0"; exit 0;; *) echo "unknown argument: $1"; exit 2;; esac done # ---- platform --------------------------------------------------------------- UNAME_S="$(uname -s 2>/dev/null || echo Windows)" case "${OS_ARG:-$UNAME_S}" in linux|Linux) PRESET="linux-relwithdebinfo"; BIN="skate3"; LIB="librexruntime.so"; EXT="Linux";; windows|Windows|MINGW*|MSYS*|CYGWIN*) PRESET="relwithdebinfo"; BIN="skate3.exe"; LIB="librexruntime.dll"; EXT="Windows";; macos|macOS|Darwin) PRESET="macos-relwithdebinfo"; BIN="skate3"; LIB="librexruntime.dylib"; EXT="macOS";; *) echo "unsupported platform: ${OS_ARG:-$UNAME_S} (set --os linux|windows|macos)"; exit 2;; esac if [ -z "$TAG" ]; then TAG="$(git describe --tags --always 2>/dev/null || echo dev)" fi VER="${TAG#v}" NAME="Skate3Recomp-$EXT-$VER" if [ ! -f "$GAME_ROOT/default.xex" ]; then echo "ERROR: game dump not found at $GAME_ROOT (need default.xex + data/webkit/EAWebkit.xex)" echo " It is required for codegen; it is NOT shipped in the release." exit 1 fi TU_ARGS="" if [ -n "$TU" ]; then if [ ! -f "$TU" ]; then echo "ERROR: title update package not found: $TU"; exit 1; fi TU_ARGS="-DSKATE3_TITLE_UPDATE_PACKAGE=$TU" fi echo "==> Release $TAG ($EXT) preset=$PRESET game=$GAME_ROOT" echo "==> Configure (extra args: ${CMAKE_ARGS:-none})" cmake --preset "$PRESET" -DSKATE3_GAME_DATA_ROOT="$GAME_ROOT" $TU_ARGS $CMAKE_ARGS echo "==> Generate recompiled code" cmake --build --preset "$PRESET" --target generate-all --parallel echo "==> Reconfigure (generated sources)" cmake --preset "$PRESET" -DSKATE3_GAME_DATA_ROOT="$GAME_ROOT" $TU_ARGS $CMAKE_ARGS echo "==> Build" cmake --build --preset "$PRESET" --parallel # ---- package --------------------------------------------------------------- OUT="out/build/$PRESET" STAGE="$NAME" rm -rf "$STAGE"; mkdir -p "$STAGE" cp "$OUT/$BIN" "$STAGE/" # The rexglue runtime lib carries a config suffix (librexruntimerd.so for # relwithdebinfo, librexruntime.so for release); the binary links whichever # was built, so ship it under its real name. RUNTIME="$(ls "$OUT"/librexruntime*.so "$OUT"/librexruntime*.dll "$OUT"/librexruntime*.dylib 2>/dev/null | head -1 || true)" if [ -n "$RUNTIME" ]; then cp "$RUNTIME" "$STAGE/" fi cp "$OUT/ghost_relay" "$STAGE/" 2>/dev/null || true cp "$OUT/ghost_relay.exe" "$STAGE/" 2>/dev/null || true # Title-update patches staged next to the binary when the build used the TU if [ -f "$OUT/game/default.xexp" ]; then mkdir -p "$STAGE/game/data/webkit" cp "$OUT/game/default.xexp" "$STAGE/game/" cp "$OUT/game/data/webkit/EAWebkit.xexp" "$STAGE/game/data/webkit/" 2>/dev/null || true fi cp README.md "$STAGE/" rm -f "$NAME.zip" zip -r "$NAME.zip" "$STAGE" rm -rf "$STAGE" echo "==> Packaged: $NAME.zip ($(du -h "$NAME.zip" | cut -f1))" sha256sum "$NAME.zip" # ---- publish ---------------------------------------------------------------- if [ "$UPLOAD" = 1 ]; then : "${GITEA_TOKEN:?--upload needs GITEA_TOKEN}" REPO_FULL="${FORGEJO_REPO:-ad3laid3/skate3recomp-multiplayer}" INSTANCE="${FORGEJO_INSTANCE:-https://git.mithraic.cloud}" AUTH="Authorization: token $GITEA_TOKEN" echo "==> Publishing $NAME.zip to $INSTANCE/$REPO_FULL release '$TAG'" RELEASE_ID="$(curl -s -X POST "$INSTANCE/api/v1/repos/$REPO_FULL/releases" \ -H "$AUTH" -H "Content-Type: application/json" \ -d "{\"tag_name\":\"$TAG\",\"name\":\"Skate 3 Recomp $TAG\",\"target_commitish\":\"main\"}" \ | python3 -c "import sys,json try: print(json.load(sys.stdin).get('id','')) except Exception: print('')")" if [ -z "$RELEASE_ID" ]; then RELEASE_ID="$(curl -s "$INSTANCE/api/v1/repos/$REPO_FULL/releases/tags/$TAG" -H "$AUTH" \ | python3 -c "import sys,json try: print(json.load(sys.stdin).get('id','')) except Exception: print('')")" fi if [ -z "$RELEASE_ID" ]; then echo "ERROR: could not create/find release '$TAG'"; exit 1 fi curl -s -X POST "$INSTANCE/api/v1/repos/$REPO_FULL/releases/$RELEASE_ID/assets" \ -H "$AUTH" -F "attachment=@$NAME.zip" -F "name=$NAME.zip" \ | python3 -c "import sys,json try: a=json.load(sys.stdin); print('Uploaded asset', a.get('name'), a.get('size'), 'bytes') except Exception as e: print('upload response parse failed:', e)" echo "==> Done: https://git.mithraic.cloud/$REPO_FULL/releases/tag/$TAG" fi