diff --git a/.gitignore b/.gitignore index b07c8325..86939c89 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,14 @@ __pycache__/ .env.* *.pem *.key + +# Personal feature-test launchers and historical setup reports. +/BUILD-MULTIPLAYER-TEST.bat +/PLAY-MULTIPLAYER-10-INSTANCES.bat +/PLAY-MULTIPLAYER-2-INSTANCES.bat +/PLAY-MULTIPLAYER-MENU.bat +/PLAY-MULTIPLAYER-SMOOTH-2-INSTANCES.bat +/PLAY-SESSION-MARKER.bat +/tools/launch_customiser_test.bat +/Build-SessionMarker.ps1 +/SETUP-PROVENANCE.json diff --git a/BUILD-MULTIPLAYER-TEST.bat b/BUILD-MULTIPLAYER-TEST.bat deleted file mode 100644 index 6b93f068..00000000 --- a/BUILD-MULTIPLAYER-TEST.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -setlocal -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\build-multiplayer-test.ps1" -if errorlevel 1 pause diff --git a/Build-SessionMarker.ps1 b/Build-SessionMarker.ps1 deleted file mode 100644 index f58fd89b..00000000 --- a/Build-SessionMarker.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -param([switch]$StageOnly, [string]$DependencyTargetDirectory = (Join-Path $PSScriptRoot 'target')) -$ErrorActionPreference = 'Stop' -$privateDirectory = Join-Path $PSScriptRoot '.local/session-marker' -$buildDirectory = Join-Path $privateDirectory 'build' -$artifact = Join-Path $buildDirectory 'skate3rust-session-marker.exe' -$destination = Join-Path $privateDirectory 'skate3-session-marker.exe' -Push-Location $PSScriptRoot -$previousFlags = $env:CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS -try { - New-Item -ItemType Directory -Force -Path $buildDirectory | Out-Null - if (-not $StageOnly) { - $env:CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS = '-C target-feature=+crt-static' - # Dependencies may use a shared cache. The linker writes this task's - # artifact directly, never staging the cache's generic skate3rust.exe. - & cargo rustc --release --locked --target x86_64-pc-windows-msvc ` - --target-dir $DependencyTargetDirectory -p skate-game --no-default-features ` - --bin skate3rust -- -C extra-filename=-session-marker ` - -o (Join-Path $buildDirectory 'skate3rust.exe') - if ($LASTEXITCODE -ne 0) { throw 'Session-marker build failed.' } - } - $bytes = [System.IO.File]::ReadAllBytes($artifact) - $text = [System.Text.Encoding]::ASCII.GetString($bytes) - foreach ($required in @('--start-paused', 'session_marker/effect.wgsl', 'Session marker return rejected')) { - if (-not $text.Contains($required)) { throw "Wrong session-marker artifact: missing $required" } - } - Copy-Item -LiteralPath $artifact -Destination $destination -Force - $hash = (Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash - if ($hash -ne (Get-FileHash -LiteralPath $artifact -Algorithm SHA256).Hash) { - throw 'Staged executable hash mismatch.' - } - @{ executable = $destination; sha256 = $hash; source = $PSScriptRoot; - revision = (& git rev-parse HEAD); staticChecks = 'CLI, marker shader, return path' } | - ConvertTo-Json | Set-Content -LiteralPath (Join-Path $privateDirectory 'build-manifest.json') -Encoding UTF8 - Write-Host "Ready for manual launch: $destination" - Write-Host "SHA256: $hash" -} finally { - $env:CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS = $previousFlags - Pop-Location -} diff --git a/Launch.ps1 b/Launch.ps1 index ad0080e0..02ebffb2 100644 --- a/Launch.ps1 +++ b/Launch.ps1 @@ -6,7 +6,7 @@ try { if (-not (Test-Path -LiteralPath $executable)) { throw 'Game is not built. Run BUILD.bat first.' } New-Item -ItemType Directory -Path (Join-Path $PSScriptRoot 'logs') -Force | Out-Null $log = Join-Path $PSScriptRoot ('logs/game-' + (Get-Date -Format 'yyyyMMdd-HHmmss') + '.log') - Write-Host 'Starting imported skater project. Use your XInput controller; Esc opens difficulty/graphics/pause settings.' + Write-Host 'Starting Skate 3 Rust Engine. Use your XInput controller; Esc opens difficulty/graphics/pause settings.' Write-Host "Log: $log" $errorLog = [System.IO.Path]::ChangeExtension($log, 'stderr.log') $assetArgument = '"' + (Join-Path $PSScriptRoot 'assets') + '"' diff --git a/PLAY-MULTIPLAYER-10-INSTANCES.bat b/PLAY-MULTIPLAYER-10-INSTANCES.bat deleted file mode 100644 index b95195fa..00000000 --- a/PLAY-MULTIPLAYER-10-INSTANCES.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -setlocal -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\launch-multiplayer-test.ps1" -Players 10 %* -if errorlevel 1 pause diff --git a/PLAY-MULTIPLAYER-2-INSTANCES.bat b/PLAY-MULTIPLAYER-2-INSTANCES.bat deleted file mode 100644 index 981bad2a..00000000 --- a/PLAY-MULTIPLAYER-2-INSTANCES.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -setlocal -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\launch-multiplayer-test.ps1" %* -if errorlevel 1 pause diff --git a/PLAY-MULTIPLAYER-MENU.bat b/PLAY-MULTIPLAYER-MENU.bat deleted file mode 100644 index ab5b3a19..00000000 --- a/PLAY-MULTIPLAYER-MENU.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -setlocal -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\launch-multiplayer-test.ps1" -MenuOnly %* -if errorlevel 1 pause diff --git a/PLAY-MULTIPLAYER-SMOOTH-2-INSTANCES.bat b/PLAY-MULTIPLAYER-SMOOTH-2-INSTANCES.bat deleted file mode 100644 index 981bad2a..00000000 --- a/PLAY-MULTIPLAYER-SMOOTH-2-INSTANCES.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -setlocal -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\launch-multiplayer-test.ps1" %* -if errorlevel 1 pause diff --git a/PLAY-SESSION-MARKER.bat b/PLAY-SESSION-MARKER.bat deleted file mode 100644 index 728d57dc..00000000 --- a/PLAY-SESSION-MARKER.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -setlocal -cd /d "%~dp0" -set "MARKER_DIR=%~dp0.local\session-marker" -if not exist "%MARKER_DIR%\skate3-session-marker.exe" ( - echo Missing private session-marker build. See docs\session-markers.md. - pause - exit /b 1 -) -if not defined SKATE3_ASSETS ( - if exist "%MARKER_DIR%\assets.path" set /p "SKATE3_ASSETS="<"%MARKER_DIR%\assets.path" -) -if not defined SKATE3_ASSETS ( - echo Set SKATE3_ASSETS to your extracted assets directory. - pause - exit /b 1 -) -set "SKATE3_SESSION_MARKER_OVERLAY=%MARKER_DIR%\overlay" -"%MARKER_DIR%\skate3-session-marker.exe" --assets "%SKATE3_ASSETS%" --start-paused %* -if errorlevel 1 pause diff --git a/README.md b/README.md index dee99a0b..a5cd2a0d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ starts University. No Blender, Python or Rust installation is needed. ISO extraction needs internet access. The first conversion can take a while. Use an XInput controller to play. Escape opens graphics, difficulty and map -settings. Loading another map restarts the game session. +settings. Maps can be switched without restarting the game. **Skate 3 assets are not included.** Your converted files stay in `%LOCALAPPDATA%/Skate3RustEngine`. diff --git a/SETUP-PROVENANCE.json b/SETUP-PROVENANCE.json deleted file mode 100644 index c4457fad..00000000 --- a/SETUP-PROVENANCE.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "archives": { - "crates (1).zip": "d039af756525a3071178c366bf6d44a8b426f320e28c414cb34449240be89bd9", - "assets.zip": "5127c4608742c4c2f574edb128829c6cc22f02cf957b9ade2fae6c56e5b95f7b" - }, - "setup_changes": [ - "Added missing Cargo workspace using installed Bevy 0.18.1 and Rust 2024 edition.", - "Selected supplied Easy profile at both game startup load sites.", - "Added build, staging and launch scripts." - ], - "animation_source": "Supplied assets.zip; no assets from the previous clone required.", - "validation": { - "build": "passed (56 supplied-source warnings)", - "startup": "GAME_CHARACTER_READY bones=35", - "skin_bones_matched": 35, - "decoded_animation_clips": 487, - "runtime_issue": "Unsupported MotionGraph Behavior AddRunoutAttribs (behavior 86); no bypass applied", - "gameplay_controls": "user-driven; no injected input or automated visual test" - }, - "modified_imported_files": [ - "crates/skate-game/src/main.rs", - "crates/skate-game/src/physics.rs" - ] -} diff --git a/docs/archive-crates-3-merge.md b/docs/archive-crates-3-merge.md index e0d3c2bd..f971d24c 100644 --- a/docs/archive-crates-3-merge.md +++ b/docs/archive-crates-3-merge.md @@ -1,6 +1,6 @@ # Merge of supplied crates (3).zip -Source: `C:/Users/Daddy/Downloads/crates (3).zip`, SHA256 +Source: `crates (3).zip`, SHA256 `beb4aabf83fe706b6678d78f4af10c85a6467e0fef1c3c2a8d92e922405134ad`. The archive contains a source snapshot without Git history. It was compared with the initial import (`a47da5b`), current HEAD (`0909877`), and the working tree. diff --git a/docs/climbing.md b/docs/climbing.md index fd192a1b..6ecba858 100644 --- a/docs/climbing.md +++ b/docs/climbing.md @@ -30,12 +30,8 @@ Optional asset: `assets/private/custom/climbing.json`. Missing assets leave stoc The JSON contains version 1, two named clips (`reach`, `mantle`), FPS, joint names, parent indices, and local SQT samples. Sample order is scale XYZ, quaternion XYZW, translation XYZ. It uses native animation bone axes, not raw Blender matrix-basis channels. It does not modify the stock bank decoder or its SHA-bound cache format. -The 60 FPS clips come from the reviewed Mixamo retargets: - -- `C:/Users/Daddy/Documents/skate3-climbing-retarget/stand-to-freehang/stand_to_freehang_skater.blend` -- `C:/Users/Daddy/Documents/skate3-climbing-retarget/climbing_skater.blend` - -Rebake using Blender's background mode and `C:/Users/Daddy/Documents/skate3-climbing-retarget/runtime-export/export_climbing.py`. This script reads the masters without saving changes and derives the exact bone conversion from `assets/private/skater.glb`. Extraction and Blender tooling remain outside the game project. +Custom clips and their authoring tools are not distributed. Export clips using the +schema above and the native bone axes from your prepared skater rig. ## Verification diff --git a/docs/multiplayer-interpolation.md b/docs/multiplayer-interpolation.md index c362c409..1360d5d3 100644 --- a/docs/multiplayer-interpolation.md +++ b/docs/multiplayer-interpolation.md @@ -1,6 +1,6 @@ # Remote-player visual interpolation -Use **PLAY-MULTIPLAYER-SMOOTH-2-INSTANCES.bat** for the new build. It starts two connected clients on University from `bin/multiplayer-interpolation-v4`; existing running games and the previous staged build are untouched. The launcher also accepts `-Players 10` and `-TwoControllers`. +Use `scripts/launch-multiplayer-test.ps1` with your prepared `-AssetRoot` for two connected local clients. Add `-Players 10` or `-TwoControllers` as needed. See [multiplayer-test.md](multiplayer-test.md) for build instructions. Both peers must use this build: timestamped state uses protocol magic `SK8NET04`. The previous v2 executable cannot join it. Steam remains optional and has its matching helper beside this build. @@ -49,4 +49,4 @@ The game and Steam helper were built and staged without launching either. User t - [Glenn Fiedler: Snapshot Interpolation](https://github.com/mas-bandwidth/gafferongames/blob/main/content/post/snapshot_interpolation.md) — buffered interpolation, Hermite curves, quaternion SLERP and extrapolation limitations. - [Mirror's snapshot interpolation implementation](https://github.com/MirrorNetworking/Mirror/blob/master/Assets/Mirror/Core/SnapshotInterpolation/SnapshotInterpolation.cs) — source timelines, jitter-based buffer adjustment and gentle catch-up/slowdown. -Rebuild with `powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/build-multiplayer-test.ps1 -OutputDirectory bin/multiplayer-interpolation-v4`. +Rebuild with `powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/build-multiplayer-test.ps1`. diff --git a/docs/multiplayer-test.md b/docs/multiplayer-test.md index 67dbb37c..e2ee2912 100644 --- a/docs/multiplayer-test.md +++ b/docs/multiplayer-test.md @@ -1,4 +1,18 @@ -> Latest build: **PLAY-MULTIPLAYER-MENU.bat**, staged in `bin/multiplayer-lobbies`. It opens University offline. Esc > Multiplayer provides public Steam hosting, a paginated lobby browser and joining by stable numeric lobby code. **PLAY-MULTIPLAYER-SMOOTH-2-INSTANCES.bat** uses this same build for the automatic two-player local test. Earlier performance results below are historical. +# Multiplayer development + +Build the game and Steam relay with `./scripts/build-multiplayer-test.ps1`. +The output is staged in `bin/multiplayer`. + +Open the menu on a prepared installation: + +```powershell +./scripts/launch-multiplayer-test.ps1 -AssetRoot -MenuOnly +``` + +Use `-Players 2` through `-Players 10` instead of `-MenuOnly` for local clients, +`-TwoControllers` for XInput slots 0 and 1, and `-MapPath ` to select +a map. The default map is University beside the supplied assets directory. +`SKATE3_ASSETS` can supply the asset directory instead of `-AssetRoot`. ## Steam lobby test (current build) @@ -10,13 +24,13 @@ Steam lobby-owner reassignment triggers automatic transport rerouting and a fres Twenty nongame tests passed, covering bounded discovery messages, Unicode labels, repeated ten-player session migration, local-state preservation, stale departed-host packets, production loopback packets, interpolation and physical contact. Release game/helper builds are staged. No game or Steam process was launched for this verification. Real public discovery, Steam relay connectivity and provider-driven migration still need the multi-PC test above. -> New visual interpolation test: [multiplayer-interpolation.md](multiplayer-interpolation.md). Use its separate launcher for timestamped protocol v3. This page retains the original optimisation results. +> New visual interpolation test: [multiplayer-interpolation.md](multiplayer-interpolation.md). It describes timestamped protocol v3. This page retains the original optimisation results. # Multiplayer optimisation / next test -Run `PLAY-MULTIPLAYER-2-INSTANCES.bat`. It launches two connected games on **University** using the same ten-player session implementation as online play. Player A hosts; B uses an unavailable outfit identifier and spawns two metres away. Click a window to control that player with raw XInput. `-TwoControllers` assigns slots 0 and 1. Steam is only initialized when choosing Steam multiplayer from the menu. +Run the launch script with `-Players 2`. It launches two connected games on **University** using the same ten-player session implementation as online play. Player A hosts; B uses an unavailable outfit identifier and spawns two metres away. Click a window to control that player with raw XInput. `-TwoControllers` assigns slots 0 and 1. Steam is only initialized when choosing Steam multiplayer from the menu. -`PLAY-MULTIPLAYER-10-INSTANCES.bat` launches all ten local game windows. This also tests rendering and physics load on one PC; it is substantially heavier than one game with nine online players. Alternatively pass `-Players 3` through `-Players 10` to the two-instance launcher. Override the map with `-MapPath "C:/path/map.skate"`. +Use `-Players 10` to launch ten local windows. This is substantially heavier than one game with nine online players. The HUD shows player count, application upload/download in decimal kB/s, worst current direct-link ping, stale packets, missing delta baselines and send errors. Steam sessions additionally show SDK transfer rates, worst link quality estimate, queue time and adapter drops/errors. Host ping is to guests; guest ping is to the host, not the full guest-to-guest path. Sequence gaps are not reported as packet loss because distance throttling intentionally skips source updates. @@ -44,7 +58,7 @@ Physical collisions still use local ownership with temporary remote proxies, not ## Verification -Release game and relay built and staged using `BUILD-MULTIPLAYER-TEST.bat`, which launches neither. Ten nongame tests passed: existing wire validation, real UDP, quantisation/deltas, truncation, full/mismatched admission, spoof rejection, disconnect/rejoin and a real core-solver contact using the last of nine 33-body remote blocks. The launcher was parsed without execution. +Release game and relay built and staged using `scripts/build-multiplayer-test.ps1`, which launches neither. Ten nongame tests passed: existing wire validation, real UDP, quantisation/deltas, truncation, full/mismatched admission, spoof rejection, disconnect/rejoin and a real core-solver contact using the last of nine 33-body remote blocks. The launcher was parsed without execution. `cargo run --release --target x86_64-pc-windows-msvc -p skate-net --example lobby_audit --locked` runs the production codec/session with ten simulated peers for 30 seconds per scenario, measuring the final 25 seconds. It introduces independent 30–90 ms delay per link, reorder and optional 5% loss. The near scenario changes every body and anchor continuously. It checks all ten memberships, bounded packet sizes, replication freshness, and zero invalid packets/missing acknowledged baselines. It does not run a game, the renderer, Steam or a real WAN. @@ -68,8 +82,8 @@ the loader cancels pending discovery/join requests and refreshes the map fingerp and physics schema before another session starts. Both players need matching maps. The build helper links into its own staging directory while reusing the dependency -cache. All multiplayer BAT launchers use `bin/multiplayer`. A prepared local combined -customiser asset view and session-marker overlay are reused when available. +cache. Supply your prepared asset view through `-AssetRoot`. If using a separate +session-marker overlay, set `SKATE3_SESSION_MARKER_OVERLAY` before launching. The merged game and Steam relay were compiled without launching either. Actual Steam connectivity still needs two PCs with separate Steam accounts. Remote clothing diff --git a/docs/session-markers.md b/docs/session-markers.md index 24bc8e10..9ede7a1d 100644 --- a/docs/session-markers.md +++ b/docs/session-markers.md @@ -1,7 +1,6 @@ # Native session markers -`PLAY-SESSION-MARKER.bat` runs this task's private executable and original HUD -overlay, starting paused. Resume, hold **LB**, press **D-pad Down** to place; +With the original HUD overlay prepared, hold **LB**, press **D-pad Down** to place; hold **LB + D-pad Up** to return. These are the original `input.cfg` bindings (`SessionMarkerSet`, `SessionMarkerUse`), including pressed versus held behavior. An unset marker cannot return. Releasing cancels the hold. A completed hold does @@ -11,7 +10,7 @@ cancel an active return and require releasing LB before accepting another one. The branch includes map-transition baseline `4a92ad1`, cherry-picked as `1d89d85`. No game, recomp, controller harness or GPU gameplay validation was launched for -this task. The launcher is for the user's manual validation. +this task. Gameplay validation remains manual. ## Original evidence @@ -115,14 +114,9 @@ Release compilation passed with the existing static-CRT Windows target flags: cargo build --release --locked --target x86_64-pc-windows-msvc -p skate-game --no-default-features ``` -The first staged executable was subsequently found to be an older build from -the shared target directory: it contained neither `--start-paused` nor the -marker shader. The compile result did not verify the staged artifact. That -executable has been superseded by `.local/session-marker/skate3-session-marker.exe`. -`Build-SessionMarker.ps1` now links directly into the task's private build -directory with a distinct artifact name, checks the CLI/marker strings without -executing it, and verifies the staged SHA-256. Use that script for future builds; -`-DependencyTargetDirectory` can select an existing dependency cache. +When sharing a Cargo target directory across worktrees, link the final executable +to a checkout-specific output path and verify that artifact before staging it. +A previous build copied a stale executable from the shared cache. Four standalone hold-state tests passed (cancellation/latching, unset/nearby/ blocked returns and tail, distance ramp, actual distance-dependent trigger ticks). @@ -131,7 +125,7 @@ and validation. Original HUD manifest counts, triangle structure and every RGBA payload size passed data checks. These checks initialize no game or GPU device. A CPU-only rendering of the compiled HUD was inspected for font layering, icon size and the three-row panel. The corrected release was rebuilt and staged -through `Build-SessionMarker.ps1`; its artifact/hash checks passed. +with artifact/hash checks. The subsequent shadow/panel adjustment changes only the extracted HUD overlay; the same executable reads it on launch. Offline checks verified all output hashes, unchanged foreground/icon bytes, unchanged shadow footprint and diff --git a/scripts/launch-multiplayer-test.ps1 b/scripts/launch-multiplayer-test.ps1 index 76ee6a9a..b25d5afc 100644 --- a/scripts/launch-multiplayer-test.ps1 +++ b/scripts/launch-multiplayer-test.ps1 @@ -1,16 +1,12 @@ -param([switch]$MenuOnly, [string]$MapPath = '', [switch]$TwoControllers, [ValidateRange(2,10)][int]$Players = 2, [string]$BuildDirectory = 'bin/multiplayer') +param([string]$AssetRoot = $env:SKATE3_ASSETS, [switch]$MenuOnly, [string]$MapPath = '', [switch]$TwoControllers, [ValidateRange(2,10)][int]$Players = 2, [string]$BuildDirectory = 'bin/multiplayer') $ErrorActionPreference = 'Stop' $instanceCount = if ($MenuOnly) { 1 } else { $Players } $workspace = Split-Path -Parent $PSScriptRoot $binary = Join-Path (Join-Path $workspace $BuildDirectory) 'skate3-multiplayer.exe' -$installation = 'C:/Users/Daddy/AppData/Local/Skate3RustEngine/installations/957f4f78db9b4f59959f10dff8ff6a84' -$assets = Join-Path $installation 'assets' -# Reuse the combined character asset view when this checkout has one prepared. -$combinedAssets = Join-Path $workspace '.local/combined-customiser/assets' -if (Test-Path -LiteralPath (Join-Path $combinedAssets 'private/game.json')) { $assets = $combinedAssets } -$markerOverlay = Join-Path $workspace '.local/session-marker/overlay' -if (Test-Path -LiteralPath (Join-Path $markerOverlay 'hud.json')) { $env:SKATE3_SESSION_MARKER_OVERLAY = $markerOverlay } -if (-not (Test-Path -LiteralPath $binary)) { throw 'Build missing. Run BUILD-MULTIPLAYER-TEST.bat first.' } +if (-not $AssetRoot) { $AssetRoot = Join-Path $workspace 'assets' } +$assets = (Resolve-Path -LiteralPath $AssetRoot).Path +$installation = Split-Path -Parent $assets +if (-not (Test-Path -LiteralPath $binary)) { throw 'Build missing. Run scripts/build-multiplayer-test.ps1 first.' } if (-not (Test-Path -LiteralPath (Join-Path $assets 'private/game.json'))) { throw 'Prepared game assets are missing. No installer or conversion will be started.' } if (-not $MapPath) { $MapPath = Join-Path $installation 'maps/University.skate' } $MapPath = (Resolve-Path -LiteralPath $MapPath).Path diff --git a/tools/launch_customiser_test.bat b/tools/launch_customiser_test.bat deleted file mode 100644 index bd3a6972..00000000 --- a/tools/launch_customiser_test.bat +++ /dev/null @@ -1,27 +0,0 @@ -@echo off -setlocal -cd /d "%~dp0" -if not exist "%~dp0skate3rust-customiser-v4.exe" ( - echo The V4 customiser executable is missing. - pause - exit /b 1 -) -if not exist "%~dp0assets\private\customisation\library-v3.json" ( - echo The prepared character library is missing. - pause - exit /b 1 -) -echo Skate 3 Character Customiser V4 -echo Open Escape / Start, then Character customiser. -echo Browse with arrows / D-pad. Change with left-right or the minus-plus buttons. -echo Right stick rotates your character. -echo Type to search an item list. Escape / B goes back. Done saves and resumes. -echo Diagnostic output: customiser-v4-session.log -"%~dp0skate3rust-customiser-v4.exe" --assets "%~dp0assets" --map "%~dp0maps\SkateSchool.skate" > "%~dp0customiser-v4-session.log" 2>&1 -set "skate_customiser_exit=%errorlevel%" -if not "%skate_customiser_exit%"=="0" ( - echo The test exited with code %skate_customiser_exit%. - echo See %~dp0customiser-v4-session.log - pause -) -exit /b %skate_customiser_exit%