Add Xbox UWP build workflow

This commit is contained in:
Caorthann
2026-08-04 15:36:35 +01:00
parent 3b490bc42f
commit ad9b03fe56
28 changed files with 1311 additions and 572 deletions
+79
View File
@@ -181,6 +181,85 @@ jobs:
if-no-files-found: error
retention-days: 7
xbox-uwp-changes:
name: detect Xbox UWP 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 '^(ports/uwp/|scripts/build_xbox_uwp\.sh$|scripts/xbox-uwp/|scripts/pack_love\.sh$|\.github/workflows/(ci|release)\.yml$|src/core/Platform\.lua$|src/import/(CacheFs|RomImporter)\.lua$|src/update/Check\.lua$|tests/engine/(platform_nx|uwp_native_picker)_test\.lua$|tests/rom_importer_double_pick_test\.lua$)'; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
xbox-uwp-selftest:
name: Xbox UWP offline selftest
needs: xbox-uwp-changes
if: needs.xbox-uwp-changes.outputs.changed == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Xbox UWP offline selftest
run: bash scripts/xbox-uwp/selftest_build_xbox_uwp.sh
- name: Build shared payload
run: |
scripts/pack_love.sh \
--output .bazinga/work/ci-game.love \
--listing .bazinga/work/ci-love-listing.txt \
--version 0.0.0
- name: Upload shared payload
uses: actions/upload-artifact@v7
with:
name: gen1recomp-xbox-uwp-payload
path: .bazinga/work/ci-game.love
if-no-files-found: error
retention-days: 1
xbox-uwp-build:
name: Xbox UWP build
needs: [xbox-uwp-changes, xbox-uwp-selftest]
if: |
always()
&& needs.xbox-uwp-changes.outputs.changed == 'true'
&& needs.xbox-uwp-selftest.result == 'success'
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- name: Download shared payload
uses: actions/download-artifact@v8
with:
name: gen1recomp-xbox-uwp-payload
path: .bazinga/work
- name: Build Xbox UWP package
shell: bash
run: |
bash scripts/build_xbox_uwp.sh \
--release \
--version 0.0.0 \
--game-love .bazinga/work/ci-game.love
- name: Upload Xbox UWP package
uses: actions/upload-artifact@v7
with:
name: gen1recomp-xbox-uwp
path: |
dist/xbox-uwp/gen1recomp-0.0.0-xbox-uwp.zip
dist/xbox-uwp/gen1recomp-0.0.0-xbox-uwp.zip.sha256
if-no-files-found: error
retention-days: 7
headless:
name: headless suites (no ROM)
runs-on: ubuntu-latest
+150 -28
View File
@@ -1,9 +1,9 @@
name: Release
# Builds the macOS, Windows, and Linux desktop apps, an Android APK, an iOS
# IPA, a Nintendo Switch SD-ready zip (experimental), and the Anbernic RG34XXSP
# (Stock OS 64-bit MOD / PortMaster) port on the self-hosted Mac runner, and
# publishes them as a GitHub Release.
# IPA, a Nintendo Switch SD-ready zip (experimental), Xbox UWP, and the Anbernic
# RG34XXSP (Stock OS 64-bit MOD / PortMaster) port, then publishes them as a
# GitHub Release.
#
# Versioning:
# - First ever release is 0.1.0.
@@ -43,22 +43,17 @@ concurrency:
cancel-in-progress: false
jobs:
release:
runs-on: ${{ fromJSON(github.repository == 'bryanthaboi/gen1recomp' && '["self-hosted", "macOS"]' || '"macos-latest"') }}
version:
name: determine release version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.ver.outputs.version }}
tag: ${{ steps.ver.outputs.tag }}
steps:
# The self-hosted runner lives under the machine owner's home
# directory; mask it first so absolute paths in every later step's
# output show up as *** in the public workflow logs.
- name: Mask runner paths
run: echo "::add-mask::$HOME"
- name: Checkout
uses: actions/checkout@v7
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Determine version
id: ver
env:
@@ -66,7 +61,6 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
semver_re='^[0-9]+\.[0-9]+\.[0-9]+$'
# 1) Explicit override from a manual run.
@@ -96,7 +90,6 @@ jobs:
| grep -E "$semver_re" \
| sort -t. -k1,1n -k2,2n -k3,3n \
| tail -1 || true)"
if [ -z "$latest" ]; then
version="0.1.0"
echo "No existing release tag; starting at $version"
@@ -124,10 +117,127 @@ jobs:
echo "::error::Release $tag already exists. Pick a different version."
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
love-payload:
name: build release game.love
needs: version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Build shared payload
run: |
scripts/pack_love.sh \
--output dist/payload/game.love \
--listing dist/payload/love-listing.txt \
--version "${{ needs.version.outputs.version }}"
- name: Upload shared payload
uses: actions/upload-artifact@v7
with:
name: gen1recomp-release-love
path: dist/payload/game.love
if-no-files-found: error
retention-days: 1
xbox-uwp:
name: build Xbox UWP release
needs: [version, love-payload]
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- name: Download shared payload
uses: actions/download-artifact@v8
with:
name: gen1recomp-release-love
path: .bazinga/work
- name: Prepare signing certificate
shell: pwsh
env:
CERTIFICATE_BASE64: ${{ secrets.XBOX_UWP_SIGNING_CERTIFICATE }}
CERTIFICATE_PASSWORD: ${{ secrets.XBOX_UWP_SIGNING_PASSWORD }}
CANONICAL_REPOSITORY: ${{ github.repository == 'bryanthaboi/gen1recomp' }}
run: |
if ($env:CANONICAL_REPOSITORY -eq 'true' -and
[string]::IsNullOrWhiteSpace($env:CERTIFICATE_BASE64)) {
throw 'XBOX_UWP_SIGNING_CERTIFICATE is not configured.'
}
if ([string]::IsNullOrWhiteSpace($env:CERTIFICATE_BASE64)) {
"UWP_PUBLISHER=CN=Gen1Recomp" | Out-File $env:GITHUB_ENV -Append
exit 0
}
$pfx = Join-Path $env:RUNNER_TEMP 'gen1recomp-uwp.pfx'
[IO.File]::WriteAllBytes($pfx, [Convert]::FromBase64String($env:CERTIFICATE_BASE64))
$flags = [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::EphemeralKeySet
$cert = [Security.Cryptography.X509Certificates.X509Certificate2]::new(
$pfx, $env:CERTIFICATE_PASSWORD, $flags)
$cer = Join-Path $env:RUNNER_TEMP 'gen1recomp-uwp.cer'
[IO.File]::WriteAllBytes(
$cer,
$cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert))
Import-Certificate -FilePath $cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople | Out-Null
"UWP_PFX=$pfx" | Out-File $env:GITHUB_ENV -Append
"UWP_CERT_THUMBPRINT=$($cert.Thumbprint)" | Out-File $env:GITHUB_ENV -Append
"UWP_PUBLISHER=$($cert.Subject)" | Out-File $env:GITHUB_ENV -Append
- name: Build Xbox UWP package
shell: bash
run: |
bash scripts/build_xbox_uwp.sh \
--release \
--version "${{ needs.version.outputs.version }}" \
--publisher "$UWP_PUBLISHER" \
--game-love .bazinga/work/game.love
- name: Sign and stage Xbox UWP release
shell: pwsh
env:
CERTIFICATE_PASSWORD: ${{ secrets.XBOX_UWP_SIGNING_PASSWORD }}
run: |
if (-not $env:UWP_PFX) {
exit 0
}
scripts/xbox-uwp/stage_release.ps1 `
-Version '${{ needs.version.outputs.version }}' `
-Configuration Release `
-BuildInfo .bazinga/work/xbox-uwp-build-info.json `
-CertificatePath $env:UWP_PFX `
-CertificatePassword $env:CERTIFICATE_PASSWORD
- name: Upload Xbox UWP release
uses: actions/upload-artifact@v7
with:
name: gen1recomp-xbox-uwp-release
path: |
dist/xbox-uwp/gen1recomp-${{ needs.version.outputs.version }}-xbox-uwp.zip
dist/xbox-uwp/gen1recomp-${{ needs.version.outputs.version }}-xbox-uwp.zip.sha256
if-no-files-found: error
retention-days: 1
- name: Remove signing certificate
if: always()
shell: pwsh
run: |
if ($env:UWP_CERT_THUMBPRINT) {
Remove-Item "Cert:\LocalMachine\TrustedPeople\$env:UWP_CERT_THUMBPRINT" -ErrorAction SilentlyContinue
}
if ($env:UWP_PFX) {
Remove-Item $env:UWP_PFX -Force -ErrorAction SilentlyContinue
}
release:
needs: [version, xbox-uwp]
runs-on: ${{ fromJSON(github.repository == 'bryanthaboi/gen1recomp' && '["self-hosted", "macOS"]' || '"macos-latest"') }}
steps:
# The self-hosted runner lives under the machine owner's home
# directory; mask it first so absolute paths in every later step's
# output show up as *** in the public workflow logs.
- name: Mask runner paths
run: echo "::add-mask::$HOME"
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Import signing certificate into a temporary keychain
if: github.repository == 'bryanthaboi/gen1recomp'
run: |
@@ -172,12 +282,12 @@ jobs:
# notarize separately below so it uses secret credentials, not a
# login-keychain profile. "all" also builds the Linux AppImage,
# which needs no signing/notarization.
scripts/build.sh all --version "${{ steps.ver.outputs.version }}" --no-notarize
scripts/build.sh all --version "${{ needs.version.outputs.version }}" --no-notarize
- name: Build Android
run: |
set -euo pipefail
scripts/build_android.sh --version "${{ steps.ver.outputs.version }}"
scripts/build_android.sh --version "${{ needs.version.outputs.version }}"
- name: Install xcbeautify
run: |
@@ -191,10 +301,10 @@ jobs:
set -euo pipefail
if [ "$CANONICAL_REPOSITORY" = true ]; then
scripts/build_ios.sh --fetch --device --release \
--version "${{ steps.ver.outputs.version }}"
--version "${{ needs.version.outputs.version }}"
else
scripts/build_ios.sh --fetch --release \
--version "${{ steps.ver.outputs.version }}"
--version "${{ needs.version.outputs.version }}"
fi
- name: Build Switch
@@ -206,14 +316,14 @@ jobs:
# Needs native switch-tools (nacptool/elf2nro) and/or Docker on the
# Mac self-hosted runner; see docs/switch-build.md.
scripts/build_switch.sh --fetch --fused \
--version "${{ steps.ver.outputs.version }}"
--version "${{ needs.version.outputs.version }}"
- name: Build Anbernic RG34XXSP port
run: |
set -euo pipefail
# Self-contained aarch64 PortMaster-style pack; pulls the LÖVE 11.5
# runtime from PortMaster-GUI, so it needs no signing/notarization.
./build-rg34xxsp.sh --version "${{ steps.ver.outputs.version }}"
./build-rg34xxsp.sh --version "${{ needs.version.outputs.version }}"
- name: Notarize & staple macOS app
if: github.repository == 'bryanthaboi/gen1recomp'
@@ -250,12 +360,19 @@ jobs:
ditto -c -k --sequesterRsrc --keepParent "$app" "$zip"
echo "Notarized + stapled ✓"
- name: Download Xbox UWP release
if: github.repository == 'bryanthaboi/gen1recomp'
uses: actions/download-artifact@v8
with:
name: gen1recomp-xbox-uwp-release
path: dist/xbox-uwp
- name: Stage release assets
if: github.repository == 'bryanthaboi/gen1recomp'
id: assets
run: |
set -euo pipefail
v="${{ steps.ver.outputs.version }}"
v="${{ needs.version.outputs.version }}"
outdir="dist/release"
rm -rf "$outdir"
mkdir -p "$outdir"
@@ -276,6 +393,10 @@ jobs:
# Local fused .nro stays under dist/switch/ for PR CI / debug; release
# publishes the SD-ready zip only.
uwp="dist/xbox-uwp/gen1recomp-${v}-xbox-uwp.zip"
[ -f "$uwp" ] || { echo "::error::$uwp not found (expected from the Xbox UWP job)"; exit 1; }
cp "$uwp" "$outdir/gen1recomp-${v}-xbox-uwp.zip"
# Anbernic handheld port (suffix names the CFW it targets, so a
# future RG35XX/other-CFW pack can ship alongside it).
rg34="dist/rg34xxsp/gen1recomp-rg34xxsp-stockos64-mod.zip"
@@ -302,8 +423,8 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
v="${{ steps.ver.outputs.version }}"
tag="${{ steps.ver.outputs.tag }}"
v="${{ needs.version.outputs.version }}"
tag="${{ needs.version.outputs.tag }}"
# Issues this release closes. Three sources, deduped by number:
# 1. GitHub's own "closing issues" links on every PR whose
@@ -394,6 +515,7 @@ jobs:
"dist/release/gen1recomp-${v}-android.apk"
"dist/release/gen1recomp-${v}-ios.ipa"
"dist/release/gen1recomp-${v}-switch.zip"
"dist/release/gen1recomp-${v}-xbox-uwp.zip"
"dist/release/gen1recomp-${v}-rg34xxsp-stockos64-mod.zip"
"dist/release/gen1recomp-${v}.love"
"dist/release/sha256sums.txt"
@@ -411,7 +533,7 @@ jobs:
if: github.repository == 'bryanthaboi/gen1recomp'
run: |
set -euo pipefail
v="${{ steps.ver.outputs.version }}"
v="${{ needs.version.outputs.version }}"
ipa="dist/release/gen1recomp-${v}-ios.ipa"
app_repo="mobile/ios/app-repo.json"
[ -f "$ipa" ] || { echo "::error::$ipa not found"; exit 1; }
+61 -11
View File
@@ -19,7 +19,8 @@ The tested toolchain is:
- C++ Universal Windows Platform tools
- Windows 11 SDK `10.0.26100.0`
- CMake 3.24 or newer
- Git
- Git for Windows
- Info-ZIP `zip` and `unzip`
Use Visual Studio Installer to add **Universal Windows Platform development**, the v143 C++ tools, CMake tools for Windows, and Windows SDK `10.0.26100.0`.
@@ -30,10 +31,10 @@ build.
## Rebuild the Dependencies
Run the dependency rebuild from `ports/uwp`:
Run the dependency rebuild from the repository root:
```powershell
.\scripts\rebuild-dependencies.ps1
.\scripts\xbox-uwp\rebuild_dependencies.ps1
```
The script clones the pinned SDL2, LÖVE, LuaJIT, vcpkg, depot_tools, and ANGLE
@@ -46,24 +47,73 @@ The generated source checkouts are ignored by Git. A fresh ANGLE sync is about
10 GB, so allow at least 20 GB of free disk space for all sources and build
outputs. Use `-SkipAngle` to retain the existing pinned ANGLE runtime while
rebuilding SDL2, LÖVE, LuaJIT, and the vcpkg libraries. Use `-SkipPackage` when
only the dependency bundle needs to be refreshed.
only the dependency bundle needs to be refreshed. The rebuild stops if a source
checkout has local changes. Remove that generated `source` directory to restore
the pinned revision.
## Build the MSIX
Build the game package from `ports/uwp`:
Run the Xbox build from Git Bash at the repository root:
```powershell
Set-Location "ports\uwp"
cmake --preset uwp-release
cmake --build --preset uwp-release
```bash
scripts/build_xbox_uwp.sh --release --version 1.2.3
```
The build creates `gen1recomp.love`, links the UWP host, and stages LÖVE, LuaJIT, SDL2, ANGLE, and the vcpkg runtime DLLs.
The build uses `scripts/pack_love.sh` to create and verify the same ROM-free
`game.love` payload used by the other release targets. It then links the UWP
host and stages LÖVE, LuaJIT, SDL2, ANGLE, and the vcpkg runtime DLLs.
Use `--relwithdebinfo` for a package with symbols. To package a `.love` produced
by another build or downloaded from CI, pass `--game-love path/to/game.love`.
The upstream `X.Y.Z` release becomes `X.Y.Z.0` in the generated MSIX manifest.
Neither the manifest template nor `src/core/Version.lua` is edited in place.
The manifest publisher must match the signing certificate subject. Pass it
when preparing a signed package:
```bash
scripts/build_xbox_uwp.sh --release --version 1.2.3 \
--publisher "CN=Gen1Recomp"
```
The normal build is unsigned. Release CI supplies the private PFX and password
from `XBOX_UWP_SIGNING_CERTIFICATE` and `XBOX_UWP_SIGNING_PASSWORD`; neither may
be committed. The public certificate is safe to include with the release.
Run the offline packaging checks from Git Bash:
```bash
bash scripts/xbox-uwp/selftest_build_xbox_uwp.sh
```
## Build Output
The Release package lands under:
Visual Studio package output lands under:
```text
ports\uwp\build\release\AppPackages\Gen1RecompUWP
```
The build also stages the distributable archive and checksum under:
```text
dist\xbox-uwp\gen1recomp-X.Y.Z-xbox-uwp.zip
dist\xbox-uwp\gen1recomp-X.Y.Z-xbox-uwp.zip.sha256
```
The archive contains the MSIX, framework dependencies, build provenance and,
for a signed release, the public certificate. The third-party notices are
packaged inside the MSIX. Install the MSIX and dependency packages through
Xbox Device Portal.
## Runtime Data
The package contains no ROM, generated cache, save or mod data. The Xbox file
picker copies user-selected files into LocalState and the launcher imports them
from there. Saves, ROM cache and installed mods remain under the LÖVE save
directory in LocalState.
LuaJIT requires the `codeGeneration` capability. `removableStorage` exposes
external media to the Xbox picker. The network capabilities support relay play
and direct hosting. The package does not request full trust or broad filesystem
access.
+57 -9
View File
@@ -12,6 +12,31 @@ set(SDL2_ROOT "${THIRD_PARTY_ROOT}/sdl2")
set(ANGLE_ROOT "${THIRD_PARTY_ROOT}/angle")
set(RUNTIME_ROOT "${THIRD_PARTY_ROOT}/runtime")
set(GEN1RECOMP_VERSION "0.0.0" CACHE STRING "Gen1Recomp release version")
if(NOT GEN1RECOMP_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+$")
message(FATAL_ERROR "GEN1RECOMP_VERSION must use X.Y.Z format.")
endif()
string(REPLACE "." ";" VERSION_PARTS "${GEN1RECOMP_VERSION}")
foreach(part IN LISTS VERSION_PARTS)
if(part GREATER 65535)
message(FATAL_ERROR "MSIX version components cannot exceed 65535.")
endif()
endforeach()
set(GEN1RECOMP_UWP_PUBLISHER "CN=Gen1Recomp" CACHE STRING
"Publisher subject from the MSIX signing certificate")
set(UWP_PUBLISHER_XML "${GEN1RECOMP_UWP_PUBLISHER}")
string(REPLACE "&" "&" UWP_PUBLISHER_XML "${UWP_PUBLISHER_XML}")
string(REPLACE "\"" """ UWP_PUBLISHER_XML "${UWP_PUBLISHER_XML}")
string(REPLACE "<" "&lt;" UWP_PUBLISHER_XML "${UWP_PUBLISHER_XML}")
string(REPLACE ">" "&gt;" UWP_PUBLISHER_XML "${UWP_PUBLISHER_XML}")
set(UWP_PACKAGE_VERSION "${GEN1RECOMP_VERSION}.0")
set(PACKAGE_MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/Package.appxmanifest")
configure_file(
"${CMAKE_CURRENT_LIST_DIR}/Package.appxmanifest.in"
"${PACKAGE_MANIFEST}"
@ONLY
)
set(REQUIRED_FILES
"${THIRD_PARTY_ROOT}/manifest.json"
"${LOVE_ROOT}/lib/lovestatic.lib"
@@ -32,19 +57,28 @@ foreach(path IN LISTS REQUIRED_FILES)
endif()
endforeach()
set(GEN1RECOMP_LOVE "${GAME_ROOT}/.bazinga/work/game.love" CACHE FILEPATH
"Path to the game.love payload produced by scripts/pack_love.sh")
if(NOT EXISTS "${GEN1RECOMP_LOVE}")
message(FATAL_ERROR
"Missing game.love payload: ${GEN1RECOMP_LOVE}\n"
"Build it with scripts/build_xbox_uwp.sh or scripts/pack_love.sh.")
endif()
set(GAME_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/gen1recomp.love")
set_source_files_properties("${GAME_ARCHIVE}" PROPERTIES GENERATED TRUE)
add_custom_target(gen1recomp_love ALL
COMMAND powershell -NoProfile -ExecutionPolicy Bypass -File
"${CMAKE_CURRENT_LIST_DIR}/scripts/package-game.ps1"
-SourceRoot "${GAME_ROOT}" -Output "${GAME_ARCHIVE}"
BYPRODUCTS "${GAME_ARCHIVE}"
add_custom_command(
OUTPUT "${GAME_ARCHIVE}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${GEN1RECOMP_LOVE}" "${GAME_ARCHIVE}"
DEPENDS "${GEN1RECOMP_LOVE}"
VERBATIM
)
add_custom_target(gen1recomp_love ALL DEPENDS "${GAME_ARCHIVE}")
set_source_files_properties("${GAME_ARCHIVE}" PROPERTIES GENERATED TRUE)
add_custom_target(verify_uwp_dependencies
COMMAND powershell -NoProfile -ExecutionPolicy Bypass -File
"${CMAKE_CURRENT_LIST_DIR}/scripts/verify-dependencies.ps1"
"${GAME_ROOT}/scripts/xbox-uwp/verify_dependencies.ps1"
VERBATIM
)
@@ -53,6 +87,7 @@ add_dependencies(${PROJECT_NAME} gen1recomp_love verify_uwp_dependencies)
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED YES
VS_GLOBAL_DefaultLanguage "en-US"
VS_SDK_REFERENCES "Microsoft.VCLibs, Version=14.0"
)
target_include_directories(${PROJECT_NAME} PRIVATE "${SDL2_ROOT}/include/SDL2")
@@ -65,7 +100,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
)
set(PACKAGE_ROOT_FILES
"${CMAKE_CURRENT_LIST_DIR}/Package.appxmanifest"
"${PACKAGE_MANIFEST}"
"${GAME_ARCHIVE}"
"${LOVE_ROOT}/bin/love.dll"
"${LOVE_ROOT}/bin/lua51.dll"
@@ -74,6 +109,7 @@ set(PACKAGE_ROOT_FILES
"${ANGLE_ROOT}/bin/libGLESv2.dll"
"${ANGLE_ROOT}/bin/d3dcompiler_47.dll"
)
set_source_files_properties("${PACKAGE_MANIFEST}" PROPERTIES GENERATED TRUE)
set(RUNTIME_NAMES
brotlicommon.dll brotlidec.dll bz2.dll fmt.dll freetype.dll libpng16.dll
@@ -98,4 +134,16 @@ set_source_files_properties(${PACKAGE_ASSETS} PROPERTIES
VS_DEPLOYMENT_CONTENT TRUE
VS_DEPLOYMENT_LOCATION "Assets"
)
target_sources(${PROJECT_NAME} PRIVATE ${PACKAGE_ROOT_FILES} ${PACKAGE_ASSETS})
file(GLOB PACKAGE_LICENSES CONFIGURE_DEPENDS "${THIRD_PARTY_ROOT}/licenses/*.txt")
set_source_files_properties(${PACKAGE_LICENSES} PROPERTIES
VS_TOOL_OVERRIDE "Content"
VS_COPY_TO_OUT_DIR Always
VS_DEPLOYMENT_CONTENT TRUE
VS_DEPLOYMENT_LOCATION "licenses"
)
target_sources(${PROJECT_NAME} PRIVATE
${PACKAGE_ROOT_FILES}
${PACKAGE_ASSETS}
${PACKAGE_LICENSES}
)
@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp rescap">
<Identity Name="Gen1RecompUWP" Publisher="CN=Caorthann" Version="0.3.0.0" />
IgnorableNamespaces="uap mp">
<Identity Name="Gen1RecompUWP" Publisher="@UWP_PUBLISHER_XML@" Version="@UWP_PACKAGE_VERSION@" />
<mp:PhoneIdentity PhoneProductId="5074018d-a46b-4dd3-b7fa-93a1e39858ad" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>Gen1Recomp</DisplayName>
@@ -37,10 +36,8 @@
<Capabilities>
<Capability Name="internetClient" />
<Capability Name="internetClientServer" />
<Capability Name="privateNetworkClientServer" />
<Capability Name="codeGeneration" />
<uap:Capability Name="removableStorage" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="broadFileSystemAccess" />
<rescap:Capability Name="expandedResources" />
</Capabilities>
</Package>
-1
View File
@@ -26,6 +26,5 @@ int runLove(int, char **)
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
SDL_SetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON, "1");
OutputDebugStringA("Gen1Recomp UWP startup\n");
return SDL_WinRTRunApp(runLove, nullptr);
}
-49
View File
@@ -1,49 +0,0 @@
param(
[Parameter(Mandatory = $true)][string]$SourceRoot,
[Parameter(Mandatory = $true)][string]$Output
)
$ErrorActionPreference = 'Stop'
$source = (Resolve-Path -LiteralPath $SourceRoot).Path
$required = @('main.lua', 'conf.lua', 'tools/rom_manifest.json')
$allowedRoots = @('assets/', 'data/', 'mods/', 'src/', 'tools/rom_manifest')
$forbidden = '(?i)(^|/)(assets/generated|data/generated|build|dist|ports|mobile|tests?)(/|$)|\.(gb|gbc|sav|srm)$'
$tracked = & git -C $source ls-files
if ($LASTEXITCODE -ne 0) { throw 'git ls-files failed' }
$entries = $tracked |
ForEach-Object { $_.Replace('\', '/') } |
Where-Object {
$path = $_
(($required -contains $path) -or ($allowedRoots | Where-Object { $path.StartsWith($_) })) -and
$path -notmatch $forbidden
} |
Sort-Object -Unique
foreach ($path in $required) {
if ($entries -notcontains $path) { throw "Required game file is missing from archive input: $path" }
}
$parent = Split-Path -Parent $Output
New-Item -ItemType Directory -Force -Path $parent | Out-Null
if (Test-Path -LiteralPath $Output) { Remove-Item -LiteralPath $Output -Force }
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
$archive = [System.IO.Compression.ZipFile]::Open($Output, 'Create')
try {
foreach ($relative in $entries) {
$full = Join-Path $source $relative
if (-not (Test-Path -LiteralPath $full -PathType Leaf)) { throw "Tracked file is missing: $relative" }
$entry = $archive.CreateEntry($relative, [System.IO.Compression.CompressionLevel]::Optimal)
$entry.LastWriteTime = [DateTimeOffset]'2000-01-01T00:00:00Z'
$input = [System.IO.File]::OpenRead($full)
$outputStream = $entry.Open()
try { $input.CopyTo($outputStream) } finally { $outputStream.Dispose(); $input.Dispose() }
}
} finally {
$archive.Dispose()
}
Write-Host "Created $Output with $($entries.Count) tracked, ROM-free entries."
-34
View File
@@ -1,34 +0,0 @@
param(
[string]$Manifest = (Join-Path $PSScriptRoot "..\third_party\manifest.json")
)
$ErrorActionPreference = "Stop"
$manifestPath = (Resolve-Path $Manifest).Path
$thirdPartyRoot = Split-Path -Parent $manifestPath
$metadata = Get-Content -Raw $manifestPath | ConvertFrom-Json
foreach ($file in $metadata.files) {
$path = Join-Path $thirdPartyRoot $file.path
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
throw "Missing UWP dependency: $($file.path)"
}
$stream = [System.IO.File]::OpenRead($path)
try {
$sha256 = [System.Security.Cryptography.SHA256]::Create()
try {
$hash = $sha256.ComputeHash($stream)
$actual = [System.BitConverter]::ToString($hash).Replace("-", "")
} finally {
$sha256.Dispose()
}
} finally {
$stream.Dispose()
}
if ($actual -ne $file.sha256) {
throw "UWP dependency hash mismatch: $($file.path)"
}
}
Write-Host "Verified $($metadata.files.Count) UWP dependency files."
+1 -1
View File
@@ -8,4 +8,4 @@ This directory contains the complete x64 UWP Release dependency bundle used by t
- `runtime` contains the codec, font, compression, and audio DLLs used by LÖVE.
- `licenses` contains the corresponding third party notices.
`manifest.json` pins the source revisions and SHA-256 hashes. Run `../scripts/verify-dependencies.ps1` after updating any dependency.
`manifest.json` pins the source revisions and SHA-256 hashes. Run `scripts/xbox-uwp/verify_dependencies.ps1` from the repository root after updating any dependency.
+302 -302
View File
@@ -90,88 +90,296 @@
"sha256": "A05F99734F7C4822FEFC12B367AF21FD0976ED6608752FB1E1E80B6ECE7ECBBB"
},
{
"path": "sdl2/include/SDL2/SDL_scancode.h",
"sha256": "EB14F3CEDDE58358F6456D185F473D7551E8234DE260151AD0319861FF1444C2"
"path": "angle/bin/libEGL.dll",
"sha256": "B0E0C6BAC9D9F0F084DC8F56083A2EEFFB866C0629A64D52B5E33616B4F90CBE"
},
{
"path": "sdl2/include/SDL2/SDL_rwops.h",
"sha256": "10DA91C08E96E5FCA452E06E11029908A6F237356E4DB11AF1AD13FFA2E57A47"
"path": "angle/bin/libGLESv2.dll",
"sha256": "6DE6940EDB728396CBA6F3C0D79172A8EFD33E37671A13B1721C652EECEBF4C4"
},
{
"path": "sdl2/include/SDL2/SDL_revision.h",
"sha256": "C28DA498955466CEF76278184636A3297F103AE34D9B605394BA6FE1B75F1850"
"path": "love/bin/love.dll",
"sha256": "7B1BE4699AC950173474BB0C03B5DD52E1202ABA6F60C29E294957057F587692"
},
{
"path": "sdl2/include/SDL2/SDL_render.h",
"sha256": "A0CF0DB1A13D0DD0D8BFDC01FFB371E2B19BE36326F85058200AC9481876C7F0"
"path": "love/bin/lua51.dll",
"sha256": "08380FB9A7C8A8A85D3425C1FD6F1CB826D980FF31925453E353227E9A23BC70"
},
{
"path": "sdl2/include/SDL2/SDL_rect.h",
"sha256": "01DB368D4B7736E2358CD29EEC0D187D964CFD6182CFFAB57A938ADF73B6A418"
"path": "love/lib/liblove.lib",
"sha256": "C93A358D5EAE8BE3D74DDFDFA767657E96E95E0151F843FEB4E587CF2D89320A"
},
{
"path": "sdl2/include/SDL2/SDL_quit.h",
"sha256": "9C902ABAEA7560F98FC546BD35A04629A205D047DF5433FC30B0C1D81AF58B21"
"path": "love/lib/lovestatic.lib",
"sha256": "15FB3A9CB3C3CDAB8B33DE5B1D1F8D8FF6CE9719E9AA7BC2CF3D7B51CDCE0C98"
},
{
"path": "sdl2/include/SDL2/SDL_power.h",
"sha256": "FBBDF3FF13B21095623EDFC5659C1B76C6DBB1364A4DD14D8F9E5CF329048784"
"path": "love/lib/lua51.lib",
"sha256": "A4F4F0942A432B88A3541A185B3D3D5B4D58413B3CEEE10A2E48CAF9D8439759"
},
{
"path": "sdl2/include/SDL2/SDL_platform.h",
"sha256": "9CE62823791D7A16B9AD17AD11F4DE8DCBCDE7918F67BF6D1DD4FC625B69E50C"
"path": "runtime/bin/brotlicommon.dll",
"sha256": "6A1D267564FE5BE6D601C1F5301F45DD0D0CCBDA2AE8975CACA4424A9FD452AF"
},
{
"path": "sdl2/include/SDL2/SDL_pixels.h",
"sha256": "FEE61AEE337A3823E832F5C26B3000315D6EB95DA91BA20D4FB0B5BAC9D4967A"
"path": "runtime/bin/brotlidec.dll",
"sha256": "C12C983AEE4E7EF966982AD11D71B32456CB445B18B8E11D9A35E781619085E2"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2.h",
"sha256": "73A3B042F7B3D296904BFF91268730D5180638F4EC1836D57258FE53EE60DF8B"
"path": "runtime/bin/bz2.dll",
"sha256": "28ADC0239EAF51D13F8C7075B8514420CAE92EFF14471EC6F5B56A11D9345F00"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_khrplatform.h",
"sha256": "7B1E01AAA7AD8F6FC34B5C7BDF79EBF5189BB09E2C4D2E79FC5D350623D11E83"
"path": "runtime/bin/fmt.dll",
"sha256": "B4ED319D0733EA619D11770558957AFBDF99021D86A4ED068628AE34426C6090"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_gl2platform.h",
"sha256": "4779BE999ACD1904458238F09C86983B7960AC40E612E05DB2DB97DB615F1E0F"
"path": "runtime/bin/freetype.dll",
"sha256": "3727B17849902FE12DED3C76BD71D2907C523CF67D1A7CB516025522E260F9D4"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_gl2ext.h",
"sha256": "4FC5B0034DCDE9C125922E3E70D01489A6B335076856EE660294E1A6305A3719"
"path": "runtime/bin/libpng16.dll",
"sha256": "9B3B823A59ABCB4BA43D1E6DB4C35855AE66384106E32FD5F9D486A7DECB81AF"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_gl2.h",
"sha256": "D6EC44B1D73F3AFCE3A20AC6976DB7FB3DAC656C5190F0B563E4CE90D79A15AA"
"path": "runtime/bin/ogg.dll",
"sha256": "283B0890599450AE4BE486C07241ECCC7B14B480465AF7F8D9F2A84528064A65"
},
{
"path": "sdl2/include/SDL2/SDL_opengles.h",
"sha256": "0542791816FCDD84B74D98347AC1B00A97BC6C2CDF31334CD9083789FFB6594A"
"path": "runtime/bin/OpenAL32.dll",
"sha256": "D37D04CDD1EEE2005ACF64B558DFB16F0A0D83991F3B2A75E5C69FF314054F8B"
},
{
"path": "sdl2/include/SDL2/SDL_opengl.h",
"sha256": "C4D2857E757B2B2A83D7531CBEDA19C383AD6D16648AB9B7544FC0A74EB2FF13"
"path": "runtime/bin/theora.dll",
"sha256": "C90101C9C169B68F4FA155E63C71F28B271BBB68649085C8ACEFB26816663857"
},
{
"path": "sdl2/include/SDL2/SDL_opengl_glext.h",
"sha256": "1ABB28891C9B0661B6FF3749DE2671DA5FE12BEB5BCB1833B2D6BDF5C89ECDF8"
"path": "runtime/bin/theoradec.dll",
"sha256": "53A5A3A0B24F72B7D8812DE4B78FD3BB222399B9293B577A8FCF80009B72F004"
},
{
"path": "sdl2/include/SDL2/SDL_name.h",
"sha256": "FDC6C648734220285056AD8B8273511C75D5BE00D17FC1EA3EB4C06526B13FA3"
"path": "runtime/bin/vorbis.dll",
"sha256": "A4B2D0A4C032A7E60AA297ADAE134E8A2C1BE61D7EC639CAA93AF85BF7EAC2C7"
},
{
"path": "sdl2/include/SDL2/SDL_mutex.h",
"sha256": "C5EF9A8AEB056422EF878672770E1F60AE965933693DF6D8EBD53D0E514A1794"
"path": "runtime/bin/vorbisfile.dll",
"sha256": "0BFFA35539F0A8233A8EFF4C6680F8A7CF3B9DBE3B437A3F94D5301B66A2F134"
},
{
"path": "runtime/bin/z.dll",
"sha256": "8B86502ADC15A13C0E136FB9D63AA6583C59AD93EC608A9A7C901757354744C3"
},
{
"path": "sdl2/bin/SDL2.dll",
"sha256": "B02D13F77221A335AB9F21304F2B4E003FE59C6DF10F21BA6D49023016D35CA8"
},
{
"path": "sdl2/include/SDL2/begin_code.h",
"sha256": "9803DAB29FB4522CE3500AB789260E9622DF6307CE90F92AD20C1808E19C4E7B"
},
{
"path": "sdl2/include/SDL2/close_code.h",
"sha256": "4599E9CEDBA7451FF07A6306F0B7531BEED05B1C5A65B1A2613D1B771BE43FDA"
},
{
"path": "sdl2/include/SDL2/SDL_assert.h",
"sha256": "32FC342E0A5F3A55EA1CE2A5D9195E77215EDCB6F4595C0DC3674DCCA1CC81D8"
},
{
"path": "sdl2/include/SDL2/SDL_atomic.h",
"sha256": "C561CE8F94DE18CCB4F708BDA45880BA6D3C9F052E166BEB5DADC5544F35221E"
},
{
"path": "sdl2/include/SDL2/SDL_audio.h",
"sha256": "047AFC29591AC43A90F06169F67EE7D99A6256C6BBE5EFE5DE79A52565BB6853"
},
{
"path": "sdl2/include/SDL2/SDL_bits.h",
"sha256": "63D22D1C8FE0D83BBA5A49ABA9BB700592F14462F7F7BF87E5838064047E3FA9"
},
{
"path": "sdl2/include/SDL2/SDL_blendmode.h",
"sha256": "1985F81B886D9BC681821AF4F23D28E6E51BF51F21E5EF28CCC13BC8C7CDFBAE"
},
{
"path": "sdl2/include/SDL2/SDL_clipboard.h",
"sha256": "3E8C73FB9B3CA5A544B70B66B683B78DB53E1A187E066912A068C0ED7BB3E8CE"
},
{
"path": "sdl2/include/SDL2/SDL_config.h",
"sha256": "108A953419E1638AE2FF09148E2927C3AC4FF3E15B72A56FF41B542F356021BA"
},
{
"path": "sdl2/include/SDL2/SDL_copying.h",
"sha256": "3F90BE470C18F99F4AEF39444E9374EDBA166CFEB1B90F99F35286CC33924642"
},
{
"path": "sdl2/include/SDL2/SDL_cpuinfo.h",
"sha256": "FEE0C489ED4364C21FE0B726A47F72DF167FBCBF42CF569807B2BBF77DC30C54"
},
{
"path": "sdl2/include/SDL2/SDL_egl.h",
"sha256": "72C119F4F7EC30F13B03D3E33D2266CB012EE103F0AD1973786D84D538A0B53D"
},
{
"path": "sdl2/include/SDL2/SDL_endian.h",
"sha256": "7907CB3AB7B8D7BC99274F5AEF5294BEF215B01EA49D97226CBE6E911DE557D5"
},
{
"path": "sdl2/include/SDL2/SDL_error.h",
"sha256": "0931656A5825E5F1F319F2CD3F573FC527393BB02FA7A1ED3F7FAE6C790328BE"
},
{
"path": "sdl2/include/SDL2/SDL_events.h",
"sha256": "CEB7BC717342E652E2C432FD1DD08A5508575CEA6BD8615FB4DDEA63C071DDC4"
},
{
"path": "sdl2/include/SDL2/SDL_filesystem.h",
"sha256": "DCFAA010C73150E7B0D56F50F5ADB3FC2E35621091A55BC5436B2FB85FE71675"
},
{
"path": "sdl2/include/SDL2/SDL_gamecontroller.h",
"sha256": "C77C1D8287EE441843B9D8BE87B71252BDB1CE76B7BFC4FCFF46889AD8E9CFEC"
},
{
"path": "sdl2/include/SDL2/SDL_gesture.h",
"sha256": "A5A8F8BB8EFB26860FAA9694189AAF76DF1CDB7755CCD30A8599B46B237A5D82"
},
{
"path": "sdl2/include/SDL2/SDL_guid.h",
"sha256": "DA8FEF1D047B31E55D1B167DE301A806481B6948E7C2497779FD71934C45D5DB"
},
{
"path": "sdl2/include/SDL2/SDL_haptic.h",
"sha256": "4267B6F039BEA7AD0F5CB37C37D63D0704AF84F73A36D2680684FF302F49F153"
},
{
"path": "sdl2/include/SDL2/SDL_hidapi.h",
"sha256": "489A83D1073E528F82E821C23C515AF8B5A59357EC5AB132C854BB588648F59F"
},
{
"path": "sdl2/include/SDL2/SDL_hints.h",
"sha256": "96C1056E0734F019B1DAFED5129D4A9D36253559ED8C7577A23C188BB75A48C1"
},
{
"path": "sdl2/include/SDL2/SDL_joystick.h",
"sha256": "A39FC5DA97EDC94EABFF8616A413CF850EFB35D1DAF437A8CC16CAA837766482"
},
{
"path": "sdl2/include/SDL2/SDL_keyboard.h",
"sha256": "F68DFA4F784F0B22949A8DF94F3C3653EA01A03AE02297D17579EB9E7EA94054"
},
{
"path": "sdl2/include/SDL2/SDL_keycode.h",
"sha256": "291C769A05BC3E1EAD011DB3E07CB52415E1AA306F484904D203E94CBB3186CD"
},
{
"path": "sdl2/include/SDL2/SDL_loadso.h",
"sha256": "8D3653B7B774B406A289519C74AE695EB5B52D71060712A88FCE4C72D82B1BD3"
},
{
"path": "sdl2/include/SDL2/SDL_locale.h",
"sha256": "C4A663CE8EA4CA22F961796CAE644A04FC521FA2D0681333F7DA8A581909560C"
},
{
"path": "sdl2/include/SDL2/SDL_log.h",
"sha256": "3342CB31280C2DBF0E5809B03E5499F0CF5EDF193EFA5E3C5B17814526A92033"
},
{
"path": "sdl2/include/SDL2/SDL_main.h",
"sha256": "622FFCD0E7FE0C755A987C5EB9DAD6B3672774026B8250B66AD3C40D3A4DDA9A"
},
{
"path": "sdl2/include/SDL2/SDL_messagebox.h",
"sha256": "65DF549CAB0A515145AE55325C447159AE1D60171331A7508EAC06034D25C972"
},
{
"path": "sdl2/include/SDL2/SDL_metal.h",
"sha256": "1F3D0251522B735B0E37677EB1A0594440599FBBB2AF86BBB508606CCA001A06"
},
{
"path": "sdl2/include/SDL2/SDL_misc.h",
"sha256": "5D5E4B42481A5EF44EC9D66159E88426BE5632262731A3C3B223277771D30006"
},
{
"path": "sdl2/include/SDL2/SDL_mouse.h",
"sha256": "66B5353387D011A54B232931E86121CB5551E251B9491B9ED15AFE293D5856FF"
},
{
"path": "sdl2/include/SDL2/SDL_misc.h",
"sha256": "5D5E4B42481A5EF44EC9D66159E88426BE5632262731A3C3B223277771D30006"
"path": "sdl2/include/SDL2/SDL_mutex.h",
"sha256": "C5EF9A8AEB056422EF878672770E1F60AE965933693DF6D8EBD53D0E514A1794"
},
{
"path": "sdl2/include/SDL2/SDL_name.h",
"sha256": "FDC6C648734220285056AD8B8273511C75D5BE00D17FC1EA3EB4C06526B13FA3"
},
{
"path": "sdl2/include/SDL2/SDL_opengl_glext.h",
"sha256": "1ABB28891C9B0661B6FF3749DE2671DA5FE12BEB5BCB1833B2D6BDF5C89ECDF8"
},
{
"path": "sdl2/include/SDL2/SDL_opengl.h",
"sha256": "C4D2857E757B2B2A83D7531CBEDA19C383AD6D16648AB9B7544FC0A74EB2FF13"
},
{
"path": "sdl2/include/SDL2/SDL_opengles.h",
"sha256": "0542791816FCDD84B74D98347AC1B00A97BC6C2CDF31334CD9083789FFB6594A"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_gl2.h",
"sha256": "D6EC44B1D73F3AFCE3A20AC6976DB7FB3DAC656C5190F0B563E4CE90D79A15AA"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_gl2ext.h",
"sha256": "4FC5B0034DCDE9C125922E3E70D01489A6B335076856EE660294E1A6305A3719"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_gl2platform.h",
"sha256": "4779BE999ACD1904458238F09C86983B7960AC40E612E05DB2DB97DB615F1E0F"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2_khrplatform.h",
"sha256": "7B1E01AAA7AD8F6FC34B5C7BDF79EBF5189BB09E2C4D2E79FC5D350623D11E83"
},
{
"path": "sdl2/include/SDL2/SDL_opengles2.h",
"sha256": "73A3B042F7B3D296904BFF91268730D5180638F4EC1836D57258FE53EE60DF8B"
},
{
"path": "sdl2/include/SDL2/SDL_pixels.h",
"sha256": "FEE61AEE337A3823E832F5C26B3000315D6EB95DA91BA20D4FB0B5BAC9D4967A"
},
{
"path": "sdl2/include/SDL2/SDL_platform.h",
"sha256": "9CE62823791D7A16B9AD17AD11F4DE8DCBCDE7918F67BF6D1DD4FC625B69E50C"
},
{
"path": "sdl2/include/SDL2/SDL_power.h",
"sha256": "FBBDF3FF13B21095623EDFC5659C1B76C6DBB1364A4DD14D8F9E5CF329048784"
},
{
"path": "sdl2/include/SDL2/SDL_quit.h",
"sha256": "9C902ABAEA7560F98FC546BD35A04629A205D047DF5433FC30B0C1D81AF58B21"
},
{
"path": "sdl2/include/SDL2/SDL_rect.h",
"sha256": "01DB368D4B7736E2358CD29EEC0D187D964CFD6182CFFAB57A938ADF73B6A418"
},
{
"path": "sdl2/include/SDL2/SDL_render.h",
"sha256": "A0CF0DB1A13D0DD0D8BFDC01FFB371E2B19BE36326F85058200AC9481876C7F0"
},
{
"path": "sdl2/include/SDL2/SDL_revision.h",
"sha256": "EF28EADA36B000C710B033317A37677B5484A4DE224547CB7293A77FA0C97195"
},
{
"path": "sdl2/include/SDL2/SDL_rwops.h",
"sha256": "10DA91C08E96E5FCA452E06E11029908A6F237356E4DB11AF1AD13FFA2E57A47"
},
{
"path": "sdl2/include/SDL2/SDL_scancode.h",
"sha256": "EB14F3CEDDE58358F6456D185F473D7551E8234DE260151AD0319861FF1444C2"
},
{
"path": "sdl2/include/SDL2/SDL_sensor.h",
@@ -190,305 +398,97 @@
"sha256": "92299233370D645F78D9C655CE7F102C16F9D4DDDE28A59BD82A962C49B51D94"
},
{
"path": "sdl2/include/SDL2/SDL_vulkan.h",
"sha256": "98ED6B3D354191019AE208FC861799237BA8FFB11FA6BD41B3569E6CE05555B8"
},
{
"path": "sdl2/include/SDL2/SDL_video.h",
"sha256": "82AB63FF37834CD4BFCEE490B8E37FB892BBB0B31A1A7913EC13C329271CA5FF"
},
{
"path": "sdl2/include/SDL2/SDL_version.h",
"sha256": "EE97570D0D6507B4687076336C07FD4A7FA1F5E7986C9B61893A279950FEBCE8"
},
{
"path": "sdl2/include/SDL2/SDL_types.h",
"sha256": "ED0C92BED5EEC2648F744E8451F3AC5140C1EF11510175FA1B726273DBDED9ED"
},
{
"path": "sdl2/include/SDL2/SDL_touch.h",
"sha256": "4E5D7A083BBF5237DAF5CCF06FAED3FAE81B1CAA693E27841EBF4EC9BF8FF769"
},
{
"path": "sdl2/include/SDL2/SDL_timer.h",
"sha256": "D0497AD3D75701613A227134D63FDCBC62ED72F645153D52753E386EE4B498C7"
},
{
"path": "sdl2/include/SDL2/SDL_thread.h",
"sha256": "0E546047DD407CA0E1D2D686CF2650AC77A987047184E3645F6BA2EC958DDC5C"
},
{
"path": "sdl2/include/SDL2/SDL_test.h",
"sha256": "55E453735FB6A14CF350F663E8C7BC9AA273DB95BB31BCF3ABBFB5B3A91A414E"
},
{
"path": "sdl2/include/SDL2/SDL_test_random.h",
"sha256": "1D8C7987AE39B74D83F40FB54394FD32C61037716C77EBCAF7CE87788934C035"
},
{
"path": "sdl2/include/SDL2/SDL_test_memory.h",
"sha256": "556F676637FBB1A85F1998545C59ADDCA358B8B95C71812337B370184F27483F"
},
{
"path": "sdl2/include/SDL2/SDL_metal.h",
"sha256": "1F3D0251522B735B0E37677EB1A0594440599FBBB2AF86BBB508606CCA001A06"
},
{
"path": "sdl2/include/SDL2/SDL_test_md5.h",
"sha256": "BE73865B584B5EB207CAB3D8DCFF6AD057286B75053B547B0238DF275E282491"
},
{
"path": "sdl2/include/SDL2/SDL_test_images.h",
"sha256": "35E7AD856A201FBAAFE7EC3FC48DB47FB5D9452C292267F8936AEC5E5C77B81D"
},
{
"path": "sdl2/include/SDL2/SDL_test_harness.h",
"sha256": "30B9CCB36E07FF0442429A27540F6A796AEE073355B538BD50EF0B98CC47982E"
},
{
"path": "sdl2/include/SDL2/SDL_test_fuzzer.h",
"sha256": "494E0E49882A9C2745D07DA7B04761D8D992DD90A7A29DD34B605051ED8DCEE5"
},
{
"path": "sdl2/include/SDL2/SDL_test_font.h",
"sha256": "B0B7E6AC8BCF7B9E5BF28695B05D3A084CD530C90322CBC9A0B198114B174231"
},
{
"path": "sdl2/include/SDL2/SDL_test_crc32.h",
"sha256": "74CB4C2F7F7130D6048A2C716260D6403620F0E358FA928136ED3560BF71A378"
},
{
"path": "sdl2/include/SDL2/SDL_test_compare.h",
"sha256": "713AF284D8520E910D94090396BFD2DB2B2292096EDD93E4D60AA69163B9C510"
},
{
"path": "sdl2/include/SDL2/SDL_test_common.h",
"sha256": "B619CC3020FFDC8F8A12F5D9D4AF8B83E9B7C6C3BFC05C6502933C4B3F0103DE"
},
{
"path": "sdl2/include/SDL2/SDL_test_assert.h",
"sha256": "FE826FEB054929284764718C67AE95B920729AE1336FFEEC88A23D611E6498F0"
"path": "sdl2/include/SDL2/SDL_system.h",
"sha256": "FFC5F3662A85F795C0B2E2B87B9FBF493BCEEDA4AACF7721A68225C5E318CA67"
},
{
"path": "sdl2/include/SDL2/SDL_syswm.h",
"sha256": "34FEC1A5F1089BD395EE11C3A25AD0FC10E7ABC56D4A77CC6F17EB9E4E8A9607"
},
{
"path": "sdl2/include/SDL2/SDL_system.h",
"sha256": "FFC5F3662A85F795C0B2E2B87B9FBF493BCEEDA4AACF7721A68225C5E318CA67"
"path": "sdl2/include/SDL2/SDL_test_assert.h",
"sha256": "FE826FEB054929284764718C67AE95B920729AE1336FFEEC88A23D611E6498F0"
},
{
"path": "sdl2/include/SDL2/SDL_test_common.h",
"sha256": "B619CC3020FFDC8F8A12F5D9D4AF8B83E9B7C6C3BFC05C6502933C4B3F0103DE"
},
{
"path": "sdl2/include/SDL2/SDL_test_compare.h",
"sha256": "713AF284D8520E910D94090396BFD2DB2B2292096EDD93E4D60AA69163B9C510"
},
{
"path": "sdl2/include/SDL2/SDL_test_crc32.h",
"sha256": "74CB4C2F7F7130D6048A2C716260D6403620F0E358FA928136ED3560BF71A378"
},
{
"path": "sdl2/include/SDL2/SDL_test_font.h",
"sha256": "B0B7E6AC8BCF7B9E5BF28695B05D3A084CD530C90322CBC9A0B198114B174231"
},
{
"path": "sdl2/include/SDL2/SDL_test_fuzzer.h",
"sha256": "494E0E49882A9C2745D07DA7B04761D8D992DD90A7A29DD34B605051ED8DCEE5"
},
{
"path": "sdl2/include/SDL2/SDL_test_harness.h",
"sha256": "30B9CCB36E07FF0442429A27540F6A796AEE073355B538BD50EF0B98CC47982E"
},
{
"path": "sdl2/include/SDL2/SDL_test_images.h",
"sha256": "35E7AD856A201FBAAFE7EC3FC48DB47FB5D9452C292267F8936AEC5E5C77B81D"
},
{
"path": "sdl2/include/SDL2/SDL_test_log.h",
"sha256": "3A8736E6D757666420616F83E7929493FCBE816A0CDDF10347F3446818870BE8"
},
{
"path": "sdl2/include/SDL2/SDL_messagebox.h",
"sha256": "65DF549CAB0A515145AE55325C447159AE1D60171331A7508EAC06034D25C972"
"path": "sdl2/include/SDL2/SDL_test_md5.h",
"sha256": "BE73865B584B5EB207CAB3D8DCFF6AD057286B75053B547B0238DF275E282491"
},
{
"path": "sdl2/include/SDL2/SDL_main.h",
"sha256": "622FFCD0E7FE0C755A987C5EB9DAD6B3672774026B8250B66AD3C40D3A4DDA9A"
"path": "sdl2/include/SDL2/SDL_test_memory.h",
"sha256": "556F676637FBB1A85F1998545C59ADDCA358B8B95C71812337B370184F27483F"
},
{
"path": "sdl2/include/SDL2/SDL_log.h",
"sha256": "3342CB31280C2DBF0E5809B03E5499F0CF5EDF193EFA5E3C5B17814526A92033"
"path": "sdl2/include/SDL2/SDL_test_random.h",
"sha256": "1D8C7987AE39B74D83F40FB54394FD32C61037716C77EBCAF7CE87788934C035"
},
{
"path": "sdl2/include/SDL2/begin_code.h",
"sha256": "9803DAB29FB4522CE3500AB789260E9622DF6307CE90F92AD20C1808E19C4E7B"
"path": "sdl2/include/SDL2/SDL_test.h",
"sha256": "55E453735FB6A14CF350F663E8C7BC9AA273DB95BB31BCF3ABBFB5B3A91A414E"
},
{
"path": "sdl2/bin/SDL2.dll",
"sha256": "B02D13F77221A335AB9F21304F2B4E003FE59C6DF10F21BA6D49023016D35CA8"
"path": "sdl2/include/SDL2/SDL_thread.h",
"sha256": "0E546047DD407CA0E1D2D686CF2650AC77A987047184E3645F6BA2EC958DDC5C"
},
{
"path": "runtime/bin/z.dll",
"sha256": "8B86502ADC15A13C0E136FB9D63AA6583C59AD93EC608A9A7C901757354744C3"
"path": "sdl2/include/SDL2/SDL_timer.h",
"sha256": "D0497AD3D75701613A227134D63FDCBC62ED72F645153D52753E386EE4B498C7"
},
{
"path": "runtime/bin/vorbisfile.dll",
"sha256": "0BFFA35539F0A8233A8EFF4C6680F8A7CF3B9DBE3B437A3F94D5301B66A2F134"
"path": "sdl2/include/SDL2/SDL_touch.h",
"sha256": "4E5D7A083BBF5237DAF5CCF06FAED3FAE81B1CAA693E27841EBF4EC9BF8FF769"
},
{
"path": "runtime/bin/vorbis.dll",
"sha256": "A4B2D0A4C032A7E60AA297ADAE134E8A2C1BE61D7EC639CAA93AF85BF7EAC2C7"
"path": "sdl2/include/SDL2/SDL_types.h",
"sha256": "ED0C92BED5EEC2648F744E8451F3AC5140C1EF11510175FA1B726273DBDED9ED"
},
{
"path": "runtime/bin/theoradec.dll",
"sha256": "53A5A3A0B24F72B7D8812DE4B78FD3BB222399B9293B577A8FCF80009B72F004"
"path": "sdl2/include/SDL2/SDL_version.h",
"sha256": "EE97570D0D6507B4687076336C07FD4A7FA1F5E7986C9B61893A279950FEBCE8"
},
{
"path": "runtime/bin/theora.dll",
"sha256": "C90101C9C169B68F4FA155E63C71F28B271BBB68649085C8ACEFB26816663857"
"path": "sdl2/include/SDL2/SDL_video.h",
"sha256": "82AB63FF37834CD4BFCEE490B8E37FB892BBB0B31A1A7913EC13C329271CA5FF"
},
{
"path": "runtime/bin/OpenAL32.dll",
"sha256": "D37D04CDD1EEE2005ACF64B558DFB16F0A0D83991F3B2A75E5C69FF314054F8B"
},
{
"path": "runtime/bin/ogg.dll",
"sha256": "283B0890599450AE4BE486C07241ECCC7B14B480465AF7F8D9F2A84528064A65"
},
{
"path": "runtime/bin/libpng16.dll",
"sha256": "9B3B823A59ABCB4BA43D1E6DB4C35855AE66384106E32FD5F9D486A7DECB81AF"
},
{
"path": "sdl2/include/SDL2/close_code.h",
"sha256": "4599E9CEDBA7451FF07A6306F0B7531BEED05B1C5A65B1A2613D1B771BE43FDA"
},
{
"path": "runtime/bin/freetype.dll",
"sha256": "3727B17849902FE12DED3C76BD71D2907C523CF67D1A7CB516025522E260F9D4"
},
{
"path": "runtime/bin/bz2.dll",
"sha256": "28ADC0239EAF51D13F8C7075B8514420CAE92EFF14471EC6F5B56A11D9345F00"
},
{
"path": "runtime/bin/brotlidec.dll",
"sha256": "C12C983AEE4E7EF966982AD11D71B32456CB445B18B8E11D9A35E781619085E2"
},
{
"path": "runtime/bin/brotlicommon.dll",
"sha256": "6A1D267564FE5BE6D601C1F5301F45DD0D0CCBDA2AE8975CACA4424A9FD452AF"
},
{
"path": "love/lib/lua51.lib",
"sha256": "A4F4F0942A432B88A3541A185B3D3D5B4D58413B3CEEE10A2E48CAF9D8439759"
},
{
"path": "love/lib/lovestatic.lib",
"sha256": "15FB3A9CB3C3CDAB8B33DE5B1D1F8D8FF6CE9719E9AA7BC2CF3D7B51CDCE0C98"
},
{
"path": "love/lib/liblove.lib",
"sha256": "C93A358D5EAE8BE3D74DDFDFA767657E96E95E0151F843FEB4E587CF2D89320A"
},
{
"path": "love/bin/lua51.dll",
"sha256": "08380FB9A7C8A8A85D3425C1FD6F1CB826D980FF31925453E353227E9A23BC70"
},
{
"path": "love/bin/love.dll",
"sha256": "7B1BE4699AC950173474BB0C03B5DD52E1202ABA6F60C29E294957057F587692"
},
{
"path": "angle/bin/libGLESv2.dll",
"sha256": "6DE6940EDB728396CBA6F3C0D79172A8EFD33E37671A13B1721C652EECEBF4C4"
},
{
"path": "angle/bin/libEGL.dll",
"sha256": "B0E0C6BAC9D9F0F084DC8F56083A2EEFFB866C0629A64D52B5E33616B4F90CBE"
},
{
"path": "runtime/bin/fmt.dll",
"sha256": "B4ED319D0733EA619D11770558957AFBDF99021D86A4ED068628AE34426C6090"
"path": "sdl2/include/SDL2/SDL_vulkan.h",
"sha256": "98ED6B3D354191019AE208FC861799237BA8FFB11FA6BD41B3569E6CE05555B8"
},
{
"path": "sdl2/include/SDL2/SDL.h",
"sha256": "952E89E1DC4E0DD1A7BEA6A153DF632B8CDB6E433A9B3B0702C5FFE15B9B9360"
},
{
"path": "sdl2/include/SDL2/SDL_assert.h",
"sha256": "32FC342E0A5F3A55EA1CE2A5D9195E77215EDCB6F4595C0DC3674DCCA1CC81D8"
},
{
"path": "sdl2/include/SDL2/SDL_audio.h",
"sha256": "047AFC29591AC43A90F06169F67EE7D99A6256C6BBE5EFE5DE79A52565BB6853"
},
{
"path": "sdl2/include/SDL2/SDL_locale.h",
"sha256": "C4A663CE8EA4CA22F961796CAE644A04FC521FA2D0681333F7DA8A581909560C"
},
{
"path": "sdl2/include/SDL2/SDL_loadso.h",
"sha256": "8D3653B7B774B406A289519C74AE695EB5B52D71060712A88FCE4C72D82B1BD3"
},
{
"path": "sdl2/include/SDL2/SDL_keycode.h",
"sha256": "291C769A05BC3E1EAD011DB3E07CB52415E1AA306F484904D203E94CBB3186CD"
},
{
"path": "sdl2/include/SDL2/SDL_keyboard.h",
"sha256": "F68DFA4F784F0B22949A8DF94F3C3653EA01A03AE02297D17579EB9E7EA94054"
},
{
"path": "sdl2/include/SDL2/SDL_joystick.h",
"sha256": "A39FC5DA97EDC94EABFF8616A413CF850EFB35D1DAF437A8CC16CAA837766482"
},
{
"path": "sdl2/include/SDL2/SDL_hints.h",
"sha256": "96C1056E0734F019B1DAFED5129D4A9D36253559ED8C7577A23C188BB75A48C1"
},
{
"path": "sdl2/include/SDL2/SDL_hidapi.h",
"sha256": "489A83D1073E528F82E821C23C515AF8B5A59357EC5AB132C854BB588648F59F"
},
{
"path": "sdl2/include/SDL2/SDL_haptic.h",
"sha256": "4267B6F039BEA7AD0F5CB37C37D63D0704AF84F73A36D2680684FF302F49F153"
},
{
"path": "sdl2/include/SDL2/SDL_guid.h",
"sha256": "DA8FEF1D047B31E55D1B167DE301A806481B6948E7C2497779FD71934C45D5DB"
},
{
"path": "sdl2/include/SDL2/SDL_gesture.h",
"sha256": "A5A8F8BB8EFB26860FAA9694189AAF76DF1CDB7755CCD30A8599B46B237A5D82"
},
{
"path": "sdl2/include/SDL2/SDL_atomic.h",
"sha256": "C561CE8F94DE18CCB4F708BDA45880BA6D3C9F052E166BEB5DADC5544F35221E"
},
{
"path": "sdl2/include/SDL2/SDL_gamecontroller.h",
"sha256": "C77C1D8287EE441843B9D8BE87B71252BDB1CE76B7BFC4FCFF46889AD8E9CFEC"
},
{
"path": "sdl2/include/SDL2/SDL_events.h",
"sha256": "CEB7BC717342E652E2C432FD1DD08A5508575CEA6BD8615FB4DDEA63C071DDC4"
},
{
"path": "sdl2/include/SDL2/SDL_error.h",
"sha256": "0931656A5825E5F1F319F2CD3F573FC527393BB02FA7A1ED3F7FAE6C790328BE"
},
{
"path": "sdl2/include/SDL2/SDL_endian.h",
"sha256": "7907CB3AB7B8D7BC99274F5AEF5294BEF215B01EA49D97226CBE6E911DE557D5"
},
{
"path": "sdl2/include/SDL2/SDL_egl.h",
"sha256": "72C119F4F7EC30F13B03D3E33D2266CB012EE103F0AD1973786D84D538A0B53D"
},
{
"path": "sdl2/include/SDL2/SDL_cpuinfo.h",
"sha256": "FEE0C489ED4364C21FE0B726A47F72DF167FBCBF42CF569807B2BBF77DC30C54"
},
{
"path": "sdl2/include/SDL2/SDL_copying.h",
"sha256": "3F90BE470C18F99F4AEF39444E9374EDBA166CFEB1B90F99F35286CC33924642"
},
{
"path": "sdl2/include/SDL2/SDL_config.h",
"sha256": "1B33FCD93DEFBC0B0C396FB5BC98DE5CAD0868A347417167C0D8CA2C68A823DA"
},
{
"path": "sdl2/include/SDL2/SDL_clipboard.h",
"sha256": "3E8C73FB9B3CA5A544B70B66B683B78DB53E1A187E066912A068C0ED7BB3E8CE"
},
{
"path": "sdl2/include/SDL2/SDL_blendmode.h",
"sha256": "1985F81B886D9BC681821AF4F23D28E6E51BF51F21E5EF28CCC13BC8C7CDFBAE"
},
{
"path": "sdl2/include/SDL2/SDL_bits.h",
"sha256": "63D22D1C8FE0D83BBA5A49ABA9BB700592F14462F7F7BF87E5838064047E3FA9"
},
{
"path": "sdl2/include/SDL2/SDL_filesystem.h",
"sha256": "DCFAA010C73150E7B0D56F50F5ADB3FC2E35621091A55BC5436B2FB85FE71675"
},
{
"path": "sdl2/lib/SDL2.lib",
"sha256": "37B330EE42407B405BD2432E79CB9B9036245309B3ACC445AD70CB8E555B7288"
+1 -1
View File
@@ -6,4 +6,4 @@ The bundled x64 UWP Release binaries use SDL 2.32.10 from the official `release-
`SDL2.dll`, `SDL2.lib`, and the headers must be updated together.
`ports/uwp/scripts/build-sdl2-angle.ps1` builds the source for x64 WindowsStore with GLES enabled and desktop OpenGL and Vulkan disabled. ANGLE supplies EGL and GLES at runtime.
`scripts/xbox-uwp/build_sdl2_angle.ps1` builds the source for x64 WindowsStore with GLES enabled and desktop OpenGL and Vulkan disabled. ANGLE supplies EGL and GLES at runtime.
@@ -1,28 +1,19 @@
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 035176b..04e1701 100644
index 36e521e..4d1f171 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -726,7 +726,12 @@ static ControllerMapping_t *SDL_CreateMappingForWGIController(SDL_JoystickGUID g
}
SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
@@ -682,0 +683,4 @@ static ControllerMapping_t *SDL_CreateMappingForWGIController(SDL_JoystickGUID g
+#ifdef __WINRT__
+ /* Xbox WGI exposes the canonical SDL axis and hat layout. */
+ SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,", sizeof(mapping_string));
+#else
SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:b10,dpdown:b12,dpleft:b13,dpright:b11,leftx:a1,lefty:a0~,rightx:a3,righty:a2~,lefttrigger:a4,righttrigger:a5,", sizeof(mapping_string));
@@ -683,0 +688 @@ static ControllerMapping_t *SDL_CreateMappingForWGIController(SDL_JoystickGUID g
+#endif
return SDL_PrivateAddMappingForGUID(guid, mapping_string, &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
}
diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c
index 6f01b4e..26b8811 100644
index 9299ac5..9fce0a5 100644
--- a/src/joystick/windows/SDL_windows_gaming_input.c
+++ b/src/joystick/windows/SDL_windows_gaming_input.c
@@ -731,10 +731,19 @@ static int WGI_JoystickOpen(SDL_Joystick *joystick, int device_index)
__x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(hwdata->gamecontroller, &wireless);
}
@@ -793,4 +793,13 @@ static int WGI_JoystickOpen(SDL_Joystick *joystick, int device_index)
- /* Initialize the joystick capabilities */
- joystick->nbuttons = state->nbuttons;
- joystick->naxes = state->naxes;
@@ -40,13 +31,7 @@ index 6f01b4e..26b8811 100644
+ joystick->naxes = state->naxes;
+ joystick->nhats = state->nhats;
+ }
joystick->epowerlevel = wireless ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
if (wireless && hwdata->battery) {
@@ -872,6 +881,51 @@ static void WGI_JoystickUpdate(SDL_Joystick *joystick)
{
struct joystick_hwdata *hwdata = joystick->hwdata;
HRESULT hr;
@@ -933,0 +943,45 @@ static void WGI_JoystickUpdate(SDL_Joystick *joystick)
+
+#ifdef __WINRT__
+ if (hwdata->gamepad) {
@@ -92,13 +77,7 @@ index 6f01b4e..26b8811 100644
+ }
+#endif
+
UINT32 nbuttons = SDL_min(joystick->nbuttons, SDL_MAX_UINT8);
boolean *buttons = NULL;
UINT32 nhats = SDL_min(joystick->nhats, SDL_MAX_UINT8);
@@ -994,7 +1048,38 @@ static void WGI_JoystickQuit(void)
static SDL_bool WGI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
@@ -1055,0 +1110,30 @@ static SDL_bool WGI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMappi
+#ifdef __WINRT__
+ WindowsGamingInputControllerState *state = &wgi.controllers[device_index];
+
@@ -129,8 +108,5 @@ index 6f01b4e..26b8811 100644
+ out->righttrigger = (SDL_InputMapping){ EMappingKind_Axis, 5 };
+ return SDL_TRUE;
+#else
return SDL_FALSE;
@@ -1056,0 +1141 @@ static SDL_bool WGI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMappi
+#endif
}
SDL_JoystickDriver SDL_WGI_JoystickDriver = {
+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env bash
# Build the Xbox Dev Mode UWP package with the shared game.love payload.
#
# Usage:
# scripts/build_xbox_uwp.sh [--release|--relwithdebinfo]
# [--version X.Y.Z] [--game-love PATH]
# [--publisher SUBJECT]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=xbox-uwp/common.sh
. "$SCRIPT_DIR/xbox-uwp/common.sh"
CONFIGURATION="Release"
PRESET="uwp-release"
GAME_LOVE=""
VERSION="0.0.0"
VERSION_EXPLICIT=0
PUBLISHER="${GEN1RECOMP_UWP_PUBLISHER:-CN=Gen1Recomp}"
while [ $# -gt 0 ]; do
case "$1" in
--release)
CONFIGURATION="Release"
PRESET="uwp-release"
shift
;;
--relwithdebinfo)
CONFIGURATION="RelWithDebInfo"
PRESET="uwp-relwithdebinfo"
shift
;;
--game-love)
[ $# -ge 2 ] || fail "--game-love requires a path"
GAME_LOVE="$2"
shift 2
;;
--version)
[ $# -ge 2 ] || fail "--version requires X.Y.Z"
VERSION="$2"
VERSION_EXPLICIT=1
shift 2
;;
--publisher)
[ $# -ge 2 ] || fail "--publisher requires a certificate subject"
PUBLISHER="$2"
shift 2
;;
-h|--help)
sed -n '2,7p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*) fail "unknown argument: $1" ;;
esac
done
case "$(uname -s)" in
MINGW*|MSYS*|CYGWIN*) ;;
*) fail "Xbox UWP packages must be built from Git Bash on Windows" ;;
esac
require_command cmake
require_command cygpath
require_command powershell.exe
require_command unzip
printf '%s' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' \
|| fail "invalid version '$VERSION' (expected X.Y.Z)"
if [ -z "$GAME_LOVE" ]; then
require_command zip
mkdir -p "$WORK"
GAME_LOVE="$WORK/game.love"
pack_args=(
--output "$GAME_LOVE" \
--listing "$WORK/love-listing.txt"
)
if [ "$VERSION_EXPLICIT" -eq 1 ]; then
pack_args+=(--version "$VERSION")
fi
"$ROOT/scripts/pack_love.sh" "${pack_args[@]}"
else
GAME_LOVE="$(cd "$(dirname "$GAME_LOVE")" && pwd)/$(basename "$GAME_LOVE")"
[ -f "$GAME_LOVE" ] || fail "missing game.love: $GAME_LOVE"
"$ROOT/scripts/switch/verify_payload.sh" "$GAME_LOVE"
if [ "$VERSION_EXPLICIT" -eq 1 ]; then
version_re="$(printf '%s' "$VERSION" | sed 's/\./\\./g')"
unzip -p "$GAME_LOVE" src/core/Version.lua \
| grep -Eq "engine[[:space:]]*=[[:space:]]*\"$version_re\"" \
|| fail "game.love does not report engine $VERSION"
fi
fi
say "configuring Xbox UWP ($CONFIGURATION)"
cmake --preset "$PRESET" -S "$(windows_path "$UWP_ROOT")" \
"-DGEN1RECOMP_LOVE:FILEPATH=$(windows_path "$GAME_LOVE")" \
"-DGEN1RECOMP_VERSION:STRING=$VERSION" \
"-DGEN1RECOMP_UWP_PUBLISHER:STRING=$PUBLISHER"
say "building Xbox UWP ($CONFIGURATION)"
(cd "$UWP_ROOT" && cmake --build --preset "$PRESET")
build_info="$WORK/xbox-uwp-build-info.json"
bash "$SCRIPT_DIR/xbox-uwp/write_build_info.sh" \
"$build_info" "$VERSION" "$CONFIGURATION"
powershell.exe -NoProfile -ExecutionPolicy Bypass -File \
"$(windows_path "$SCRIPT_DIR/xbox-uwp/stage_release.ps1")" \
-Version "$VERSION" \
-Configuration "$CONFIGURATION" \
-BuildInfo "$(windows_path "$build_info")"
say "done. See dist/xbox-uwp/"
+22 -2
View File
@@ -1,14 +1,15 @@
#!/usr/bin/env bash
# Shared game.love packer for desktop and Switch builds.
# Shared game.love packer for platform builds.
#
# Usage:
# scripts/pack_love.sh [--output PATH] [--listing PATH] [--dry-run]
# [--build-info PATH]
# [--build-info PATH] [--version X.Y.Z]
#
# Packs the same include/exclude set as the desktop release. Materializes a
# listing file once and greps it (avoids SIGPIPE from unzip|grep under pipefail).
#
# --build-info PATH copy JSON into the love archive root before verification
# --version X.Y.Z stamp the release version inside the archive
# --dry-run pack + verify only (for CI gates; no platform artifacts)
set -euo pipefail
@@ -19,6 +20,7 @@ OUTPUT="$WORK/game.love"
LISTING="$WORK/love-listing.txt"
DRY_RUN=0
BUILD_INFO=""
VERSION=""
say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
@@ -28,6 +30,7 @@ while [ $# -gt 0 ]; do
--output) OUTPUT="$2"; shift 2 ;;
--listing) LISTING="$2"; shift 2 ;;
--build-info) BUILD_INFO="$2"; shift 2 ;;
--version) VERSION="$2"; shift 2 ;;
--dry-run) DRY_RUN=1; shift ;;
-h|--help)
sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//'
@@ -56,6 +59,23 @@ if [ -n "$BUILD_INFO" ]; then
(cd "$(dirname "$BUILD_INFO")" && zip -q "$OUTPUT" build-info.json)
fi
if [ -n "$VERSION" ]; then
printf '%s' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' \
|| fail "invalid version '$VERSION' (expected X.Y.Z)"
stamp_dir="$(mktemp -d "$WORK/stamp-love.XXXXXX")"
output_abs="$(cd "$(dirname "$OUTPUT")" && pwd)/$(basename "$OUTPUT")"
trap 'rm -rf "$stamp_dir"' EXIT
mkdir -p "$stamp_dir/src/core"
sed -E "s/(engine[[:space:]]*=[[:space:]]*\")[^\"]*(\")/\1$VERSION\2/" \
"$ROOT/src/core/Version.lua" > "$stamp_dir/src/core/Version.lua"
(cd "$stamp_dir" && zip -q "$output_abs" src/core/Version.lua)
version_re="$(printf '%s' "$VERSION" | sed 's/\./\\./g')"
unzip -p "$output_abs" src/core/Version.lua \
| grep -Eq "engine[[:space:]]*=[[:space:]]*\"$version_re\"" \
|| fail "version stamp failed: game.love does not report engine $VERSION"
say "stamped engine version: $VERSION"
fi
# Materialize the listing once. Piping unzip→grep -q under `set -o pipefail`
# SIGPIPEs unzip when grep exits early on a match and aborts the build.
unzip -Z1 "$OUTPUT" > "$LISTING"
@@ -5,7 +5,8 @@ param(
$ErrorActionPreference = "Stop"
$portRoot = Split-Path -Parent $PSScriptRoot
$repoRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
$portRoot = Join-Path $repoRoot "ports\uwp"
$sourceRoot = Join-Path $portRoot "third_party\sdl2\source"
$buildRoot = Join-Path $portRoot "build\sdl2"
$installRoot = Join-Path $portRoot "build\sdl2-install"
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
UWP_ROOT="$ROOT/ports/uwp"
WORK="$ROOT/.bazinga/work"
say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
require_command() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
sha256_file() {
local path="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$path" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$path" | awk '{print $1}'
else
fail "sha256sum or shasum is required"
fi
}
windows_path() {
cygpath -aw "$1"
}
@@ -10,7 +10,8 @@ param(
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$portRoot = Split-Path -Parent $PSScriptRoot
$repoRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
$portRoot = Join-Path $repoRoot "ports\uwp"
$thirdPartyRoot = Join-Path $portRoot "third_party"
$manifestPath = Join-Path $thirdPartyRoot "manifest.json"
$metadata = Get-Content -Raw -LiteralPath $manifestPath | ConvertFrom-Json
@@ -61,7 +62,7 @@ function Ensure-GitSource {
[Parameter(Mandatory)][string]$Repository,
[Parameter(Mandatory)][string]$Revision,
[Parameter(Mandatory)][string]$Path,
[string]$SnapshotRevision
[switch]$AllowTrackedChanges
)
if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
@@ -74,28 +75,34 @@ function Ensure-GitSource {
}
$gitDirectory = Join-Path $Path ".git"
if (Test-Path -LiteralPath $gitDirectory) {
$actual = (& git -C $Path rev-parse HEAD).Trim()
if ($LASTEXITCODE -ne 0) {
throw "Unable to inspect the $Name source checkout."
}
if ($actual -ne $Revision) {
throw "$Name source is at $actual; expected $Revision. Remove '$Path' to recreate it."
}
return
if (-not (Test-Path -LiteralPath $gitDirectory -PathType Container)) {
throw "$Name source has no Git metadata. Remove '$Path' to recreate the pinned checkout."
}
if (-not $SnapshotRevision) {
throw "$Name source exists without Git metadata, so its revision cannot be verified."
$actual = (& git -C $Path rev-parse HEAD).Trim()
if ($LASTEXITCODE -ne 0) {
throw "Unable to inspect the $Name source checkout."
}
if ($actual -ne $Revision) {
throw "$Name source is at $actual; expected $Revision. Remove '$Path' to recreate it."
}
if (-not $AllowTrackedChanges) {
Assert-GitSourceClean -Name $Name -Path $Path
}
}
$revisionFile = Join-Path $Path "REVISION.txt"
if (-not (Test-Path -LiteralPath $revisionFile -PathType Leaf)) {
throw "$Name source snapshot is missing REVISION.txt."
}
$actualSnapshot = (Get-Content -Raw -LiteralPath $revisionFile).Trim()
if ($actualSnapshot -ne $SnapshotRevision) {
throw "$Name source snapshot is '$actualSnapshot'; expected '$SnapshotRevision'."
function Assert-GitSourceClean {
param(
[Parameter(Mandatory)][string]$Name,
[Parameter(Mandatory)][string]$Path
)
& git -C $Path diff --quiet --ignore-submodules --
$worktreeDirty = $LASTEXITCODE -ne 0
& git -C $Path diff --cached --quiet --ignore-submodules --
$indexDirty = $LASTEXITCODE -ne 0
if ($worktreeDirty -or $indexDirty) {
throw "$Name source has local changes. Remove '$Path' to recreate the pinned checkout."
}
}
@@ -133,7 +140,22 @@ function Ensure-DepotToolsGit {
}
function Get-Sha256 {
param([Parameter(Mandatory)][string]$Path)
param(
[Parameter(Mandatory)][string]$Path,
[switch]$NormalizeLineEndings
)
if ($NormalizeLineEndings) {
$bytes = [System.IO.File]::ReadAllBytes($Path)
$text = [System.Text.Encoding]::UTF8.GetString($bytes).Replace("`r`n", "`n")
$bytes = [System.Text.UTF8Encoding]::new($false).GetBytes($text)
$sha256 = [System.Security.Cryptography.SHA256]::Create()
try {
return [System.BitConverter]::ToString($sha256.ComputeHash($bytes)).Replace("-", "")
} finally {
$sha256.Dispose()
}
}
$stream = [System.IO.File]::OpenRead($Path)
try {
@@ -163,15 +185,16 @@ function Update-Manifest {
$path = Join-Path $thirdPartyRoot $relativeRoot
Get-ChildItem -LiteralPath $path -File -Recurse | ForEach-Object {
$relative = $_.FullName.Substring($thirdPartyRoot.Length + 1).Replace("\", "/")
$normalize = $relative.StartsWith("sdl2/include/", [System.StringComparison]::Ordinal)
[ordered]@{
path = $relative
sha256 = Get-Sha256 $_.FullName
sha256 = Get-Sha256 -Path $_.FullName -NormalizeLineEndings:$normalize
}
}
}
$metadata.configuration = $Configuration
$metadata.files = @($files | Sort-Object path)
$metadata.files = @($files | Sort-Object { $_['path'] })
$json = $metadata | ConvertTo-Json -Depth 10
[System.IO.File]::WriteAllText($manifestPath, "$json`r`n", [System.Text.UTF8Encoding]::new($false))
}
@@ -184,22 +207,30 @@ Ensure-GitSource `
-Repository $metadata.sources.sdl2.repository `
-Revision $metadata.sources.sdl2.commit `
-Path $sdlSource `
-SnapshotRevision $metadata.sources.sdl2.revision
-AllowTrackedChanges
$sdlPatch = Join-Path $thirdPartyRoot $metadata.sources.sdl2.patch
Push-Location $sdlSource
try {
& git apply --reverse --check $sdlPatch 2>$null
if ($LASTEXITCODE -ne 0) {
Invoke-Tool git apply --check $sdlPatch
Invoke-Tool git apply $sdlPatch
& git apply --unidiff-zero --reverse --check $sdlPatch 2>$null
if ($LASTEXITCODE -eq 0) {
Invoke-Tool git apply --unidiff-zero --reverse $sdlPatch
try {
Assert-GitSourceClean -Name "SDL2" -Path $sdlSource
} finally {
Invoke-Tool git apply --unidiff-zero $sdlPatch
}
} else {
Assert-GitSourceClean -Name "SDL2" -Path $sdlSource
Invoke-Tool git apply --unidiff-zero --check $sdlPatch
Invoke-Tool git apply --unidiff-zero $sdlPatch
}
} finally {
Pop-Location
}
Write-Host "Building SDL2..."
& (Join-Path $PSScriptRoot "build-sdl2-angle.ps1") `
& (Join-Path $PSScriptRoot "build_sdl2_angle.ps1") `
-Configuration $Configuration `
-WindowsSdkVersion $WindowsSdkVersion
if ($LASTEXITCODE -ne 0) {
@@ -375,15 +406,31 @@ foreach ($license in $metadata.sources.vcpkg.licenses.PSObject.Properties) {
Write-Host "Updating dependency hashes..."
Update-Manifest
& (Join-Path $PSScriptRoot "verify-dependencies.ps1") -Manifest $manifestPath
& (Join-Path $PSScriptRoot "verify_dependencies.ps1") -Manifest $manifestPath
if ($LASTEXITCODE -ne 0) {
throw "Dependency verification failed with exit code $LASTEXITCODE."
}
if (-not $SkipPackage) {
Write-Host "Building the Release package..."
Invoke-Tool cmake --preset uwp-release -S $portRoot
Invoke-Tool cmake --build --preset uwp-release
$gitRoot = Split-Path -Parent (Split-Path -Parent (Get-Command git).Source)
$bash = Join-Path $gitRoot "bin\bash.exe"
if (-not (Test-Path -LiteralPath $bash -PathType Leaf)) {
throw "Git Bash was not found at $bash."
}
$buildScript = [System.IO.Path]::GetFullPath(
(Join-Path $portRoot "..\..\scripts\build_xbox_uwp.sh")
).Replace("\", "/")
if ($buildScript -match "^([A-Za-z]):/(.*)$") {
$buildScript = "/$($Matches[1].ToLowerInvariant())/$($Matches[2])"
}
$packageConfiguration = if ($Configuration -eq "RelWithDebInfo") {
"--relwithdebinfo"
} else {
"--release"
}
Invoke-Tool $bash $buildScript $packageConfiguration
}
Write-Host "UWP dependencies rebuilt and staged successfully."
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Offline checks for the Xbox UWP build entry points.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=common.sh
. "$SCRIPT_DIR/common.sh"
require_command zip
require_command unzip
say "checking shell entry points"
bash -n "$ROOT/scripts/build_xbox_uwp.sh" "$SCRIPT_DIR"/*.sh
help="$(bash "$ROOT/scripts/build_xbox_uwp.sh" --help)"
printf '%s' "$help" | grep -q -- '--version X.Y.Z' \
|| fail "build help does not document --version"
say "checking the shared game.love payload"
temp_dir="$(mktemp -d "${TMPDIR:-/tmp}/gen1recomp-uwp-selftest.XXXXXX")"
trap 'rm -rf "$temp_dir"' EXIT
love_file="$temp_dir/game.love"
listing="$temp_dir/love-listing.txt"
"$ROOT/scripts/pack_love.sh" \
--output "$love_file" \
--listing "$listing" \
--version 1.2.3 \
--dry-run >/dev/null
unzip -p "$love_file" src/core/Version.lua \
| grep -Eq 'engine[[:space:]]*=[[:space:]]*"1\.2\.3"' \
|| fail "shared payload version was not stamped"
say "checking the manifest template"
grep -q '@UWP_PACKAGE_VERSION@' "$UWP_ROOT/Package.appxmanifest.in" \
|| fail "manifest template is missing the package version placeholder"
grep -q '@UWP_PUBLISHER_XML@' "$UWP_ROOT/Package.appxmanifest.in" \
|| fail "manifest template is missing the publisher placeholder"
bash "$SCRIPT_DIR/write_build_info.sh" \
"$temp_dir/build-info.json" 1.2.3 Release >/dev/null
grep -q '"version": "1.2.3"' "$temp_dir/build-info.json" \
|| fail "build metadata does not contain the requested version"
say "Xbox UWP self-test passed"
+150
View File
@@ -0,0 +1,150 @@
[CmdletBinding()]
param(
[Parameter(Mandatory)][ValidatePattern('^\d+\.\d+\.\d+$')]
[string]$Version,
[ValidateSet('Release', 'RelWithDebInfo')]
[string]$Configuration = 'Release',
[string]$PackageRoot,
[string]$OutputRoot,
[string]$BuildInfo,
[string]$CertificatePath,
[string]$CertificatePassword
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$repositoryRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..'))
$configurationDirectory = $Configuration.ToLowerInvariant()
if (-not $PackageRoot) {
$PackageRoot = Join-Path $repositoryRoot "ports\uwp\build\$configurationDirectory\AppPackages\Gen1RecompUWP"
}
if (-not $OutputRoot) {
$OutputRoot = Join-Path $repositoryRoot 'dist\xbox-uwp'
}
$packageVersion = "$Version.0"
$packageDirectory = Join-Path $PackageRoot "Gen1RecompUWP_${packageVersion}_x64_Test"
$package = Join-Path $packageDirectory "Gen1RecompUWP_${packageVersion}_x64.msix"
if (-not (Test-Path -LiteralPath $package -PathType Leaf)) {
throw "Expected MSIX was not found: $package"
}
function Get-SignTool {
$kitsRoot = ${env:ProgramFiles(x86)}
if (-not $kitsRoot) {
throw 'ProgramFiles(x86) is not defined.'
}
$binRoot = Join-Path $kitsRoot 'Windows Kits\10\bin'
$tool = Get-ChildItem -LiteralPath $binRoot -Filter signtool.exe -File -Recurse |
Where-Object { $_.FullName -match '\\x64\\signtool\.exe$' } |
Sort-Object FullName -Descending |
Select-Object -First 1
if (-not $tool) {
throw 'SignTool was not found in the Windows SDK.'
}
return $tool.FullName
}
$certificate = $null
if ($CertificatePath) {
if (-not (Test-Path -LiteralPath $CertificatePath -PathType Leaf)) {
throw "Signing certificate was not found: $CertificatePath"
}
$flags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::EphemeralKeySet
$certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
$CertificatePath,
$CertificatePassword,
$flags
)
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
$archive = [System.IO.Compression.ZipFile]::OpenRead($package)
try {
$entry = $archive.GetEntry('AppxManifest.xml')
if (-not $entry) { throw 'AppxManifest.xml is missing from the MSIX.' }
$reader = [System.IO.StreamReader]::new($entry.Open())
try { [xml]$manifest = $reader.ReadToEnd() } finally { $reader.Dispose() }
} finally {
$archive.Dispose()
}
$publisher = $manifest.Package.Identity.Publisher
if ($publisher -ne $certificate.Subject) {
throw "Manifest publisher '$publisher' does not match certificate subject '$($certificate.Subject)'."
}
$signTool = Get-SignTool
$signArguments = @('sign', '/fd', 'SHA256', '/f', $CertificatePath)
if ($CertificatePassword) {
$signArguments += @('/p', $CertificatePassword)
}
$signArguments += $package
& $signTool @signArguments
if ($LASTEXITCODE -ne 0) { throw "SignTool failed with exit code $LASTEXITCODE." }
& $signTool verify /pa $package
if ($LASTEXITCODE -ne 0) { throw "Signature verification failed with exit code $LASTEXITCODE." }
}
New-Item -ItemType Directory -Path $OutputRoot -Force | Out-Null
$stage = Join-Path $OutputRoot 'stage'
if (Test-Path -LiteralPath $stage) {
Remove-Item -LiteralPath $stage -Recurse -Force
}
New-Item -ItemType Directory -Path $stage | Out-Null
$releasePackage = "gen1recomp-$Version-xbox-uwp.msix"
Copy-Item -LiteralPath $package -Destination (Join-Path $stage $releasePackage)
$dependencies = Join-Path $packageDirectory 'Dependencies\x64'
if (Test-Path -LiteralPath $dependencies -PathType Container) {
$dependencyStage = Join-Path $stage 'Dependencies\x64'
New-Item -ItemType Directory -Path $dependencyStage -Force | Out-Null
Copy-Item -Path (Join-Path $dependencies '*') -Destination $dependencyStage -Recurse
}
if ($BuildInfo -and (Test-Path -LiteralPath $BuildInfo -PathType Leaf)) {
Copy-Item -LiteralPath $BuildInfo -Destination (Join-Path $stage 'build-info.json')
}
if ($certificate) {
[System.IO.File]::WriteAllBytes(
(Join-Path $stage 'Gen1RecompUWP.cer'),
$certificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
)
}
$install = @"
Gen1Recomp $Version for Xbox Dev Mode
Install the MSIX and any packages under Dependencies through Xbox Device Portal.
The certificate is public and is included only when the package was release-signed.
ROMs, saves and mods are not included.
"@
[System.IO.File]::WriteAllText(
(Join-Path $stage 'INSTALL.txt'),
$install,
[System.Text.UTF8Encoding]::new($false)
)
$archivePath = Join-Path $OutputRoot "gen1recomp-$Version-xbox-uwp.zip"
if (Test-Path -LiteralPath $archivePath) {
Remove-Item -LiteralPath $archivePath -Force
}
Compress-Archive -Path (Join-Path $stage '*') -DestinationPath $archivePath -CompressionLevel Optimal
$stream = [System.IO.File]::OpenRead($archivePath)
try {
$sha256 = [System.Security.Cryptography.SHA256]::Create()
try {
$hash = ([System.BitConverter]::ToString($sha256.ComputeHash($stream))).Replace('-', '').ToLowerInvariant()
} finally {
$sha256.Dispose()
}
} finally {
$stream.Dispose()
}
[System.IO.File]::WriteAllText(
"$archivePath.sha256",
"$hash $([System.IO.Path]::GetFileName($archivePath))`n",
[System.Text.UTF8Encoding]::new($false)
)
Remove-Item -LiteralPath $stage -Recurse -Force
Write-Host "Staged $archivePath"
+55
View File
@@ -0,0 +1,55 @@
param(
[string]$Manifest = (Join-Path $PSScriptRoot "..\..\ports\uwp\third_party\manifest.json")
)
$ErrorActionPreference = "Stop"
$manifestPath = (Resolve-Path $Manifest).Path
$thirdPartyRoot = Split-Path -Parent $manifestPath
$metadata = Get-Content -Raw $manifestPath | ConvertFrom-Json
function Get-Sha256 {
param(
[Parameter(Mandatory)][string]$Path,
[switch]$NormalizeLineEndings
)
if ($NormalizeLineEndings) {
$bytes = [System.IO.File]::ReadAllBytes($Path)
$text = [System.Text.Encoding]::UTF8.GetString($bytes).Replace("`r`n", "`n")
$bytes = [System.Text.UTF8Encoding]::new($false).GetBytes($text)
$sha256 = [System.Security.Cryptography.SHA256]::Create()
try {
return [System.BitConverter]::ToString($sha256.ComputeHash($bytes)).Replace("-", "")
} finally {
$sha256.Dispose()
}
}
$stream = [System.IO.File]::OpenRead($Path)
try {
$sha256 = [System.Security.Cryptography.SHA256]::Create()
try {
return [System.BitConverter]::ToString($sha256.ComputeHash($stream)).Replace("-", "")
} finally {
$sha256.Dispose()
}
} finally {
$stream.Dispose()
}
}
foreach ($file in $metadata.files) {
$path = Join-Path $thirdPartyRoot $file.path
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
throw "Missing UWP dependency: $($file.path)"
}
$normalize = $file.path.StartsWith("sdl2/include/", [System.StringComparison]::Ordinal)
$actual = Get-Sha256 -Path $path -NormalizeLineEndings:$normalize
if ($actual -ne $file.sha256) {
throw "UWP dependency hash mismatch: $($file.path)"
}
}
Write-Host "Verified $($metadata.files.Count) UWP dependency files."
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Write provenance for an Xbox UWP package.
#
# Usage: scripts/xbox-uwp/write_build_info.sh OUTPUT VERSION CONFIGURATION
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=common.sh
. "$SCRIPT_DIR/common.sh"
OUTPUT="${1:-}"
VERSION="${2:-}"
CONFIGURATION="${3:-}"
MANIFEST="$UWP_ROOT/third_party/manifest.json"
[ -n "$OUTPUT" ] && [ -n "$VERSION" ] && [ -n "$CONFIGURATION" ] \
|| fail "usage: $0 OUTPUT VERSION CONFIGURATION"
[ -f "$MANIFEST" ] || fail "missing dependency manifest: $MANIFEST"
mkdir -p "$(dirname "$OUTPUT")"
GIT_COMMIT="$(git -C "$ROOT" rev-parse HEAD 2>/dev/null || echo unknown)"
BUILT_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
MANIFEST_SHA256="$(sha256_file "$MANIFEST")"
LOVE_COMMIT="$(awk '
/"love"[[:space:]]*:/ { in_love=1 }
in_love && /"commit"[[:space:]]*:/ {
value=$0
sub(/^.*"commit"[[:space:]]*:[[:space:]]*"/, "", value)
sub(/".*$/, "", value)
print value
exit
}
' "$MANIFEST")"
[ -n "$LOVE_COMMIT" ] || fail "LÖVE revision is missing from the dependency manifest"
cat > "$OUTPUT" <<EOF
{
"platform": "xbox-uwp",
"version": "$VERSION",
"configuration": "$CONFIGURATION",
"gitCommit": "$GIT_COMMIT",
"loveCommit": "$LOVE_COMMIT",
"dependencyManifestSha256": "$MANIFEST_SHA256",
"builtAt": "$BUILT_AT"
}
EOF
say "build info: $OUTPUT"
+9 -3
View File
@@ -1,4 +1,4 @@
-- Platform capability detection for NX / mobile / desktop.
-- Platform capability detection for console, mobile and desktop builds.
local Platform = {}
@@ -8,20 +8,22 @@ local function compute()
local osName = (love and love.system and love.system.getOS and love.system.getOS())
or "Unknown"
local nx = osName == "NX"
local uwp = osName == "UWP"
local mobile = osName == "Android" or osName == "iOS"
local nativePicker = love and love.system
and type(love.system.pickFile) == "function"
return {
os = osName,
nx = nx,
uwp = uwp,
mobile = mobile,
console = nx,
console = nx or uwp,
hasNativePicker = nativePicker,
canSpawnProcess = osName == "OS X" or osName == "Windows" or osName == "Linux",
romImportMode = nx and "save-directory"
or (nativePicker and "native-picker")
or "desktop",
networkValidated = not nx,
networkValidated = not nx and not uwp,
}
end
@@ -34,6 +36,10 @@ function Platform.isNX()
return Platform.detect().nx
end
function Platform.isUWP()
return Platform.detect().uwp
end
function Platform.romImportMode()
return Platform.detect().romImportMode
end
+3 -7
View File
@@ -28,14 +28,10 @@
-- ordinary love.filesystem/save-directory behaviour.
local CacheFs = {}
local Platform = require("src.core.Platform")
local SEP = package.config:sub(1, 1)
local function isUWP()
return love and love.system and love.system.getOS
and love.system.getOS() == "UWP"
end
-- Cache-relative paths are prefixed with this before every read/write, so a
-- Blue/Yellow import lands under its GameVersion.cachePrefix (blue/, yellow/)
-- while a Red import keeps the historical root. The launcher sets it per
@@ -57,7 +53,7 @@ local mkdirFn = nil
local function resolveMkdir()
if mkdirFn ~= nil then return mkdirFn end
mkdirFn = false
if isUWP() then return mkdirFn end
if Platform.isUWP() then return mkdirFn end
local ok, ffi = pcall(require, "ffi")
if not ok then return mkdirFn end
if ffi.os == "Windows" then
@@ -89,7 +85,7 @@ local rmdirFn = nil
local function resolveRmdir()
if rmdirFn ~= nil then return rmdirFn end
rmdirFn = false
if isUWP() then return rmdirFn end
if Platform.isUWP() then return rmdirFn end
local ok, ffi = pcall(require, "ffi")
if not ok then return rmdirFn end
if ffi.os == "Windows" then
+21 -27
View File
@@ -8,11 +8,6 @@ local SafeArea = require("src.core.SafeArea")
local RomImporter = {}
RomImporter.__index = RomImporter
local function isUWP()
return love and love.system and love.system.getOS
and love.system.getOS() == "UWP"
end
-- love.system.pickFile is a NATIVE BRIDGE, not part of LÖVE: it exists only on
-- builds that compiled one (Android, and iOS builds patched by
-- mobile/ios/patch_love_src.py). A build without it must fall back to the
@@ -995,7 +990,6 @@ end
-- import-only run all skip the release check so headless and CI runs never spin
-- up the background worker or reach out to the network.
local function updaterAllowed()
if isUWP() then return false end
if not Platform.networkValidated() then return false end
if not (love.filesystem.isFused and love.filesystem.isFused()) then return false end
if os.getenv("POKEPORT_AUTOPILOT") or os.getenv("POKEPORT_DRIVER") then return false end
@@ -1100,8 +1094,8 @@ function RomImporter.new(onComplete, opts)
-- Android SAF create-document: which game's SAVE FILES card should show
-- "Save exported." when export_done.flag appears on focus.
androidPendingExportVersion = nil,
iosPendingKind = nil,
iosPendingVersion = nil,
pickerPendingKind = nil,
pickerPendingVersion = nil,
-- Virtual pointer for handhelds / gamepads (Anbernic stock OS has no
-- mouse). D-pad + left stick move it; A clicks; shoulders cycle tabs;
-- right stick scrolls the save-slot / mods lists.
@@ -1501,9 +1495,9 @@ function RomImporter:chooseMod()
return
end
if self.nativePicker and love.system.getPickedFile then
self.iosPendingKind = "mod"
self.pickerPendingKind = "mod"
if not pickFile("mod") then
self.iosPendingKind = nil
self.pickerPendingKind = nil
self.modNotice = { ok = false, text = "Could not open the file picker." }
end
return
@@ -1577,11 +1571,11 @@ function RomImporter:chooseSaveImport(version)
return
end
if self.nativePicker and love.system.getPickedFile then
self.iosPendingKind = "sav"
self.iosPendingVersion = version
self.pickerPendingKind = "sav"
self.pickerPendingVersion = version
if not pickFile("sav") then
self.iosPendingKind = nil
self.iosPendingVersion = nil
self.pickerPendingKind = nil
self.pickerPendingVersion = nil
self.saveNotice[version] = { ok = false, text = "Could not open the file picker." }
end
return
@@ -1695,9 +1689,9 @@ function RomImporter:choose(version)
return
end
if self.nativePicker and love.system.getPickedFile then
self.iosPendingKind = "rom"
self.pickerPendingKind = "rom"
if not pickFile("rom") then
self.iosPendingKind = nil
self.pickerPendingKind = nil
self:setError("Could not open the file picker.")
end
return
@@ -1899,32 +1893,32 @@ function RomImporter:update(dt)
if self.nativePicker and love.system.getPickedFile and self.workState ~= "working" then
local path = love.system.getPickedFile()
if path then
local kind = self.iosPendingKind or "rom"
local version = self.iosPendingVersion
self.iosPendingKind = nil
self.iosPendingVersion = nil
local kind = self.pickerPendingKind or "rom"
local version = self.pickerPendingVersion
self.pickerPendingKind = nil
self.pickerPendingVersion = nil
if kind == "mod" then
self:_installMod(path)
if isUWP() and self.modNotice and self.modNotice.ok then
if Platform.isUWP() and self.modNotice and self.modNotice.ok then
os.remove(path)
end
elseif kind == "sav" then
local target = version or self:_savedropTarget()
self:_importSave(target, path)
if isUWP() and self.saveNotice[target] and self.saveNotice[target].ok then
if Platform.isUWP() and self.saveNotice[target] and self.saveNotice[target].ok then
os.remove(path)
end
else
self:startPath(path)
if isUWP() then os.remove(path) end
if Platform.isUWP() then os.remove(path) end
end
elseif love.system.getPickError then
local errorText = love.system.getPickError()
if errorText then
local kind = self.iosPendingKind or "rom"
local version = self.iosPendingVersion or self:_savedropTarget()
self.iosPendingKind = nil
self.iosPendingVersion = nil
local kind = self.pickerPendingKind or "rom"
local version = self.pickerPendingVersion or self:_savedropTarget()
self.pickerPendingKind = nil
self.pickerPendingVersion = nil
if kind == "mod" then
self.modNotice = { ok = false, text = errorText }
elseif kind == "sav" then
+2 -2
View File
@@ -17,6 +17,7 @@
-- worker can reuse the exact same code path via love.filesystem.load.
local Check = {}
local Platform = require("src.core.Platform")
Check.REPO = "bryanthaboi/gen1recomp"
@@ -99,8 +100,7 @@ local cache = { status = "idle" } -- newest snapshot from the worker
local function ensureWorker()
if workerReady ~= nil then return workerReady end
if love and love.system and love.system.getOS
and love.system.getOS() == "UWP" then
if not Platform.networkValidated() then
workerReady = false
return false
end
+13
View File
@@ -37,6 +37,19 @@ withOS("NX", nil, function(Platform)
eq(Platform.romImportMode(), "save-directory", "romImportMode helper")
end)
-- Xbox UWP: native picker, console constraints, no in-app updater
withOS("UWP", function() end, function(Platform)
local caps = Platform.detect()
eq(caps.os, "UWP", "UWP detect os")
eq(caps.uwp, true, "UWP flag")
eq(caps.console, true, "UWP console")
eq(caps.hasNativePicker, true, "UWP has pickFile")
eq(caps.romImportMode, "native-picker", "UWP romImportMode")
eq(caps.canSpawnProcess, false, "UWP cannot spawn processes")
eq(caps.networkValidated, false, "UWP network not validated")
eq(Platform.isUWP(), true, "isUWP convenience")
end)
-- Android: mobile native picker path, not NX semantics
withOS("Android", function() end, function(Platform)
local caps = Platform.detect()
+54
View File
@@ -0,0 +1,54 @@
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local S = require("tests.harness").suite("UWP native picker")
local check = S.check
local Platform = require("src.core.Platform")
local RomImporter = require("src.import.RomImporter")
love.system = love.system or {}
local saved = {
getOS = love.system.getOS,
pickFile = love.system.pickFile,
getPickedFile = love.system.getPickedFile,
getPickError = love.system.getPickError,
remove = os.remove,
}
love.system.getOS = function() return "UWP" end
love.system.pickFile = function() return true end
love.system.getPickedFile = function()
love.system.getPickedFile = function() return nil end
return [[C:\LocalState\picked_mod.zip]]
end
love.system.getPickError = function() return nil end
local removedPath
os.remove = function(path)
removedPath = path
return true
end
Platform._resetForTests()
local importer = RomImporter.new(function() end, { launcher = true })
importer.pickerPendingKind = "mod"
importer._installMod = function(self, source)
self.installedPath = source
self.modNotice = { ok = true, text = "Installed test-mod" }
end
importer:update(0)
check(importer.installedPath == [[C:\LocalState\picked_mod.zip]],
"passes the picked path to the mod installer")
check(removedPath == [[C:\LocalState\picked_mod.zip]],
"removes the temporary copy after installation")
love.system.getOS = saved.getOS
love.system.pickFile = saved.pickFile
love.system.getPickedFile = saved.getPickedFile
love.system.getPickError = saved.getPickError
os.remove = saved.remove
Platform._resetForTests()
S.finish()
+4 -23
View File
@@ -23,6 +23,7 @@ local S = require("tests.harness").suite("rom importer double pick (#553)")
local check = S.check
local RomImporter = require("src.import.RomImporter")
local Platform = require("src.core.Platform")
love.system = love.system or {}
local saved = {
@@ -53,6 +54,7 @@ love.filesystem.remove = function(name) saveDir[name] = nil; return true end
local function importer(os)
love.system.getOS = function() return os end
Platform._resetForTests()
local ri = RomImporter.new(function() end, { launcher = true })
ri.ready = { red = false, blue = false, yellow = false }
return ri
@@ -68,6 +70,7 @@ local ios = importer("iOS")
check(ios.pickPending, "iOS still boots armed (unchanged by this fix)")
love.system.getOS = function() return "OS X" end
Platform._resetForTests()
local desktop = RomImporter.new(function() end, { launcher = true })
check(not desktop.pickPending, "desktop does not poll: it has no save-dir picks")
@@ -137,29 +140,6 @@ contract:choose("red")
check(picks == 2,
"choose() still reopens the picker per call (#420/#442 contract, got " .. picks .. ")")
-- 7. UWP consumes the absolute LocalState path returned by its native picker
-- and removes the temporary copy only after a successful import.
local removedPath
local savedOsRemove = os.remove
os.remove = function(path) removedPath = path; return true end
love.system.getPickedFile = function()
love.system.getPickedFile = function() return nil end
return [[C:\LocalState\picked_mod.zip]]
end
love.system.getPickError = function() return nil end
local uwp = importer("UWP")
uwp.iosPendingKind = "mod"
uwp._installMod = function(self, source)
self._installed = source
self.modNotice = { ok = true, text = "Installed test-mod" }
end
uwp:update(0)
check(uwp._installed == [[C:\LocalState\picked_mod.zip]],
"UWP passes the picker path to the mod installer")
check(removedPath == [[C:\LocalState\picked_mod.zip]],
"UWP removes the temporary picker copy after installation")
os.remove = savedOsRemove
local touchForwardsToImporter = {
Android = true,
iOS = true,
@@ -192,5 +172,6 @@ love.filesystem.getDirectoryItems = saved.getDirectoryItems
love.filesystem.getInfo = saved.getInfo
love.filesystem.read = saved.read
love.filesystem.remove = saved.remove
Platform._resetForTests()
S.finish()