fix: Argon skin corruption + ppy cherry-pick + surface format + safe-mode shader wipe #2462
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| on: [push, pull_request] | |
| name: Continuous Integration | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read # to fetch code (actions/checkout) | |
| packages: read # to restore NuGet packages from GitHub Packages | |
| security-events: write # for reporting InspectCode issues | |
| jobs: | |
| resource-budget-source: | |
| name: Resource Budget (Source Overrides) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install ffmpeg | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y ffmpeg | |
| - name: Optimize local override media | |
| run: | | |
| python3 scripts/optimize_resource_overrides.py \ | |
| --root osu.Game/Resources \ | |
| --config .github/resource-optimizer/config.json \ | |
| --report-file resource-budget/optimizer-report.json \ | |
| --summary-file resource-budget/optimizer-summary.md | |
| - name: Run source override resource budget checks | |
| run: | | |
| python3 scripts/check_resource_budgets.py \ | |
| --mode source \ | |
| --source-root osu.Game/Resources \ | |
| --budget-file .github/resource-budgets/source-overrides.json \ | |
| --report-file resource-budget/source-report.json \ | |
| --summary-file resource-budget/source-summary.md | |
| - name: Publish source optimization summary | |
| if: ${{ !cancelled() }} | |
| run: | | |
| cat resource-budget/optimizer-summary.md >> "$GITHUB_STEP_SUMMARY" | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| cat resource-budget/source-summary.md >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload source resource budget reports | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: resource-budget-source | |
| path: resource-budget/* | |
| inspect-code: | |
| name: Code Quality | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install .NET 10.0.x | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props') }} | |
| restore-keys: ${{ runner.os }}-nuget- | |
| - name: Authenticate to GitHub Packages | |
| run: dotnet nuget update source winnerspiros-github --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text | |
| - name: Restore Tools | |
| run: dotnet tool restore | |
| - name: Restore Packages | |
| run: dotnet restore osu.Desktop.slnf | |
| - name: Restore inspectcode cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ github.workspace }}/inspectcode | |
| key: inspectcode-${{ hashFiles('.config/dotnet-tools.json', '.github/workflows/ci.yml', 'osu.sln*', 'osu*.slnf', '.editorconfig', '.globalconfig', 'CodeAnalysis/*', '**/*.csproj', '**/*.props') }} | |
| - name: Dotnet code style | |
| run: dotnet build -c Debug -warnaserror osu.Desktop.slnf -p:EnforceCodeStyleInBuild=true | |
| - name: CodeFileSanity | |
| run: | | |
| # TODO: Add ignore filters and GitHub Workflow Command Reporting in CFS. That way we don't have to do this workaround. | |
| # FIXME: Suppress warnings from templates project | |
| exit_code=0 | |
| while read -r line; do | |
| if [[ ! -z "$line" ]]; then | |
| echo "::error::$line" | |
| exit_code=1 | |
| fi | |
| done <<< $(dotnet codefilesanity) | |
| exit $exit_code | |
| - name: InspectCode | |
| uses: JetBrains/ReSharper-InspectCode@v0.13 | |
| with: | |
| tool-version: 2026.1.0.1 | |
| # this is WTF tier but if you don't specify *both* of these the defaults assume `build: true` | |
| build: false | |
| no-build: true | |
| solution: ./osu.Desktop.slnf | |
| caches-home: inspectcode | |
| verbosity: WARN | |
| test: | |
| name: Test | |
| runs-on: ${{matrix.os.fullname}} | |
| env: | |
| OSU_EXECUTION_MODE: ${{matrix.threadingMode}} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: | |
| - { prettyname: Windows, fullname: windows-2025-vs2026 } | |
| # macOS runner performance has gotten unbearably slow so let's turn them off temporarily. | |
| # - { prettyname: macOS, fullname: macos-latest } | |
| - { prettyname: Linux, fullname: ubuntu-latest } | |
| threadingMode: ['MultiThreaded'] | |
| # Split tests into two parallel groups so Windows runners (which are ~2-3× slower than | |
| # Linux) finish each group in ~60 min rather than timing out on the full suite at 120 min. | |
| testSuite: | |
| - name: game | |
| dlls: >- | |
| osu.Game.Tests/bin/Debug/**/osu.Game.Tests.dll | |
| osu.Game.Tournament.Tests/bin/Debug/**/osu.Game.Tournament.Tests.dll | |
| Templates/**/*.Tests/bin/Debug/**/*.Tests.dll | |
| - name: rulesets | |
| dlls: >- | |
| osu.Game.Rulesets.Osu.Tests/bin/Debug/**/osu.Game.Rulesets.Osu.Tests.dll | |
| osu.Game.Rulesets.Taiko.Tests/bin/Debug/**/osu.Game.Rulesets.Taiko.Tests.dll | |
| osu.Game.Rulesets.Catch.Tests/bin/Debug/**/osu.Game.Rulesets.Catch.Tests.dll | |
| osu.Game.Rulesets.Mania.Tests/bin/Debug/**/osu.Game.Rulesets.Mania.Tests.dll | |
| timeout-minutes: 90 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install .NET 10.0.x | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props') }} | |
| restore-keys: ${{ runner.os }}-nuget- | |
| - name: Authenticate to GitHub Packages | |
| run: dotnet nuget update source winnerspiros-github --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text | |
| - name: Compile | |
| run: dotnet build -c Debug -warnaserror osu.Desktop.slnf | |
| - name: Test | |
| run: > | |
| dotnet test | |
| ${{matrix.testSuite.dlls}} | |
| --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}-${{matrix.testSuite.name}}.trx" | |
| -- | |
| NUnit.ConsoleOut=0 | |
| # Upload results even when the test step fails (non-cancellation failure still satisfies !cancelled()). | |
| # https://docs.github.com/en/actions/reference/workflows-and-actions/expressions#cancelled | |
| - name: Upload Test Results | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}}-${{matrix.testSuite.name}} | |
| path: ${{github.workspace}}/TestResults/TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}-${{matrix.testSuite.name}}.trx | |
| test-results: | |
| name: Test results | |
| runs-on: ubuntu-latest | |
| # we want to wait for the `test` job to complete, but run regardless of whether it succeeds or fails | |
| # https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#example-not-requiring-successful-dependent-jobs | |
| if: ${{ !cancelled() }} | |
| needs: test | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Download results | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: osu-test-results-* | |
| merge-multiple: true | |
| - name: Add test results summary to workflow run | |
| uses: dorny/test-reporter@v3.0.0 | |
| with: | |
| name: Results | |
| path: "*.trx" | |
| reporter: dotnet-trx | |
| list-suites: 'failed' | |
| list-tests: 'failed' | |
| use-actions-summary: 'true' | |
| build-only-android: | |
| name: Build only (Android) | |
| runs-on: windows-2025-vs2026 | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup JDK 11 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: microsoft | |
| java-version: 11 | |
| - name: Install .NET 10.0.x | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props') }} | |
| restore-keys: ${{ runner.os }}-nuget- | |
| - name: Authenticate to GitHub Packages | |
| run: dotnet nuget update source winnerspiros-github --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text | |
| - name: Install .NET workloads | |
| run: dotnet workload install android | |
| - name: Compile | |
| run: dotnet build -c Debug osu.Android.slnf | |
| build-only-ios: | |
| name: Build only (iOS) | |
| runs-on: macos-26 | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install .NET 10.0.x | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "10.0.x" | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props') }} | |
| restore-keys: ${{ runner.os }}-nuget- | |
| - name: Authenticate to GitHub Packages | |
| run: dotnet nuget update source winnerspiros-github --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text | |
| # https://github.com/dotnet/macios/issues/19157 | |
| # https://github.com/actions/runner-images/issues/12758 | |
| - name: Use Xcode 26.5 | |
| run: | | |
| # Pin to Xcode 26.5 — the .NET iOS workload (net10.0_26.5) requires exactly Xcode 26.5. | |
| # Fix: MacOSX.sdk in Xcode 26.5 is a minimal stub. Replace it with a symlink to the | |
| # real versioned SDK found across Xcode installs. Real SDKs have hundreds of headers; | |
| # stubs have ≤1. | |
| PREFERRED_XCODE="/Applications/Xcode_26.5.app" | |
| REAL_SDK="" | |
| REAL_XCODE="" | |
| # Search ALL Xcode_26.x.app installs for versioned MacOSX[N].sdk. | |
| # Validate by usr/include header count: stubs ≤1 file, real SDKs have hundreds. | |
| for xapp in $(ls -d /Applications/Xcode_26.*.app 2>/dev/null | sort -rV); do | |
| sdk_dir="$xapp/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs" | |
| [ -d "$sdk_dir" ] || continue | |
| for sdk in $(ls "$sdk_dir" 2>/dev/null | grep '^MacOSX[0-9].*\.sdk$' | sort -rV); do | |
| cand="$sdk_dir/$sdk" | |
| hdr_count=$(ls "$cand/usr/include" 2>/dev/null | wc -l | tr -d ' ') | |
| if [ "${hdr_count:-0}" -gt 5 ]; then | |
| REAL_SDK="$cand" | |
| REAL_XCODE="$xapp" | |
| break 2 | |
| fi | |
| done | |
| done | |
| # Fallback: CommandLineTools | |
| if [ -z "$REAL_SDK" ]; then | |
| for sdk in $(ls /Library/Developer/CommandLineTools/SDKs 2>/dev/null | grep '^MacOSX[0-9].*\.sdk$' | sort -rV); do | |
| cand="/Library/Developer/CommandLineTools/SDKs/$sdk" | |
| hdr_count=$(ls "$cand/usr/include" 2>/dev/null | wc -l | tr -d ' ') | |
| if [ "${hdr_count:-0}" -gt 5 ]; then | |
| REAL_SDK="$cand" | |
| break | |
| fi | |
| done | |
| fi | |
| # Switch to preferred Xcode if it exists, otherwise the one that has the real SDK. | |
| if [ -d "$PREFERRED_XCODE" ]; then | |
| sudo xcode-select -switch "$PREFERRED_XCODE" | |
| elif [ -n "$REAL_XCODE" ]; then | |
| sudo xcode-select -switch "$REAL_XCODE" | |
| echo "Note: Xcode_26.5.app not found; using $REAL_XCODE for xcode-select" | |
| fi | |
| # Replace stub MacOSX.sdk in the active Xcode with a symlink to the real versioned SDK. | |
| if [ -n "$REAL_SDK" ]; then | |
| ACTIVE_DEV="$(xcode-select -p)" | |
| ACTIVE_SDKS_DIR="$ACTIVE_DEV/Platforms/MacOSX.platform/Developer/SDKs" | |
| MACOS_SDK="$ACTIVE_SDKS_DIR/MacOSX.sdk" | |
| # Resolve REAL_SDK to its canonical (symlink-free) path to prevent ELOOP errors. | |
| REAL_SDK_CANON=$(python3 -c "import os, sys; print(os.path.realpath(sys.argv[1]))" "$REAL_SDK" 2>/dev/null || echo "$REAL_SDK") | |
| sudo rm -rf "$MACOS_SDK" | |
| sudo ln -sfn "$REAL_SDK_CANON" "$MACOS_SDK" | |
| echo "Created MacOSX.sdk symlink -> $REAL_SDK_CANON" | |
| else | |
| echo "WARNING: no valid macOS SDK found; build may fail" | |
| fi | |
| - name: Install .NET Workloads | |
| run: dotnet workload install ios | |
| - name: Build | |
| run: dotnet build -c Debug osu.iOS.slnf |