mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-20 12:40:21 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0dd889b35b | |||
| 032f894f7f | |||
| 9922e235c6 | |||
| 667267d9bb | |||
| 6588901e9a | |||
| 142d1358dd |
@@ -26,64 +26,6 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
macos-changes:
|
||||
name: detect macOS changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
changed: ${{ steps.paths.outputs.changed }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: paths
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
|
||||
HEAD_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -Eq '^(conf\.lua$|scripts/(build\.sh|build_love_macos\.sh|run\.sh|setup\.sh)$|Play-Mac\.command$|mobile/macos/|src/core/SaveData\.lua$|\.github/workflows/(ci|release)\.yml$)'; then
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
macos-build:
|
||||
name: macOS LÖVE 12 build
|
||||
needs: macos-changes
|
||||
if: needs.macos-changes.outputs.changed == 'true'
|
||||
runs-on: ${{ fromJSON(github.repository == 'bryanthaboi/gen1recomp' && '["self-hosted", "macOS"]' || '"macos-latest"') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- name: Build LÖVE 12 macOS runtime
|
||||
run: scripts/build_love_macos.sh --fetch
|
||||
- name: Build and verify macOS app
|
||||
env:
|
||||
LOVE_APP: ${{ github.workspace }}/.bazinga/love12/love.app
|
||||
MAC_STAGE_DIR: ${{ runner.temp }}/gen1recomp-mac-stage
|
||||
run: |
|
||||
set -euo pipefail
|
||||
scripts/build.sh mac --no-notarize --identity - --version 0.0.0
|
||||
unzip -tqq 'dist/mac/gen1recomp++-macos.zip'
|
||||
app="$MAC_STAGE_DIR/gen1recomp++.app"
|
||||
[ -d "$app" ]
|
||||
[ -x "$app/Contents/MacOS/gen1recomp++" ]
|
||||
[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$app/Contents/Info.plist")" = 'gen1recomp++' ]
|
||||
[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleDisplayName' "$app/Contents/Info.plist")" = 'gen1recomp++' ]
|
||||
[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$app/Contents/Info.plist")" = 'com.theboisclub.gen1recompplusplus' ]
|
||||
[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$app/Contents/Info.plist")" = 0.0.0 ]
|
||||
codesign --verify --deep --strict "$app"
|
||||
otool -L "$app/Contents/Frameworks/love.framework/love" | grep -q '/Metal.framework/'
|
||||
- name: Upload macOS build
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: gen1recomp++-macos
|
||||
path: dist/mac/gen1recomp++-macos.zip
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
ios-changes:
|
||||
name: detect iOS changes
|
||||
runs-on: ubuntu-latest
|
||||
@@ -178,7 +120,7 @@ jobs:
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -Eq '^(scripts/build_switch\.sh$|scripts/switch/|docs/switch-.*\.md$|tests/switch_ci_workflows_test\.lua$|tests/switch_transfer_docs_test\.lua$|\.github/workflows/(ci|release|platform-artifact-comment)\.yml$|src/core/(NxAssetOverlay|Platform|GameVersion)\.lua$|src/import/CacheFs\.lua$|tests/engine/(assets_version_fallback|nx_generated_guard|nx_yellow_boot|switch_diagnostics|cache_fs_gold_nx_load)_test\.lua$|tests/engine/platform_nx)'; then
|
||||
if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -Eq '^(scripts/build_switch\.sh$|scripts/switch/|docs/switch-.*\.md$|tests/switch_ci_workflows_test\.lua$|tests/switch_transfer_docs_test\.lua$|\.github/workflows/(ci|release|switch-artifact-comment)\.yml$|src/core/(NxAssetOverlay|Platform|GameVersion)\.lua$|src/import/CacheFs\.lua$|tests/engine/(assets_version_fallback|nx_generated_guard|nx_yellow_boot|switch_diagnostics|cache_fs_gold_nx_load)_test\.lua$|tests/engine/platform_nx)'; then
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
name: iOS artifact comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [ci]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: artifact
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
HEAD_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }}
|
||||
run: |
|
||||
artifact_id="$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts" --jq '.artifacts[] | select(.name == "gen1recomp++-ios-ipa") | .id')"
|
||||
[ -n "$artifact_id" ] || exit 0
|
||||
head_owner="${HEAD_REPOSITORY%%/*}"
|
||||
pr_number="$(gh api "repos/$GITHUB_REPOSITORY/pulls?state=open&head=$head_owner:$HEAD_BRANCH" --jq '.[0].number // empty')"
|
||||
[ -n "$pr_number" ] || exit 0
|
||||
echo "artifact_url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts/$artifact_id" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
|
||||
# Upsert via comment-tag only — do not delete-all bot comments (clobbers Switch).
|
||||
- name: Get build info
|
||||
id: build-info
|
||||
env:
|
||||
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
run: |
|
||||
commit_hash="$(printf '%s' "$HEAD_SHA" | cut -c1-7)"
|
||||
build_time="$(date "+%Y-%m-%d %H:%M:%S")"
|
||||
echo "hash=$commit_hash" >> "$GITHUB_OUTPUT"
|
||||
echo "time=$build_time" >> "$GITHUB_OUTPUT"
|
||||
- name: comment iOS artifact
|
||||
if: steps.artifact.outputs.pr_number != ''
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
message: |
|
||||
[gen1recomp++.ipa](${{ steps.artifact.outputs.artifact_url }})
|
||||
|
||||
**Commit**: [#${{ steps.build-info.outputs.hash }}](https://github.com/${{ github.event.workflow_run.head_repository.full_name }}/commit/${{ github.event.workflow_run.head_sha }})
|
||||
**Build Time**: `${{ steps.build-info.outputs.time }}`
|
||||
|
||||
<sub>This comment was automatically generated. [View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})</sub>
|
||||
pr-number: ${{ steps.artifact.outputs.pr_number }}
|
||||
comment-tag: ios-build-result
|
||||
github-token: ${{ github.token }}
|
||||
@@ -1,68 +0,0 @@
|
||||
name: platform artifact comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [ci]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: artifacts
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
HEAD_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
artifacts="$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts")"
|
||||
head_owner="${HEAD_REPOSITORY%%/*}"
|
||||
pr_number="$(gh api "repos/$GITHUB_REPOSITORY/pulls?state=open&head=$head_owner:$HEAD_BRANCH" --jq '.[0].number // empty')"
|
||||
[ -n "$pr_number" ] || exit 0
|
||||
|
||||
message="## CI build artifacts"
|
||||
found=0
|
||||
while IFS='|' read -r platform artifact_name artifact_file; do
|
||||
artifact_id="$(printf '%s' "$artifacts" | jq -r --arg name "$artifact_name" '[.artifacts[] | select(.name == $name) | .id][0] // empty')"
|
||||
if [ -n "$artifact_id" ] && [ "$artifact_id" != null ]; then
|
||||
artifact_url="https://github.com/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts/$artifact_id"
|
||||
message+=$'\n'"- **$platform**: [$artifact_file]($artifact_url)"
|
||||
found=1
|
||||
fi
|
||||
done <<'ARTIFACTS'
|
||||
macOS|gen1recomp++-macos|gen1recomp++-macos.zip
|
||||
iOS|gen1recomp++-ios-ipa|gen1recomp++.ipa
|
||||
Nintendo Switch|gen1recomp-switch-nro|gen1recomp-switch.nro
|
||||
Xbox UWP|gen1recomp-xbox-uwp|gen1recomp-xbox-uwp.zip
|
||||
Linux arm64|gen1recomp-linux-arm64|gen1recomp-linux-arm64.AppImage
|
||||
ARTIFACTS
|
||||
|
||||
[ "$found" -eq 1 ] || exit 0
|
||||
commit_hash="$(printf '%s' "${{ github.event.workflow_run.head_sha }}" | cut -c1-7)"
|
||||
build_time="$(date -u "+%Y-%m-%d %H:%M:%S UTC")"
|
||||
message+=$'\n\n'"**Commit**: [#$commit_hash](https://github.com/$HEAD_REPOSITORY/commit/${{ github.event.workflow_run.head_sha }})"
|
||||
message+=$'\n'"**Build Time**: \`$build_time\`"
|
||||
message+=$'\n\n'"<sub>This comment was automatically generated. [View workflow run](https://github.com/$GITHUB_REPOSITORY/actions/runs/$RUN_ID)</sub>"
|
||||
|
||||
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
|
||||
{
|
||||
echo 'message<<BUILD_MESSAGE'
|
||||
printf '%s\n' "$message"
|
||||
echo 'BUILD_MESSAGE'
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
- name: comment platform artifacts
|
||||
if: steps.artifacts.outputs.pr_number != ''
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
message: ${{ steps.artifacts.outputs.message }}
|
||||
pr-number: ${{ steps.artifacts.outputs.pr_number }}
|
||||
comment-tag: platform-build-result
|
||||
github-token: ${{ github.token }}
|
||||
@@ -344,16 +344,9 @@ jobs:
|
||||
echo "Identities available to codesign:"
|
||||
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
|
||||
|
||||
- name: Build LÖVE 12 macOS runtime
|
||||
run: |
|
||||
set -euo pipefail
|
||||
scripts/build_love_macos.sh --fetch
|
||||
|
||||
- name: Build macOS + Windows + Linux
|
||||
env:
|
||||
GEN1TLS_DLL: ${{ github.workspace }}/dist/native/win-x64/gen1tls.dll
|
||||
LOVE_APP: ${{ github.workspace }}/.bazinga/love12/love.app
|
||||
MAC_STAGE_DIR: ${{ runner.temp }}/gen1recomp-mac-stage
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Sign in-build (identity auto-detected from the temp keychain);
|
||||
@@ -435,8 +428,8 @@ jobs:
|
||||
set -a; . "$ci_dir/notary.env"; set +a
|
||||
echo "::add-mask::$APPLE_APP_PASSWORD"
|
||||
|
||||
app="$RUNNER_TEMP/gen1recomp-mac-stage/gen1recomp++.app"
|
||||
zip="dist/mac/gen1recomp++-macos.zip"
|
||||
app=".bazinga/work/gen1recomp.app"
|
||||
zip="dist/mac/gen1recomp-macos.zip"
|
||||
[ -d "$app" ] || { echo "::error::signed app not found at $app"; exit 1; }
|
||||
if [ -z "${APPLE_ID:-}" ] || [ -z "${APPLE_APP_PASSWORD:-}" ] || [ -z "${APPLE_TEAM_ID:-}" ]; then
|
||||
echo "::error::notary.env is missing APPLE_ID / APPLE_APP_PASSWORD / APPLE_TEAM_ID."
|
||||
@@ -481,7 +474,7 @@ jobs:
|
||||
outdir="dist/release"
|
||||
rm -rf "$outdir"
|
||||
mkdir -p "$outdir"
|
||||
cp "dist/mac/gen1recomp++-macos.zip" "$outdir/gen1recomp++-${v}-macos.zip"
|
||||
cp "dist/mac/gen1recomp-macos.zip" "$outdir/gen1recomp-${v}-macos.zip"
|
||||
cp "dist/win/gen1recomp-win64.zip" "$outdir/gen1recomp-${v}-windows.zip"
|
||||
cp "dist/linux/gen1recomp-linux.zip" "$outdir/gen1recomp-${v}-linux.zip"
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
name: Switch artifact comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [ci]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: artifact
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
HEAD_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }}
|
||||
run: |
|
||||
artifact_id="$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts" --jq '.artifacts[] | select(.name == "gen1recomp-switch-nro") | .id')"
|
||||
[ -n "$artifact_id" ] || exit 0
|
||||
head_owner="${HEAD_REPOSITORY%%/*}"
|
||||
pr_number="$(gh api "repos/$GITHUB_REPOSITORY/pulls?state=open&head=$head_owner:$HEAD_BRANCH" --jq '.[0].number // empty')"
|
||||
[ -n "$pr_number" ] || exit 0
|
||||
echo "artifact_url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts/$artifact_id" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
|
||||
# Upsert via comment-tag only — do not delete-all bot comments (clobbers iOS).
|
||||
- name: Get build info
|
||||
id: build-info
|
||||
env:
|
||||
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
run: |
|
||||
commit_hash="$(printf '%s' "$HEAD_SHA" | cut -c1-7)"
|
||||
build_time="$(date "+%Y-%m-%d %H:%M:%S")"
|
||||
echo "hash=$commit_hash" >> "$GITHUB_OUTPUT"
|
||||
echo "time=$build_time" >> "$GITHUB_OUTPUT"
|
||||
- name: comment Switch artifact
|
||||
if: steps.artifact.outputs.pr_number != ''
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
message: |
|
||||
[gen1recomp-switch.nro](${{ steps.artifact.outputs.artifact_url }})
|
||||
|
||||
**Commit**: [#${{ steps.build-info.outputs.hash }}](https://github.com/${{ github.event.workflow_run.head_repository.full_name }}/commit/${{ github.event.workflow_run.head_sha }})
|
||||
**Build Time**: `${{ steps.build-info.outputs.time }}`
|
||||
|
||||
<sub>This comment was automatically generated. [View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})</sub>
|
||||
pr-number: ${{ steps.artifact.outputs.pr_number }}
|
||||
comment-tag: switch-build-result
|
||||
github-token: ${{ github.token }}
|
||||
+17
-12
@@ -27,15 +27,9 @@ ask() { # ask "question" -> yes by default
|
||||
printf '\n \033[1mPokémon Red - LÖVE2D port\033[0m\n\n'
|
||||
|
||||
have_love() {
|
||||
local app version
|
||||
for app in ".bazinga/love12/love.app" "/Applications/love12.app" "$HOME/Applications/love12.app" \
|
||||
"/Applications/love.app" "$HOME/Applications/love.app"; do
|
||||
[ -x "$app/Contents/MacOS/love" ] || continue
|
||||
version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$app/Contents/Info.plist" 2>/dev/null || true)"
|
||||
printf '%s' "$version" | grep -Eq '^12(\.|$)' || continue
|
||||
otool -L "$app/Contents/Frameworks/love.framework/love" 2>/dev/null \
|
||||
| grep -q '/Metal.framework/' && return 0
|
||||
done
|
||||
command -v love >/dev/null 2>&1 && return 0
|
||||
[ -x "/Applications/love.app/Contents/MacOS/love" ] && return 0
|
||||
[ -x "$HOME/Applications/love.app/Contents/MacOS/love" ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -63,11 +57,22 @@ if ! command -v python3 >/dev/null 2>&1; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! have_love && ! command -v xcodebuild >/dev/null 2>&1; then
|
||||
warn "LÖVE 12 is not installed and Xcode is required to build it for macOS."
|
||||
warn "Install Xcode from the App Store, launch it once, then run this again."
|
||||
# ----------------------------------------------------------------- Homebrew
|
||||
if ! have_love && ! command -v brew >/dev/null 2>&1 \
|
||||
&& [ ! -x /opt/homebrew/bin/brew ] && [ ! -x /usr/local/bin/brew ]; then
|
||||
warn "LÖVE (the game engine) is not installed; the easiest installer is Homebrew"
|
||||
if ask "Install Homebrew now? (asks for your macOS password)"; then
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" \
|
||||
|| { err "Homebrew install failed"; pause_exit 1; }
|
||||
else
|
||||
warn "OK, download LÖVE 11.x yourself from https://love2d.org,"
|
||||
warn "drop love.app into /Applications, then run this again."
|
||||
pause_exit 1
|
||||
fi
|
||||
fi
|
||||
# make brew visible in THIS shell (fresh installs aren't on PATH yet)
|
||||
[ -x /opt/homebrew/bin/brew ] && eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
[ -x /usr/local/bin/brew ] && eval "$(/usr/local/bin/brew shellenv)"
|
||||
|
||||
# ------------------------------------------------------------------- build
|
||||
echo
|
||||
|
||||
@@ -194,9 +194,8 @@ By default the game keeps your save, options, and the private ROM-derived
|
||||
data cache in your OS's normal per-user app data folder. To keep everything
|
||||
next to the game instead (handy for a USB stick or portable drive you carry
|
||||
between computers), drop an empty file named `portable.txt` next to the app
|
||||
(next to `gen1recomp++.app` on macOS or `gen1recomp.exe` on Windows, or next
|
||||
to `main.lua`/`conf.lua` when running from source), then launch the game.
|
||||
Portable mode is desktop-only
|
||||
(next to `gen1recomp.app`/`.exe`, or next to `main.lua`/`conf.lua` when
|
||||
running from source), then launch the game. Portable mode is desktop-only
|
||||
(Windows, Linux, macOS); it has no effect on Android or iOS, where the app
|
||||
runs from a read-only package.
|
||||
|
||||
|
||||
@@ -193,6 +193,26 @@ get_controls
|
||||
[ -f "${controlfolder}/mod_${CFW_NAME}.txt" ] && source "${controlfolder}/mod_${CFW_NAME}.txt"
|
||||
|
||||
GAMEDIR="$SHDIR/gen1recomp"
|
||||
# Anbernic stock keeps the launcher and the game folder side by side, so the
|
||||
# SHDIR-relative path above is correct there and is tried first.
|
||||
#
|
||||
# Other firmwares (muOS, and PortMaster's layout on several devices) keep
|
||||
# launcher scripts and port data in SEPARATE trees -- scripts under roms/ports,
|
||||
# data under ports -- so the sibling folder holds no game.
|
||||
#
|
||||
# Probe for the BINARY, not the directory: on a split layout this script has
|
||||
# usually already created "$SHDIR/gen1recomp/conf" and log.txt on an earlier
|
||||
# failed run (see mkdir/tee below), so an existence test matches a decoy of our
|
||||
# own making. Stock is unaffected -- its sibling holds the real binary and wins
|
||||
# on the first test.
|
||||
if [ ! -f "$GAMEDIR/bin/love.aarch64" ]; then
|
||||
for candidate in "/$directory/ports/gen1recomp" \
|
||||
"/mnt/sdcard/ports/gen1recomp" \
|
||||
"/mnt/mmc/ports/gen1recomp" \
|
||||
"/roms/ports/gen1recomp"; do
|
||||
if [ -f "$candidate/bin/love.aarch64" ]; then GAMEDIR="$candidate"; break; fi
|
||||
done
|
||||
fi
|
||||
CONFDIR="$GAMEDIR/conf"
|
||||
mkdir -p "$CONFDIR"
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ function love.conf(t)
|
||||
t.window.minwidth = 480
|
||||
t.window.minheight = 360
|
||||
end
|
||||
t.version = (love._os == "iOS" or love._os == "OS X") and "12.0" or "11.5"
|
||||
t.version = love._os == "iOS" and "12.0" or "11.5"
|
||||
t.window.vsync = 1
|
||||
t.modules.audio = not companion
|
||||
t.modules.joystick = not companion
|
||||
|
||||
@@ -188,8 +188,8 @@ or the Switch-related workflow YAML), CI runs:
|
||||
head is that repo (same-repo push/PR). Fork CI never runs fused. Fork PRs into the main repo also skip Switch fused (offline selftest still runs) so untrusted head code is not executed on the self-hosted Mac; iOS device build eligibility is unchanged. Fused also waits for a successful offline selftest before starting on the Mac runner.
|
||||
3. On successful PR fused builds, a follow-up workflow posts a PR comment
|
||||
linking the Actions artifact named `gen1recomp-switch-nro`
|
||||
(comment tag `platform-build-result`; see
|
||||
`.github/workflows/platform-artifact-comment.yml`).
|
||||
(comment tag `switch-build-result`; see
|
||||
`.github/workflows/switch-artifact-comment.yml`).
|
||||
|
||||
Unrelated PRs do not burn the self-hosted Mac on Switch packaging.
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
a5522634f1e581a1ebab73bf3ab4bd7a853b7a3e
|
||||
@@ -1 +0,0 @@
|
||||
97d4465e8c81099f79696ea4b4bb8b1f9083bc1a
|
||||
@@ -1 +0,0 @@
|
||||
12.0
|
||||
@@ -1,19 +0,0 @@
|
||||
# macOS build
|
||||
|
||||
The desktop app uses the pinned LÖVE 12 runtime built from the LÖVE source
|
||||
tree and the matching Apple dependency repository. The runtime enables Metal
|
||||
and is fused into the branded `gen1recomp++.app` bundle.
|
||||
|
||||
Build the runtime and desktop app from the repository root:
|
||||
|
||||
```bash
|
||||
scripts/build_love_macos.sh --fetch
|
||||
LOVE_APP="$PWD/.bazinga/love12/love.app" scripts/build.sh mac --no-notarize --identity -
|
||||
```
|
||||
|
||||
The source and dependency revisions are recorded in `LOVE_SOURCE_REF` and
|
||||
`APPLE_DEPENDENCIES_REF`. Delete `.bazinga/love12/source` or use `--clean`
|
||||
when changing those pins.
|
||||
|
||||
The packaged executable is `gen1recomp++` inside `gen1recomp++.app`, and the
|
||||
bundle declares LÖVE 12.0 compatibility.
|
||||
+15
-75
@@ -8,7 +8,7 @@
|
||||
# [--notary-profile NAME] [--no-notarize]
|
||||
# [--release] # ios only: release config instead of debug
|
||||
#
|
||||
# Output: dist/mac/gen1recomp++-macos.zip
|
||||
# Output: dist/mac/gen1recomp-macos.zip
|
||||
# dist/win/gen1recomp-win64.zip
|
||||
# dist/linux/gen1recomp-linux.zip (fused x86_64 AppImage)
|
||||
# dist/android/debug/*.apk (full gradle output stays under
|
||||
@@ -27,18 +27,13 @@ ENTITLEMENTS="$ROOT/scripts/macos-entitlements.plist"
|
||||
|
||||
APP_NAME="gen1recomp"
|
||||
BUNDLE_ID="com.theboisclub.pokemonred"
|
||||
MAC_APP_NAME="gen1recomp++"
|
||||
MAC_BUNDLE_ID="com.theboisclub.gen1recompplusplus"
|
||||
LOVE_VERSION="11.5"
|
||||
LOVE_MAC_VERSION="$(tr -d '[:space:]' < "$ROOT/mobile/macos/LOVE_VERSION" 2>/dev/null || echo 12.0)"
|
||||
LOVE_MAC_APP="$HERE/love12/love.app"
|
||||
VERSION="$(git -C "$ROOT" rev-parse --short HEAD 2>/dev/null || echo dev)"
|
||||
VERSION_EXPLICIT=false
|
||||
IDENTITY=""
|
||||
TARGET="all"
|
||||
NOTARY_PROFILE="notary-profile"
|
||||
NOTARIZE=true
|
||||
FETCH_MAC_RUNTIME=false
|
||||
IOS_RELEASE=false
|
||||
IOS_IPA=false
|
||||
|
||||
@@ -46,22 +41,6 @@ say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33mwarn:\033[0m %s\n' "$*" >&2; }
|
||||
fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
strip_bundle_metadata() {
|
||||
local bundle="$1"
|
||||
xattr -rc "$bundle"
|
||||
xattr -rd com.apple.FinderInfo "$bundle" 2>/dev/null || true
|
||||
xattr -rd 'com.apple.fileprovider.fpfs#P' "$bundle" 2>/dev/null || true
|
||||
}
|
||||
|
||||
valid_love12_app() {
|
||||
local app="$1" version
|
||||
[ -x "$app/Contents/MacOS/love" ] || return 1
|
||||
version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$app/Contents/Info.plist" 2>/dev/null || true)"
|
||||
printf '%s' "$version" | grep -Eq '^12(\.|$)' || return 1
|
||||
otool -L "$app/Contents/Frameworks/love.framework/love" 2>/dev/null \
|
||||
| grep -q '/Metal.framework/'
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
mac|win|linux|android|ios|all) TARGET="$1" ;;
|
||||
@@ -69,7 +48,6 @@ while [ $# -gt 0 ]; do
|
||||
--identity) IDENTITY="$2"; shift ;;
|
||||
--notary-profile) NOTARY_PROFILE="$2"; shift ;;
|
||||
--no-notarize) NOTARIZE=false ;;
|
||||
--fetch) FETCH_MAC_RUNTIME=true ;;
|
||||
--release) IOS_RELEASE=true ;;
|
||||
--ipa) IOS_IPA=true ;;
|
||||
*) fail "unknown argument: $1" ;;
|
||||
@@ -172,55 +150,24 @@ make_ico() { # $1 = output .ico path
|
||||
# --------------------------------------------------------------- macOS
|
||||
build_mac() {
|
||||
say "building macOS app"
|
||||
local love_app="${LOVE_APP:-}"
|
||||
if [ -z "$love_app" ]; then
|
||||
for candidate in "$LOVE_MAC_APP" "/Applications/love12.app" "$HOME/Applications/love12.app" \
|
||||
"/Applications/love.app" "$HOME/Applications/love.app"; do
|
||||
if [ -d "$candidate" ] && valid_love12_app "$candidate"; then
|
||||
love_app="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ ! -d "$love_app" ] && [ -z "${LOVE_APP:-}" ] && $FETCH_MAC_RUNTIME; then
|
||||
"$ROOT/scripts/build_love_macos.sh" --fetch
|
||||
love_app="$LOVE_MAC_APP"
|
||||
fi
|
||||
[ -d "$love_app" ] || fail "LÖVE 12 Metal app not found; run scripts/build_love_macos.sh --fetch or set LOVE_APP=/path/to/love.app"
|
||||
local love_version
|
||||
love_version=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$love_app/Contents/Info.plist" 2>/dev/null || true)
|
||||
printf '%s' "$love_version" | grep -Eq '^12(\.|$)' \
|
||||
|| fail "macOS build requires LÖVE $LOVE_MAC_VERSION at $love_app (set LOVE_APP to a LÖVE 12 app)"
|
||||
[ -f "$love_app/Contents/Frameworks/love.framework/love" ] \
|
||||
|| fail "macOS build requires love.framework at $love_app"
|
||||
otool -L "$love_app/Contents/Frameworks/love.framework/love" \
|
||||
| grep -q '/Metal.framework/' \
|
||||
|| fail "macOS build requires a LÖVE runtime linked to Metal at $love_app"
|
||||
local love_app="${LOVE_APP:-/Applications/love.app}"
|
||||
[ -d "$love_app" ] || fail "LÖVE.app not found at $love_app (install it or set LOVE_APP=/path/to/love.app)"
|
||||
|
||||
local stage_dir="${MAC_STAGE_DIR:-${RUNNER_TEMP:-/tmp}/gen1recomp-mac-stage}"
|
||||
local out_app="$stage_dir/$MAC_APP_NAME.app"
|
||||
mkdir -p "$stage_dir"
|
||||
local out_app="$WORK/$APP_NAME.app"
|
||||
rm -rf "$out_app"
|
||||
ditto --norsrc "$love_app" "$out_app"
|
||||
|
||||
local love_executable="$out_app/Contents/MacOS/love"
|
||||
local app_executable="$out_app/Contents/MacOS/$MAC_APP_NAME"
|
||||
[ -f "$love_executable" ] || fail "LÖVE app is missing Contents/MacOS/love"
|
||||
mv "$love_executable" "$app_executable"
|
||||
cp -R "$love_app" "$out_app"
|
||||
|
||||
# drop any bundled placeholder .love and fuse ours in
|
||||
find "$out_app/Contents/Resources" -maxdepth 1 -name '*.love' -delete
|
||||
cp "$LOVE_FILE" "$out_app/Contents/Resources/game.love"
|
||||
|
||||
local plist="$out_app/Contents/Info.plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleName $MAC_APP_NAME" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleName string $MAC_APP_NAME" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $MAC_APP_NAME" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleDisplayName string $MAC_APP_NAME" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleExecutable $MAC_APP_NAME" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleExecutable string $MAC_APP_NAME" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $MAC_BUNDLE_ID" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleIdentifier string $MAC_BUNDLE_ID" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleName $APP_NAME" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleName string $APP_NAME" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $APP_NAME" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleDisplayName string $APP_NAME" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleIdentifier string $BUNDLE_ID" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string $VERSION" "$plist"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $VERSION" "$plist" 2>/dev/null \
|
||||
@@ -242,11 +189,6 @@ build_mac() {
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIconFile OS X AppIcon" "$plist" 2>/dev/null \
|
||||
|| /usr/libexec/PlistBuddy -c "Add :CFBundleIconFile string 'OS X AppIcon'" "$plist"
|
||||
|
||||
strip_bundle_metadata "$out_app"
|
||||
|
||||
rm -rf "$WORK/$MAC_APP_NAME.app"
|
||||
ln -s "$out_app" "$WORK/$MAC_APP_NAME.app"
|
||||
|
||||
local id="$IDENTITY"
|
||||
if [ -z "$id" ]; then
|
||||
id="$(security find-identity -v -p codesigning 2>/dev/null | grep 'Developer ID Application' | head -1 | sed -E 's/^[^"]*"(.*)"$/\1/' || true)"
|
||||
@@ -268,9 +210,9 @@ build_mac() {
|
||||
warn "keychain profile '$NOTARY_PROFILE' not found/working, skipping notarization."
|
||||
warn "set it up with: xcrun notarytool store-credentials \"$NOTARY_PROFILE\" --apple-id ... --team-id ... --password ..."
|
||||
else
|
||||
local notarize_zip="$stage_dir/$MAC_APP_NAME-notarize.zip"
|
||||
local notarize_zip="$WORK/$APP_NAME-notarize.zip"
|
||||
rm -f "$notarize_zip"
|
||||
(cd "$stage_dir" && ditto -c -k --keepParent "$MAC_APP_NAME.app" "$notarize_zip")
|
||||
(cd "$WORK" && ditto -c -k --keepParent "$APP_NAME.app" "$notarize_zip")
|
||||
say "submitting to Apple notary service (this can take a few minutes)"
|
||||
xcrun notarytool submit "$notarize_zip" --keychain-profile "$NOTARY_PROFILE" --wait
|
||||
say "stapling notarization ticket"
|
||||
@@ -279,11 +221,9 @@ build_mac() {
|
||||
fi
|
||||
fi
|
||||
|
||||
strip_bundle_metadata "$out_app"
|
||||
|
||||
local zip_out="$DIST/mac/$MAC_APP_NAME-macos.zip"
|
||||
local zip_out="$DIST/mac/$APP_NAME-macos.zip"
|
||||
rm -f "$zip_out"
|
||||
(cd "$stage_dir" && ditto -c -k --norsrc --keepParent "$MAC_APP_NAME.app" "$zip_out")
|
||||
(cd "$WORK" && ditto -c -k --sequesterRsrc --keepParent "$APP_NAME.app" "$zip_out")
|
||||
say "macOS build: $zip_out"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
MACOS_DIR="$ROOT/mobile/macos"
|
||||
CACHE="$ROOT/.bazinga/love12"
|
||||
SOURCE_DIR="${LOVE_SOURCE_DIR:-$CACHE/source}"
|
||||
RUNTIME_APP="${LOVE_APP_OUTPUT:-$CACHE/love.app}"
|
||||
BUILD_DIR="$CACHE/build"
|
||||
LOVE_VERSION="$(tr -d '[:space:]' < "$MACOS_DIR/LOVE_VERSION")"
|
||||
LOVE_SOURCE_REF="$(tr -d '[:space:]' < "$MACOS_DIR/LOVE_SOURCE_REF")"
|
||||
APPLE_DEPENDENCIES_REF="$(tr -d '[:space:]' < "$MACOS_DIR/APPLE_DEPENDENCIES_REF")"
|
||||
LOVE_SOURCE_REPO="${LOVE_SOURCE_REPO:-https://github.com/love2d/love.git}"
|
||||
APPLE_DEPENDENCIES_REPO="${APPLE_DEPENDENCIES_REPO:-https://github.com/love2d/love-apple-dependencies.git}"
|
||||
|
||||
FETCH=false
|
||||
CLEAN=false
|
||||
|
||||
say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
|
||||
fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
strip_bundle_metadata() {
|
||||
local bundle="$1"
|
||||
xattr -rc "$bundle"
|
||||
xattr -rd com.apple.FinderInfo "$bundle" 2>/dev/null || true
|
||||
xattr -rd 'com.apple.fileprovider.fpfs#P' "$bundle" 2>/dev/null || true
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--fetch) FETCH=true ;;
|
||||
--clean) CLEAN=true ;;
|
||||
-h|--help)
|
||||
printf '%s\n' 'usage: scripts/build_love_macos.sh [--fetch] [--clean]'
|
||||
exit 0
|
||||
;;
|
||||
*) fail "unknown argument: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
[ "$(uname -s)" = "Darwin" ] || fail "macOS LÖVE builds require Darwin"
|
||||
command -v git >/dev/null 2>&1 || fail "git is required to fetch LÖVE sources"
|
||||
command -v xcodebuild >/dev/null 2>&1 || fail "xcodebuild is required to build LÖVE for macOS"
|
||||
command -v xattr >/dev/null 2>&1 || fail "xattr is required to normalize the runtime bundle"
|
||||
|
||||
source_ready() {
|
||||
[ -d "$SOURCE_DIR/platform/xcode/love.xcodeproj" ] \
|
||||
&& [ -d "$SOURCE_DIR/platform/xcode/macosx/Frameworks/Lua.framework" ] \
|
||||
&& [ -d "$SOURCE_DIR/platform/xcode/shared/Frameworks/SDL3.xcframework" ]
|
||||
}
|
||||
|
||||
source_is_pinned() {
|
||||
[ "$(git -C "$SOURCE_DIR" rev-parse HEAD 2>/dev/null || true)" = "$LOVE_SOURCE_REF" ] \
|
||||
&& [ -f "$SOURCE_DIR/.gen1recomp-apple-dependencies-ref" ] \
|
||||
&& [ "$(tr -d '[:space:]' < "$SOURCE_DIR/.gen1recomp-apple-dependencies-ref")" = "$APPLE_DEPENDENCIES_REF" ]
|
||||
}
|
||||
|
||||
fetch_repo() {
|
||||
local repo_url="$1"
|
||||
local ref="$2"
|
||||
local destination="$3"
|
||||
mkdir -p "$destination"
|
||||
git -C "$destination" init -q
|
||||
git -C "$destination" remote add origin "$repo_url"
|
||||
git -C "$destination" fetch --depth 1 origin "$ref"
|
||||
git -C "$destination" checkout --detach -q FETCH_HEAD
|
||||
}
|
||||
|
||||
fetch_sources() {
|
||||
local tmp
|
||||
mkdir -p "$CACHE"
|
||||
tmp="$(mktemp -d "$CACHE/fetch.XXXXXX")"
|
||||
say "fetching LÖVE source $LOVE_SOURCE_REF"
|
||||
fetch_repo "$LOVE_SOURCE_REPO" "$LOVE_SOURCE_REF" "$tmp/love"
|
||||
say "fetching Apple dependencies $APPLE_DEPENDENCIES_REF"
|
||||
fetch_repo "$APPLE_DEPENDENCIES_REPO" "$APPLE_DEPENDENCIES_REF" "$tmp/dependencies"
|
||||
mkdir -p "$tmp/love/platform/xcode/macosx/Frameworks" "$tmp/love/platform/xcode/shared"
|
||||
cp -R "$tmp/dependencies/macOS/Frameworks/." "$tmp/love/platform/xcode/macosx/Frameworks/"
|
||||
cp -R "$tmp/dependencies/shared/." "$tmp/love/platform/xcode/shared/"
|
||||
rm -rf "$SOURCE_DIR"
|
||||
mkdir -p "$(dirname "$SOURCE_DIR")"
|
||||
mv "$tmp/love" "$SOURCE_DIR"
|
||||
printf '%s\n' "$APPLE_DEPENDENCIES_REF" > "$SOURCE_DIR/.gen1recomp-apple-dependencies-ref"
|
||||
rm -rf "$tmp"
|
||||
say "LÖVE source ready at $SOURCE_DIR"
|
||||
}
|
||||
|
||||
if $CLEAN; then
|
||||
[ -z "${LOVE_SOURCE_DIR:-}" ] \
|
||||
|| fail "--clean cannot be used with LOVE_SOURCE_DIR"
|
||||
rm -rf "$SOURCE_DIR" "$BUILD_DIR" "$RUNTIME_APP"
|
||||
fi
|
||||
|
||||
if ! source_ready || ! source_is_pinned; then
|
||||
if ! $FETCH; then
|
||||
fail "pinned LÖVE 12 sources are missing at $SOURCE_DIR; run scripts/build_love_macos.sh --fetch"
|
||||
fi
|
||||
[ -z "${LOVE_SOURCE_DIR:-}" ] \
|
||||
|| fail "LOVE_SOURCE_DIR is not the pinned LÖVE commit $LOVE_SOURCE_REF"
|
||||
fetch_sources
|
||||
fi
|
||||
|
||||
PROJECT="$SOURCE_DIR/platform/xcode/love.xcodeproj"
|
||||
rm -rf "$BUILD_DIR" "$RUNTIME_APP"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
say "building LÖVE 12 macOS runtime"
|
||||
xcodebuild \
|
||||
-quiet \
|
||||
-project "$PROJECT" \
|
||||
-target love-macosx \
|
||||
-configuration Release \
|
||||
-sdk macosx \
|
||||
SYMROOT="$BUILD_DIR" \
|
||||
OBJROOT="$BUILD_DIR/Intermediates" \
|
||||
ARCHS="arm64 x86_64" \
|
||||
ONLY_ACTIVE_ARCH=NO \
|
||||
MACOSX_DEPLOYMENT_TARGET=12.0 \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
CODE_SIGNING_REQUIRED=NO \
|
||||
CODE_SIGN_IDENTITY=-
|
||||
|
||||
BUILT_APP="$BUILD_DIR/Release/love.app"
|
||||
[ -d "$BUILT_APP" ] || fail "xcodebuild produced no LÖVE app at $BUILT_APP"
|
||||
ditto --norsrc "$BUILT_APP" "$RUNTIME_APP"
|
||||
strip_bundle_metadata "$RUNTIME_APP"
|
||||
|
||||
version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$RUNTIME_APP/Contents/Info.plist" 2>/dev/null || true)"
|
||||
version_re="$(printf '%s' "$LOVE_VERSION" | sed 's/\./\\./g')"
|
||||
printf '%s' "$version" | grep -Eq "^${version_re}(\.|$)" \
|
||||
|| fail "built runtime reports LÖVE version '$version'"
|
||||
[ -x "$RUNTIME_APP/Contents/MacOS/love" ] \
|
||||
|| fail "built runtime is missing Contents/MacOS/love"
|
||||
[ -f "$RUNTIME_APP/Contents/Frameworks/love.framework/love" ] \
|
||||
|| fail "built runtime is missing love.framework"
|
||||
otool -L "$RUNTIME_APP/Contents/Frameworks/love.framework/love" \
|
||||
| grep -q '/Metal.framework/' \
|
||||
|| fail "built LÖVE runtime is not linked to Metal"
|
||||
|
||||
archs="$(lipo -archs "$RUNTIME_APP/Contents/MacOS/love")"
|
||||
printf '%s' "$archs" | grep -qw arm64 \
|
||||
|| fail "built LÖVE app is missing arm64"
|
||||
printf '%s' "$archs" | grep -qw x86_64 \
|
||||
|| fail "built LÖVE app is missing x86_64"
|
||||
framework_archs="$(lipo -archs "$RUNTIME_APP/Contents/Frameworks/love.framework/love")"
|
||||
printf '%s' "$framework_archs" | grep -qw arm64 \
|
||||
|| fail "built LÖVE framework is missing arm64"
|
||||
printf '%s' "$framework_archs" | grep -qw x86_64 \
|
||||
|| fail "built LÖVE framework is missing x86_64"
|
||||
|
||||
say "LÖVE 12 macOS runtime: $RUNTIME_APP"
|
||||
+1
-23
@@ -32,30 +32,8 @@ find_love() {
|
||||
return 1
|
||||
}
|
||||
|
||||
find_love12() {
|
||||
local app version
|
||||
for app in "${LOVE_APP:-}" "$ROOT/.bazinga/love12/love.app" "/Applications/love12.app" "$HOME/Applications/love12.app" \
|
||||
"/Applications/love.app" "$HOME/Applications/love.app"; do
|
||||
[ -n "$app" ] || continue
|
||||
if [ -x "$app/Contents/MacOS/love" ]; then
|
||||
version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$app/Contents/Info.plist" 2>/dev/null || true)"
|
||||
if printf '%s' "$version" | grep -Eq '^12(\.|$)' \
|
||||
&& otool -L "$app/Contents/Frameworks/love.framework/love" 2>/dev/null | grep -q '/Metal.framework/'; then
|
||||
echo "$app/Contents/MacOS/love"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
LOVE_BIN="$(find_love12)" \
|
||||
|| fail "LÖVE 12 with Metal not found, run scripts/setup.sh or scripts/build_love_macos.sh --fetch"
|
||||
else
|
||||
LOVE_BIN="$(find_love)" \
|
||||
LOVE_BIN="$(find_love)" \
|
||||
|| fail "LÖVE not found, run scripts/setup.sh (or install from https://love2d.org)"
|
||||
fi
|
||||
|
||||
# SDL2 on Wayland crashes during desktop drag-and-drop in certain compositors;
|
||||
# default to X11/XWayland when available to ensure rock-solid drag-drop stability.
|
||||
|
||||
+4
-25
@@ -70,32 +70,11 @@ find_love() {
|
||||
return 1
|
||||
}
|
||||
|
||||
valid_love12_app() {
|
||||
local app="$1" version
|
||||
[ -x "$app/Contents/MacOS/love" ] || return 1
|
||||
version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$app/Contents/Info.plist" 2>/dev/null || true)"
|
||||
printf '%s' "$version" | grep -Eq '^12(\.|$)' || return 1
|
||||
otool -L "$app/Contents/Frameworks/love.framework/love" 2>/dev/null \
|
||||
| grep -q '/Metal.framework/'
|
||||
}
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
if valid_love12_app "$ROOT/.bazinga/love12/love.app"; then
|
||||
say "LÖVE 12 found: $ROOT/.bazinga/love12/love.app"
|
||||
elif valid_love12_app "/Applications/love12.app"; then
|
||||
say "LÖVE 12 found: /Applications/love12.app"
|
||||
elif valid_love12_app "$HOME/Applications/love12.app"; then
|
||||
say "LÖVE 12 found: $HOME/Applications/love12.app"
|
||||
elif valid_love12_app "/Applications/love.app"; then
|
||||
say "LÖVE 12 found: /Applications/love.app"
|
||||
elif valid_love12_app "$HOME/Applications/love.app"; then
|
||||
say "LÖVE 12 found: $HOME/Applications/love.app"
|
||||
else
|
||||
say "building LÖVE 12 for macOS"
|
||||
"$ROOT/scripts/build_love_macos.sh" --fetch
|
||||
fi
|
||||
elif LOVE_BIN="$(find_love)"; then
|
||||
if LOVE_BIN="$(find_love)"; then
|
||||
say "LÖVE found: $LOVE_BIN"
|
||||
elif [ "$(uname -s)" = "Darwin" ] && command -v brew >/dev/null 2>&1; then
|
||||
say "installing LÖVE via Homebrew"
|
||||
brew install --cask love
|
||||
else
|
||||
fail "LÖVE 11.x is not installed; install it from https://love2d.org"
|
||||
fi
|
||||
|
||||
+15
-2
@@ -140,7 +140,7 @@ function SaveData.gameFolders()
|
||||
local src = love.filesystem.getSource and love.filesystem.getSource()
|
||||
local sbd = love.filesystem.getSourceBaseDirectory
|
||||
and love.filesystem.getSourceBaseDirectory()
|
||||
-- A packaged macOS build nests the game inside gen1recomp++.app/Contents/
|
||||
-- A packaged macOS build nests the game inside gen1recomp.app/Contents/
|
||||
-- Resources, so getSource()/getSourceBaseDirectory() point INSIDE the
|
||||
-- bundle -- not where the player drops portable.txt (next to the .app).
|
||||
-- Recover the folder containing the .app so a packaged app finds its
|
||||
@@ -1279,14 +1279,27 @@ function SaveData.ensurePlaythroughId(save, injectedFs)
|
||||
local isFresh = save == freshPlaythrough
|
||||
if isFresh then freshPlaythrough = nil end
|
||||
local byVersion = opts.playthroughIds and opts.playthroughIds[version]
|
||||
id = not isFresh and byVersion and byVersion[scope] or nil
|
||||
local existing = byVersion and byVersion[scope]
|
||||
id = not isFresh and existing or nil
|
||||
if type(id) ~= "string" or id == "" then
|
||||
id = SaveData.newPlaythroughId()
|
||||
-- A fresh skeleton still gets its own id (two unsaved New Games sharing a
|
||||
-- slot must stay distinct), and it is still persisted when the slot has no
|
||||
-- binding yet -- that is the contract a tool relies on to resolve
|
||||
-- `selected` at the title after a restart, before any normal SAVE.
|
||||
--
|
||||
-- What it must NOT do is OVERWRITE a binding that already exists. newGame()
|
||||
-- marks a skeleton on the boot frame, before any save is loaded, and mods
|
||||
-- initialise inside that window -- so a mod touching storage at init
|
||||
-- replaced the real save's id with a throwaway, stranding that save's mod
|
||||
-- storage and repeating on every launch.
|
||||
if not (isFresh and type(existing) == "string" and existing ~= "") then
|
||||
opts.playthroughIds = opts.playthroughIds or {}
|
||||
opts.playthroughIds[version] = opts.playthroughIds[version] or {}
|
||||
opts.playthroughIds[version][scope] = id
|
||||
SaveData.saveOptions(opts, injectedFs)
|
||||
end
|
||||
end
|
||||
save.meta.playthroughId = id
|
||||
return id
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ love = love or require("tests.love_stub")
|
||||
-- scripts/build.sh mac layout: the game is an archive inside the .app, the
|
||||
-- player's portable folder is the one holding the .app.
|
||||
local PORTABLE = "/Users/p/Games"
|
||||
local APP = PORTABLE .. "/gen1recomp++.app"
|
||||
local APP = PORTABLE .. "/gen1recomp.app"
|
||||
local SOURCE = APP .. "/Contents/Resources/game.love"
|
||||
local BASE = APP .. "/Contents/MacOS"
|
||||
|
||||
|
||||
@@ -26,11 +26,12 @@ end
|
||||
-- Also gates the NX runtime modules and the NX engine suites so an NX
|
||||
-- runtime regression cannot slip past switch-selftest / switch-build.
|
||||
local SWITCH_PATH_REGEX =
|
||||
[[^(scripts/build_switch\.sh$|scripts/switch/|docs/switch-.*\.md$|tests/switch_ci_workflows_test\.lua$|tests/switch_transfer_docs_test\.lua$|\.github/workflows/(ci|release|platform-artifact-comment)\.yml$|src/core/(NxAssetOverlay|Platform|GameVersion)\.lua$|src/import/CacheFs\.lua$|tests/engine/(assets_version_fallback|nx_generated_guard|nx_yellow_boot|switch_diagnostics|cache_fs_gold_nx_load)_test\.lua$|tests/engine/platform_nx)]]
|
||||
[[^(scripts/build_switch\.sh$|scripts/switch/|docs/switch-.*\.md$|tests/switch_ci_workflows_test\.lua$|tests/switch_transfer_docs_test\.lua$|\.github/workflows/(ci|release|switch-artifact-comment)\.yml$|src/core/(NxAssetOverlay|Platform|GameVersion)\.lua$|src/import/CacheFs\.lua$|tests/engine/(assets_version_fallback|nx_generated_guard|nx_yellow_boot|switch_diagnostics|cache_fs_gold_nx_load)_test\.lua$|tests/engine/platform_nx)]]
|
||||
|
||||
local ci = read(".github/workflows/ci.yml")
|
||||
local release = read(".github/workflows/release.yml")
|
||||
local comment_wf = read(".github/workflows/platform-artifact-comment.yml")
|
||||
local comment_wf = read(".github/workflows/switch-artifact-comment.yml")
|
||||
local ios_comment_wf = read(".github/workflows/ios-artifact-comment.yml")
|
||||
|
||||
-- --- SWCI-01: path detector ---
|
||||
mustContain(ci, "switch-changes:", "ci.yml")
|
||||
@@ -128,26 +129,28 @@ do
|
||||
end
|
||||
|
||||
-- --- SWCI-06 / SWCI-07 / SWFIX-01: PR artifact comment (no delete-all clobber) ---
|
||||
mustContain(comment_wf, "workflows: [ci]", "platform-artifact-comment")
|
||||
for _, artifact in ipairs({
|
||||
"gen1recomp++-macos",
|
||||
"gen1recomp++-ios-ipa",
|
||||
"gen1recomp-switch-nro",
|
||||
"gen1recomp-xbox-uwp",
|
||||
"gen1recomp-linux-arm64",
|
||||
}) do
|
||||
mustContain(comment_wf, artifact, "platform-artifact-comment")
|
||||
end
|
||||
mustContain(comment_wf, "comment-tag: platform-build-result", "platform-artifact-comment")
|
||||
mustContain(comment_wf, "pull_request", "platform-artifact-comment")
|
||||
mustContain(comment_wf, "conclusion == 'success'", "platform-artifact-comment")
|
||||
mustContain(comment_wf, 'exit 0', "platform-artifact-comment no-op")
|
||||
mustContain(comment_wf, "**Commit**:", "platform-artifact-comment")
|
||||
mustContain(comment_wf, "**Build Time**:", "platform-artifact-comment")
|
||||
mustContain(comment_wf, "View workflow run", "platform-artifact-comment")
|
||||
mustContain(comment_wf, "thollander/actions-comment-pull-request@v3", "platform-artifact-comment")
|
||||
mustNotContain(comment_wf, "delete-comment", "platform-artifact-comment")
|
||||
mustNotContain(comment_wf, "izhangzhihao/delete-comment", "platform-artifact-comment")
|
||||
mustContain(comment_wf, "workflows: [ci]", "switch-artifact-comment")
|
||||
mustContain(comment_wf, "gen1recomp-switch-nro", "switch-artifact-comment")
|
||||
mustContain(comment_wf, "comment-tag: switch-build-result", "switch-artifact-comment")
|
||||
mustContain(comment_wf, "pull_request", "switch-artifact-comment")
|
||||
mustContain(comment_wf, "conclusion == 'success'", "switch-artifact-comment")
|
||||
mustContain(comment_wf, 'exit 0', "switch-artifact-comment no-op")
|
||||
mustContain(comment_wf, "**Commit**:", "switch-artifact-comment")
|
||||
mustContain(comment_wf, "**Build Time**:", "switch-artifact-comment")
|
||||
mustContain(comment_wf, "View workflow run", "switch-artifact-comment")
|
||||
mustContain(comment_wf, "thollander/actions-comment-pull-request@v3", "switch-artifact-comment")
|
||||
mustNotContain(comment_wf, "delete-comment", "switch-artifact-comment")
|
||||
mustNotContain(comment_wf, "izhangzhihao/delete-comment", "switch-artifact-comment")
|
||||
|
||||
mustContain(ios_comment_wf, "comment-tag: ios-build-result", "ios-artifact-comment")
|
||||
mustContain(ios_comment_wf, "thollander/actions-comment-pull-request@v3", "ios-artifact-comment")
|
||||
mustNotContain(ios_comment_wf, "delete-comment", "ios-artifact-comment")
|
||||
mustNotContain(ios_comment_wf, "izhangzhihao/delete-comment", "ios-artifact-comment")
|
||||
-- Distinct tags so both commenters can coexist on the same PR
|
||||
check(comment_wf:find("comment-tag: switch-build-result", 1, true)
|
||||
and ios_comment_wf:find("comment-tag: ios-build-result", 1, true)
|
||||
and comment_wf:find("comment-tag: ios-build-result", 1, true) == nil,
|
||||
"iOS and Switch comment-tags must be distinct and present")
|
||||
|
||||
-- --- SWCI-08 / SWCI-09: docs CI vs release ---
|
||||
local build_doc = read("docs/switch-build.md")
|
||||
@@ -158,7 +161,7 @@ mustContain(build_doc, "ubuntu-latest", "switch-build.md")
|
||||
mustContain(build_doc, "selftest_build_switch.sh", "switch-build.md")
|
||||
mustContain(build_doc, "main repo", "switch-build.md")
|
||||
mustContain(build_doc, "gen1recomp-switch-nro", "switch-build.md")
|
||||
mustContain(build_doc, "platform-build-result", "switch-build.md")
|
||||
mustContain(build_doc, "switch-build-result", "switch-build.md")
|
||||
mustContain(build_doc, "hard gate", "switch-build.md")
|
||||
mustContain(build_doc, "continue-on-error", "switch-build.md")
|
||||
mustContain(build_doc, "nacptool", "switch-build.md")
|
||||
|
||||
+15
-4
@@ -988,14 +988,25 @@ def cmd_add_release_workflow(args, repo):
|
||||
# ---------------------------------------------------------------- lint
|
||||
|
||||
def ahash(image):
|
||||
"""Ink-mask hash over the 8x8 downscale: background (the lightest GB
|
||||
shade) vs ink. Swapping the three ink shades -- the classic recolor --
|
||||
leaves the mask intact, which is exactly what MK302 wants to catch."""
|
||||
"""Ink-mask hash over the 8x8 downscale: background vs ink, split at
|
||||
THIS image's own average brightness rather than a fixed shade. Swapping
|
||||
the three ink shades -- the classic recolor -- leaves the mask intact,
|
||||
which is exactly what MK302 wants to catch.
|
||||
|
||||
A fixed cutoff (e.g. "<=200 is ink") only makes sense for sprites with a
|
||||
light background to split against; a mostly-opaque 16x16 icon has almost
|
||||
no pixel above that cutoff, so every such icon collapsed onto the same
|
||||
"all ink" hash and was flagged as a near-duplicate of anything else that
|
||||
also collapsed -- which was most of them, boulder.png included.
|
||||
Thresholding against the image's own mean keeps the split meaningful
|
||||
(and roughly balanced) no matter how light or dark the source is."""
|
||||
from PIL import Image
|
||||
small = image.convert("L").resize((8, 8), Image.LANCZOS)
|
||||
raw = (small.get_flattened_data() if hasattr(small, "get_flattened_data")
|
||||
else small.getdata())
|
||||
return sum((1 << i) for i, p in enumerate(raw) if p <= 200)
|
||||
raw = list(raw)
|
||||
average = sum(raw) / len(raw)
|
||||
return sum((1 << i) for i, p in enumerate(raw) if p <= average)
|
||||
|
||||
|
||||
def hamming(a, b):
|
||||
|
||||
Reference in New Issue
Block a user