From 4b1f22c13efad4eeabb7a9d59533baeec877ab86 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Thu, 11 Jun 2026 18:34:19 +0000 Subject: [PATCH] Close phase 3 package bridge and clarify wiring posture --- .../HyperTwistClassicCubeGameMode.cpp | 1 + .../HyperTwistClassicCubeOrbitPawn.cpp | 48 ++++++++++++ .../HyperTwistClassicCubeOrbitPawn.h | 6 ++ .../HyperTwistClassicCubeGameModeTest.cpp | 8 ++ ...NSIVE_RECONSTRUCTION_ROADMAP_2026-06-10.md | 16 +++- ...NVENTORY_AND_WIRING_SCHEDULE_2026-06-10.md | 11 ++- .../HyperTwist/FEATURE_REGISTRY.md | 2 +- .../HyperTwist/ROADMAP.md | 9 +++ .../Invoke-HyperTwistClassicCubePackage.ps1 | 78 +++++++++++++++++++ .../Launch-HyperTwistClassicCubePackage.ps1 | 47 +++++++++++ 10 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 scripts/Invoke-HyperTwistClassicCubePackage.ps1 create mode 100644 scripts/Launch-HyperTwistClassicCubePackage.ps1 diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeGameMode.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeGameMode.cpp index f2358af..b7d9b09 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeGameMode.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeGameMode.cpp @@ -56,6 +56,7 @@ AHyperTwistClassicCubeGameMode::AHyperTwistClassicCubeGameMode() PrimaryActorTick.bCanEverTick = true; PlayerControllerClass = AHyperTwistClassicCubePlayerController::StaticClass(); DefaultPawnClass = AHyperTwistClassicCubeOrbitPawn::StaticClass(); + CubeSpawnLocation = FVector(0.0f, 0.0f, 120.0f); } void AHyperTwistClassicCubeGameMode::BeginPlay() diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.cpp index d949615..5fcce85 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.cpp @@ -1,8 +1,11 @@ #include "HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.h" #include "Camera/CameraComponent.h" +#include "EngineUtils.h" #include "GameFramework/PlayerController.h" #include "GameFramework/SpringArmComponent.h" +#include "HyperTwistSimulation/HyperTwistClassicCubeActor.h" +#include "HyperTwistSimulation/HyperTwistClassicCubeGameMode.h" #include "InputCoreTypes.h" #include "Components/SceneComponent.h" @@ -31,6 +34,7 @@ void AHyperTwistClassicCubeOrbitPawn::BeginPlay() CurrentYawDegrees = InitialYawDegrees; CurrentPitchDegrees = InitialPitchDegrees; + RefreshOrbitFocusPointFromClassicCube(); if (SpringArm != nullptr) { SpringArm->TargetArmLength = FMath::Clamp(InitialArmLength, MinimumArmLength, MaximumArmLength); @@ -43,6 +47,13 @@ void AHyperTwistClassicCubeOrbitPawn::Tick(const float DeltaSeconds) Super::Tick(DeltaSeconds); static_cast(DeltaSeconds); + const FVector PreviousFocusPoint = OrbitFocusPoint; + RefreshOrbitFocusPointFromClassicCube(); + if (!OrbitFocusPoint.Equals(PreviousFocusPoint)) + { + ApplyOrbitTransform(); + } + APlayerController* PlayerController = Cast(GetController()); if (PlayerController == nullptr) { @@ -89,6 +100,43 @@ void AHyperTwistClassicCubeOrbitPawn::ApplyOrbitTransform() } } +void AHyperTwistClassicCubeOrbitPawn::RefreshOrbitFocusPointFromClassicCube() +{ + if (!bFollowActiveCubeActor) + { + return; + } + + if (const AHyperTwistClassicCubeActor* CubeActor = ResolveFocusCubeActor()) + { + OrbitFocusPoint = CubeActor->GetActorLocation(); + } +} + +AHyperTwistClassicCubeActor* AHyperTwistClassicCubeOrbitPawn::ResolveFocusCubeActor() const +{ + if (GetWorld() == nullptr) + { + return nullptr; + } + + if (const AHyperTwistClassicCubeGameMode* GameMode = + Cast(GetWorld()->GetAuthGameMode())) + { + if (GameMode->ActiveCubeActor != nullptr) + { + return GameMode->ActiveCubeActor; + } + } + + for (TActorIterator ActorIt(GetWorld()); ActorIt; ++ActorIt) + { + return *ActorIt; + } + + return nullptr; +} + bool AHyperTwistClassicCubeOrbitPawn::ShouldOrbitFromMouseInput() const { const APlayerController* PlayerController = Cast(GetController()); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.h index a4fdf2e..968a863 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSimulation/HyperTwistClassicCubeOrbitPawn.h @@ -4,6 +4,7 @@ #include "GameFramework/Pawn.h" #include "HyperTwistClassicCubeOrbitPawn.generated.h" +class AHyperTwistClassicCubeActor; class UCameraComponent; class USceneComponent; class USpringArmComponent; @@ -22,6 +23,9 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|ClassicCube|Camera") FVector OrbitFocusPoint = FVector::ZeroVector; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|ClassicCube|Camera") + bool bFollowActiveCubeActor = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|ClassicCube|Camera") float InitialArmLength = 360.0f; @@ -69,6 +73,8 @@ public: protected: void ApplyOrbitTransform(); + void RefreshOrbitFocusPointFromClassicCube(); + AHyperTwistClassicCubeActor* ResolveFocusCubeActor() const; bool ShouldOrbitFromMouseInput() const; float CurrentYawDegrees = 0.0f; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistClassicCubeGameModeTest.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistClassicCubeGameModeTest.cpp index 61e5d93..23c34e4 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistClassicCubeGameModeTest.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistClassicCubeGameModeTest.cpp @@ -35,6 +35,10 @@ bool FHyperTwistClassicCubeGameModeDefaultsTest::RunTest(const FString& Paramete ); TestTrue(TEXT("The classic cube game mode must still auto-create its HUD by default."), GameMode->bAutoCreateHud); TestTrue(TEXT("The classic cube game mode must still auto-spawn the cube actor by default."), GameMode->bAutoSpawnCubeActor); + TestTrue( + TEXT("The classic cube game mode must keep its default cube spawn above the generic validation-map floor."), + GameMode->CubeSpawnLocation.Z > 0.0f + ); return true; } @@ -85,6 +89,10 @@ bool FHyperTwistClassicCubeOrbitPawnDefaultsTest::RunTest(const FString& Paramet OrbitPawn->MinimumArmLength < OrbitPawn->InitialArmLength && OrbitPawn->InitialArmLength < OrbitPawn->MaximumArmLength ); + TestTrue( + TEXT("The orbit pawn must follow the active cube actor by default."), + OrbitPawn->bFollowActiveCubeActor + ); TestTrue( TEXT("The orbit pawn must support at least one mouse-orbit gesture by default."), OrbitPawn->bUseMiddleMouseOrbit || OrbitPawn->bUseRightMouseOrbitWithShift diff --git a/docs/ops/HYPERTWIST_COMPREHENSIVE_RECONSTRUCTION_ROADMAP_2026-06-10.md b/docs/ops/HYPERTWIST_COMPREHENSIVE_RECONSTRUCTION_ROADMAP_2026-06-10.md index 5800480..441280f 100644 --- a/docs/ops/HYPERTWIST_COMPREHENSIVE_RECONSTRUCTION_ROADMAP_2026-06-10.md +++ b/docs/ops/HYPERTWIST_COMPREHENSIVE_RECONSTRUCTION_ROADMAP_2026-06-10.md @@ -149,6 +149,8 @@ for the full 29-repo queue and per-repo wiring posture. - [x] Queue early Unreal command and shell-state pushes during bootstrap so the browser lane remains deterministic even if the JS runtime finishes loading slightly later than the CEF widget - [x] Add shell-verification coverage proving the authoritative shell, bootstrap script, and fallback runtime exist and no longer point directly at a TypeScript source entrypoint +**Phase 1 answer after repair:** the intended wiring set is complete on the accepted posture. The runtime/direct/sidecar lanes for `1A` through `1J` are present in current code and runtime manifests; support-only rows such as `modelviewer.dev`, `glTF-Sample-Viewer`, `space-opera`, `render-fidelity-tools`, and `@react-spring/types` remain intentionally subordinate or non-default rather than evidence of a missing gameplay integration. + **Estimated actions:** 40–60 per repo (UHT regen on first include) **Estimated time:** 1–2 days per repo (build-debug cycles) @@ -216,12 +218,18 @@ for the full 29-repo queue and per-repo wiring posture. **Goal:** A level you can launch, scramble, solve, and time. +**Phase 3 separation (current doctrine):** +- Code-owned runtime closure: first-party game mode, player controller, HUD, orbit camera, runtime cube spawn, and package-gate boot route. +- Packaged gate: real Windows package + launch proof. +- Editor-owned presentation closure: dedicated `.umap`, authored lights, and material polish. + ### 3A — Level Creation - [ ] Create `L_HyperTwist_ClassicTraining` (`.umap`) - [ ] Place `AHyperTwistClassicCubeActor` at world origin - [ ] Add directional light + ambient environment (basic, not immersive yet) - [ ] Add `WBP_HyperTwistGameHUD` to viewport (optional polish replacement for the first-party runtime HUD that already auto-adds to viewport) - [x] Add first-party orbit camera pawn with mouse-drag orbit and scroll-wheel zoom (`AHyperTwistClassicCubeOrbitPawn`) so camera interaction is owned in code before the `.umap` polish pass exists +- [x] Keep the source-owned runtime reachable on the generic validation map by spawning the cube above floor height and having the orbit pawn follow the active cube actor rather than assuming a hand-authored map origin ### 3B — Game Mode - [x] Create first-party `AHyperTwistClassicCubeGameMode` : `AGameModeBase` @@ -230,6 +238,10 @@ for the full 29-repo queue and per-repo wiring posture. - [x] Add an in-HUD button for "New Scramble" alongside the keyboard shortcut so restart does not depend on remembering `R` ### 3C — Build & Package Validation +- [x] Add source-controlled Windows helper scripts for package and smoke-launch validation: + - `scripts/Invoke-HyperTwistClassicCubePackage.ps1` + - `scripts/Launch-HyperTwistClassicCubePackage.ps1` +- [x] Define the temporary package-gate boot route explicitly as `/Engine/Maps/Templates/OpenWorld?game=/Script/UnrealHyperTwist.HyperTwistClassicCubeGameMode` until the dedicated `L_HyperTwist_ClassicTraining` map exists - [ ] Package `UnrealHyperTwist` for Windows (not just Editor build) - [ ] Launch packaged build on Windows host - [ ] Verify: cube visible, clickable, scramble applies, timer works, solve detected @@ -241,7 +253,7 @@ for the full 29-repo queue and per-repo wiring posture. ## Phase 4: Wire Solver into Training Pipeline -**Prerequisite:** Phase 1A (rob-twophase) + Phase 2 (renderer) +**Prerequisite:** Phase 1A (rob-twophase) + Phase 2 (renderer) + Phase 3C packaged gate GREEN ### 4A — Solver HUD Integration - [ ] Add "Hint" button to HUD @@ -266,7 +278,7 @@ for the full 29-repo queue and per-repo wiring posture. ## Phase 5: Speech Pipeline (STT + TTS) -**Prerequisite:** Phase 1B (freestyle) + Phase 1C (piper) +**Prerequisite:** Phase 1B (freestyle) + Phase 1C (piper) + Phase 3C packaged gate GREEN ### 5A — Voice Command Input - [ ] Add "Voice" button to HUD (or use freestyle global hotkey) diff --git a/docs/ops/HYPERTWIST_UNWIRED_REPO_INVENTORY_AND_WIRING_SCHEDULE_2026-06-10.md b/docs/ops/HYPERTWIST_UNWIRED_REPO_INVENTORY_AND_WIRING_SCHEDULE_2026-06-10.md index 2c76998..4206175 100644 --- a/docs/ops/HYPERTWIST_UNWIRED_REPO_INVENTORY_AND_WIRING_SCHEDULE_2026-06-10.md +++ b/docs/ops/HYPERTWIST_UNWIRED_REPO_INVENTORY_AND_WIRING_SCHEDULE_2026-06-10.md @@ -164,8 +164,17 @@ Current repaired note: - `1E`, `1G`, `1H`, `1I`, and `1J` now close through the authoritative `Content/Browser/index.html` shell, bundled-runtime upgrade path, committed clean-checkout fallback runtime, and embedded `UHyperTwistBrowserWidget` / bridge-object lane. - The browser queue is no longer blocked on retaining `dist/index.html`; build artifacts can be cleaned after validation because the authoritative shell remains runnable without them. +### Phase 1 wiring answer — 2026-06-11 + +- Yes: the intended Phase 1 wiring set is complete on the accepted posture. +- `1A` through `1J` are live across direct-link, IPC, retained-sidecar, and authoritative-browser-shell routes. +- Do not miscount intentionally subordinate or non-default rows as missing runtime wiring: + - `google/model-viewer/packages/modelviewer.dev` remains docs-only. + - `@react-spring/types` remains dev-types only. + - `KhronosGroup/glTF-Sample-Viewer`, `google/model-viewer/packages/space-opera`, and `google/model-viewer/packages/render-fidelity-tools` are retained support or sidecar lanes beneath the landed browser-viewer owner rather than missing standalone gameplay lanes. + --- ## Next Step -**Current next step after repair:** package-proof and presentation-proof work, not Phase 0. The repaired code lane already owns the authoritative browser shell, native-sidecar browser bridge, first-party classic-cube player controller, first-party orbit camera pawn, and first-party timer/HUD loop including GUI or keyboard scramble restart. The remaining best move is Windows packaged-build validation plus the level/material polish that still requires Unreal Editor content work. +**Current next step after repair:** package-proof and presentation-proof work, not Phase 0. The repaired code lane already owns the authoritative browser shell, native-sidecar browser bridge, first-party classic-cube player controller, first-party orbit camera pawn, active-cube camera follow, above-floor validation-map cube spawn, and first-party timer/HUD loop including GUI or keyboard scramble restart. The remaining best move is to run the real Windows packaged-build gate through `scripts/Invoke-HyperTwistClassicCubePackage.ps1`, then keep the dedicated `.umap` plus material/light polish as the separate Unreal Editor asset lane. diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md b/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md index 9a367dc..ef1aafc 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md @@ -161,7 +161,7 @@ repo. | Feature | Status | Primary authority | Notes | |---|---|---|---| | Native puzzle-state runtime | Implemented now | first-party runtime + landed donor packets | Core product identity. | -| Classic-cube playable runtime loop | Implemented now | first-party current code + landed timer/training substrate | First-party `AHyperTwistClassicCubeActor`, `AHyperTwistClassicCubeGameMode`, `AHyperTwistClassicCubePlayerController`, `AHyperTwistClassicCubeOrbitPawn`, and `UHyperTwistClassicCubeHUDWidget` now own the bounded classic-cube scramble/play/timer/solve loop with left-click, right-click, touch, middle-mouse drag orbit, scroll-wheel zoom, GUI or keyboard fresh-attempt restart, and solved-state submission in code. Packaged-build proof plus art/material/level polish remain separate next-step work. | +| Classic-cube playable runtime loop | Implemented now | first-party current code + landed timer/training substrate | First-party `AHyperTwistClassicCubeActor`, `AHyperTwistClassicCubeGameMode`, `AHyperTwistClassicCubePlayerController`, `AHyperTwistClassicCubeOrbitPawn`, and `UHyperTwistClassicCubeHUDWidget` now own the bounded classic-cube scramble/play/timer/solve loop with left-click, right-click, touch, middle-mouse drag orbit, scroll-wheel zoom, GUI or keyboard fresh-attempt restart, solved-state submission, active-cube orbit focus, and above-floor validation-map spawn in code. The current package-gate route is source-controlled through `scripts/Invoke-HyperTwistClassicCubePackage.ps1` and `scripts/Launch-HyperTwistClassicCubePackage.ps1` using the explicit classic-cube boot URL until the dedicated `.umap` lands. Packaged-build proof plus art/material/level polish remain separate next-step work. | | Classic-cubing semantic/runtime adapter | Implemented now | landed `cubing/cubing.js` packet | Live adapter family. | | Classic-cubing semantic, bridge, and `MPL`-boundary reference grounding | Implemented now | `cubing/cubing.js` retained boundary-sensitive lane + first-party current code | Current live `Classic Cubing Semantics and Runtime` reference side includes seven rewritten first-party contract/reference targets grounded in `cubing/cubing.js`: semantics, geometry, viewer adapter, device boundary, search contract, Melinda bridge, and explicit `MPL` compliance-boundary notes. This does not displace the landed `Phase 4R-A` first-party owner lane, the separate `cubing/twisty.js` replay shell lane, the separate `cubing/alg.js` parser/AST lane, or the explicit practical `MPL` path and notice-retention boundary. | | Seeded competition scramble workflow and lightweight scramble-operator shell adjuncts | Deep-source grounded retained | `cubing/cubing.js` retained lane + `cubing/mark3` / `cubing/scramble.cubing.net` successor evaluation | Source-backed successor surfaces sharpen competition-spec workflow and operator-shell expectations above the retained scramble and visualization seams, but they do not displace `cubing/cubing.js` or `cubing/twisty.js`; `scramble-display` remains comparison-only. | diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md index f45d162..fda96ca 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md @@ -42,6 +42,15 @@ Current consolidated milestone snapshot: not just a deferred idea; proof lives in the primary `22022` lane plus the fallback `22023` recovery path documented in `C:\HyperTwist\docs\ops\HYPERTWIST_REVERSE_SSH_WINDOWS_BUILD_LANE_VERIFICATION_2026-06-01.md` +- the classic-cube Phase 3 lane is now split explicitly into: + - code-owned runtime closure already present in first-party code + - a real packaged Windows gate that still must run green + - a separate editor-owned `.umap` / lights / materials polish lane +- the current packaged validation bridge for that lane is source-controlled via + `C:\HyperTwist\scripts\Invoke-HyperTwistClassicCubePackage.ps1` and + `C:\HyperTwist\scripts\Launch-HyperTwistClassicCubePackage.ps1` +- `Phase 4` and `Phase 5` widening should not proceed ahead of the classic-cube + packaged gate; they reopen only after that gate is green - the canonical HyperTwist repo-row portfolio is now treated as `75` rows, not `71` - currently implemented rows are now `35`, not `20` diff --git a/scripts/Invoke-HyperTwistClassicCubePackage.ps1 b/scripts/Invoke-HyperTwistClassicCubePackage.ps1 new file mode 100644 index 0000000..c950563 --- /dev/null +++ b/scripts/Invoke-HyperTwistClassicCubePackage.ps1 @@ -0,0 +1,78 @@ +param( + [string]$ProjectRoot = 'C:\HyperTwist', + [string]$ArchiveDirectory = 'C:\HyperTwist\packaged\classic-cube', + [ValidateSet('Development', 'Shipping')] + [string]$Configuration = 'Development', + [string]$CookMap = '/Engine/Maps/Templates/OpenWorld', + [switch]$CleanArchive, + [switch]$SkipBuild, + [switch]$SkipLaunch +) + +$ErrorActionPreference = 'Stop' + +$RunUatPath = 'C:\Program Files\Epic Games\UE_5.7\Engine\Build\BatchFiles\RunUAT.bat' +$UProjectPath = Join-Path $ProjectRoot 'UnrealHyperTwist\UnrealHyperTwist.uproject' +$LaunchScriptPath = Join-Path $ProjectRoot 'scripts\Launch-HyperTwistClassicCubePackage.ps1' +$ClassicCubeBootUrl = "$CookMap?game=/Script/UnrealHyperTwist.HyperTwistClassicCubeGameMode" + +if (-not (Test-Path $RunUatPath)) +{ + throw "RunUAT was not found at '$RunUatPath'." +} + +if (-not (Test-Path $UProjectPath)) +{ + throw "UnrealHyperTwist project file was not found at '$UProjectPath'." +} + +if ($CleanArchive -and (Test-Path $ArchiveDirectory)) +{ + Remove-Item -LiteralPath $ArchiveDirectory -Recurse -Force +} + +New-Item -ItemType Directory -Force -Path $ArchiveDirectory | Out-Null + +$RunUatArguments = @( + 'BuildCookRun', + "-project=$UProjectPath", + '-noP4', + '-platform=Win64', + "-clientconfig=$Configuration", + '-cook', + '-stage', + '-package', + '-pak', + '-archive', + "-archivedirectory=$ArchiveDirectory", + "-map=$CookMap", + '-unattended', + '-utf8output' +) + +if (-not $SkipBuild) +{ + $RunUatArguments += '-build' +} + +Write-Host "Packaging HyperTwist classic-cube validation lane to '$ArchiveDirectory'..." +& $RunUatPath @RunUatArguments + +if ($LASTEXITCODE -ne 0) +{ + throw "RunUAT packaging failed with exit code $LASTEXITCODE." +} + +if (-not $SkipLaunch) +{ + if (-not (Test-Path $LaunchScriptPath)) + { + throw "Launch script was not found at '$LaunchScriptPath'." + } + + & $LaunchScriptPath -PackageRoot $ArchiveDirectory -MapUrl $ClassicCubeBootUrl + if ($LASTEXITCODE -ne 0) + { + throw "Packaged classic-cube smoke launch failed with exit code $LASTEXITCODE." + } +} diff --git a/scripts/Launch-HyperTwistClassicCubePackage.ps1 b/scripts/Launch-HyperTwistClassicCubePackage.ps1 new file mode 100644 index 0000000..1b93f61 --- /dev/null +++ b/scripts/Launch-HyperTwistClassicCubePackage.ps1 @@ -0,0 +1,47 @@ +param( + [string]$PackageRoot = 'C:\HyperTwist\packaged\classic-cube', + [string]$MapUrl = '/Engine/Maps/Templates/OpenWorld?game=/Script/UnrealHyperTwist.HyperTwistClassicCubeGameMode', + [int]$SmokeSeconds = 10, + [int]$ResX = 1600, + [int]$ResY = 900, + [switch]$KeepRunning +) + +$ErrorActionPreference = 'Stop' + +$CandidateExecutablePaths = @( + (Join-Path $PackageRoot 'Windows\UnrealHyperTwist.exe'), + (Join-Path $PackageRoot 'WindowsNoEditor\UnrealHyperTwist.exe'), + (Join-Path $PackageRoot 'UnrealHyperTwist.exe') +) + +$ExecutablePath = $CandidateExecutablePaths | Where-Object { Test-Path $_ } | Select-Object -First 1 +if ($null -eq $ExecutablePath) +{ + throw "No packaged UnrealHyperTwist executable was found beneath '$PackageRoot'." +} + +$ArgumentList = @( + $MapUrl, + "-ResX=$ResX", + "-ResY=$ResY", + '-windowed', + '-log' +) + +Write-Host "Launching packaged classic-cube validation lane from '$ExecutablePath'..." +$Process = Start-Process -FilePath $ExecutablePath -ArgumentList $ArgumentList -PassThru +Start-Sleep -Seconds $SmokeSeconds + +$Process.Refresh() +if ($Process.HasExited) +{ + throw "Packaged classic-cube executable exited early with code $($Process.ExitCode)." +} + +Write-Host "Packaged classic-cube smoke launch succeeded (PID $($Process.Id))." +if (-not $KeepRunning) +{ + Stop-Process -Id $Process.Id -Force + Write-Host 'Stopped packaged classic-cube smoke process after successful launch validation.' +}