diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 1ed3986..e5c15e4 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -12800,6 +12800,15 @@ UHyperTwistCoachDashboardWidget::GetDisplayedControlInputReadinessInspectSurface return Surface; } +FHyperTwistTrainingControlSettingsOwnershipInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedControlSettingsOwnershipInspectSurface() const +{ + FHyperTwistTrainingControlSettingsOwnershipInspectSurface Surface = + UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurface(); + Surface.Headline = TEXT("Control settings ownership"); + return Surface; +} + FHyperTwistTrainingCoachDashboardGuidanceRationaleInspectSurface UHyperTwistCoachDashboardWidget::GetDisplayedGuidanceRationaleInspectSurface() const { @@ -19136,6 +19145,24 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt() TEXT("CoachControlInputReadinessDetail"), 8 ); + ControlSettingsOwnershipHeaderTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow( + WidgetTree, + RootLayout, + TEXT("CoachControlSettingsOwnershipHeader"), + 2 + ); + ControlSettingsOwnershipStatusTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow( + WidgetTree, + RootLayout, + TEXT("CoachControlSettingsOwnershipStatus"), + 2 + ); + ControlSettingsOwnershipDetailTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow( + WidgetTree, + RootLayout, + TEXT("CoachControlSettingsOwnershipDetail"), + 8 + ); RecognitionStatusTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow( WidgetTree, RootLayout, @@ -30207,6 +30234,23 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() ControlInputReadinessDetailTextBlock->SetText( FText::FromString(ControlInputSurface.DetailLine)); } + const FHyperTwistTrainingControlSettingsOwnershipInspectSurface ControlSettingsSurface = + GetDisplayedControlSettingsOwnershipInspectSurface(); + if (ControlSettingsOwnershipHeaderTextBlock != nullptr) + { + ControlSettingsOwnershipHeaderTextBlock->SetText( + FText::FromString(TEXT("[Control Settings Ownership]"))); + } + if (ControlSettingsOwnershipStatusTextBlock != nullptr) + { + ControlSettingsOwnershipStatusTextBlock->SetText( + FText::FromString(ControlSettingsSurface.StatusLine)); + } + if (ControlSettingsOwnershipDetailTextBlock != nullptr) + { + ControlSettingsOwnershipDetailTextBlock->SetText( + FText::FromString(ControlSettingsSurface.DetailLine)); + } if (VerificationStatusTextBlock != nullptr) { DisplayedVerificationStatusLine = CachedCoachPanelState.VerificationStatusLine; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp index 8bb4435..88f7e39 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp @@ -4,7 +4,11 @@ #include "HyperTwistBrowser/HyperTwistBrowserWidget.h" #include "HyperTwistSimulation/HyperTwistClassicCubePlayerController.h" #include "HyperTwistSimulation/HyperTwistVirtual3333ProjectionPlayerController.h" +#include "HyperTwistTraining/HyperTwistTrainingImmersiveEnvironmentLibrary.h" +#include "HyperTwistTraining/HyperTwistTrainingMagic120CellLibrary.h" +#include "HyperTwistTraining/HyperTwistTrainingMagicCube5DLibrary.h" #include "HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h" +#include "HyperTwistTraining/HyperTwistTrainingViewerLibrary.h" #include "Misc/ConfigCacheIni.h" namespace HyperTwistTrainingPanelWidgetInternal @@ -22,6 +26,30 @@ namespace HyperTwistTrainingPanelWidgetInternal return bValue ? TEXT("yes") : TEXT("no"); } + FString DescribeReadyState(const bool bValue) + { + return bValue ? TEXT("ready") : TEXT("not ready"); + } + + bool TryFindViewerEditorToolById( + const FHyperTwistTrainingViewerReferenceBundle& Bundle, + const FString& ToolId, + FHyperTwistTrainingViewerEditorToolReference& OutTool + ) + { + for (const FHyperTwistTrainingViewerEditorToolReference& Tool : Bundle.EditorTools) + { + if (Tool.ToolId == ToolId && Tool.IsStructurallyValid()) + { + OutTool = Tool; + return true; + } + } + + OutTool = FHyperTwistTrainingViewerEditorToolReference(); + return false; + } + bool AxisConfigEntriesContainToken( const TArray& AxisConfigEntries, const TCHAR* Token @@ -896,6 +924,163 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface( return Surface; } +FHyperTwistTrainingControlSettingsOwnershipInspectSurface +UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurface() const +{ + FHyperTwistTrainingControlSettingsOwnershipInspectSurface Surface; + Surface.Headline = TEXT("Control settings ownership"); + + const FHyperTwistTrainingViewerReferenceBundle ViewerBundle = + UHyperTwistTrainingViewerLibrary::BuildBundledBrowserViewerReferenceBundle(); + FHyperTwistTrainingViewerEditorToolReference CameraSettingsTool; + Surface.bCameraSettingsReady = + ViewerBundle.IsStructurallyValid() + && HyperTwistTrainingPanelWidgetInternal::TryFindViewerEditorToolById( + ViewerBundle, + TEXT("tool/camera-settings"), + CameraSettingsTool + ); + if (Surface.bCameraSettingsReady) + { + Surface.CameraSettingsToolId = CameraSettingsTool.ToolId; + } + + FHyperTwistTrainingImmersivePresenceControlContract ImmersivePresenceContract; + Surface.bImmersivePresenceSettingsReady = + UHyperTwistTrainingRuntimeLibrary::TryGetBundledImmersivePresenceControlContract( + TEXT("immersive-training-presence-control-contract"), + ImmersivePresenceContract + ) && ImmersivePresenceContract.IsStructurallyValid(); + + FHyperTwistTrainingHigherDimensionalRuntimeViewContextSurface Magic120CellViewContextSurface; + const bool bMagic120CellViewContextReady = + UHyperTwistTrainingRuntimeLibrary::TryGetBundledHigherDimensionalRuntimeViewContextSurfaceByActivationProfileId( + TEXT("magic120cell-cleanroom-runtime-activation"), + Magic120CellViewContextSurface + ) && Magic120CellViewContextSurface.IsStructurallyValid(); + Surface.Magic120CellSelectorCount = Magic120CellViewContextSurface.Selectors.Num(); + Surface.Magic120CellViewProfileContractId = + Magic120CellViewContextSurface.PrimaryViewProfileContractId; + FHyperTwistTrainingMagic120CellViewProfileContract Magic120CellViewProfileContract; + Surface.bMagic120CellViewSettingsReady = + bMagic120CellViewContextReady + && UHyperTwistTrainingRuntimeLibrary::TryGetBundledMagic120CellViewProfileContract( + Magic120CellViewContextSurface.PrimaryViewProfileContractId, + Magic120CellViewProfileContract + ) && Magic120CellViewProfileContract.IsStructurallyValid(); + + FHyperTwistTrainingHigherDimensionalRuntimeViewContextSurface MagicCube5DViewContextSurface; + const bool bMagicCube5DViewContextReady = + UHyperTwistTrainingRuntimeLibrary::TryGetBundledHigherDimensionalRuntimeViewContextSurfaceByActivationProfileId( + TEXT("magiccube5d-cleanroom-runtime-activation"), + MagicCube5DViewContextSurface + ) && MagicCube5DViewContextSurface.IsStructurallyValid(); + Surface.MagicCube5DSelectorCount = MagicCube5DViewContextSurface.Selectors.Num(); + Surface.MagicCube5DViewProfileContractId = + MagicCube5DViewContextSurface.PrimaryViewProfileContractId; + FHyperTwistTrainingMagicCube5DViewProfileContract MagicCube5DViewProfileContract; + Surface.bMagicCube5DViewSettingsReady = + bMagicCube5DViewContextReady + && UHyperTwistTrainingRuntimeLibrary::TryGetBundledMagicCube5DViewProfileContract( + MagicCube5DViewContextSurface.PrimaryViewProfileContractId, + MagicCube5DViewProfileContract + ) && MagicCube5DViewProfileContract.IsStructurallyValid(); + + const FHyperTwistTrainingHigherDimensionalRuntimeViewContextSurface ActiveViewContextSurface = + HasDisplayedHigherDimensionalRuntimeViewContextSurface() + ? GetDisplayedHigherDimensionalRuntimeViewContextSurface() + : FHyperTwistTrainingHigherDimensionalRuntimeViewContextSurface(); + Surface.bActiveHigherDimensionalSettingsVisible = ActiveViewContextSurface.IsStructurallyValid(); + Surface.ActiveHigherDimensionalViewContextId = + Surface.bActiveHigherDimensionalSettingsVisible + ? ActiveViewContextSurface.ViewContextSurfaceId + : TEXT("none"); + Surface.ActiveHigherDimensionalSelectorCount = + Surface.bActiveHigherDimensionalSettingsVisible + ? ActiveViewContextSurface.Selectors.Num() + : 0; + + Surface.bHigherDimensionalSelectorSettingsReady = + Surface.bMagic120CellViewSettingsReady + && Surface.bMagicCube5DViewSettingsReady + && Surface.Magic120CellSelectorCount > 0 + && Surface.MagicCube5DSelectorCount > 0; + Surface.bFinishedControllerRebindingReady = false; + + const FString CameraSettingsToolId = + !Surface.CameraSettingsToolId.IsEmpty() ? Surface.CameraSettingsToolId : TEXT("n/a"); + const FString ActiveViewContextId = + !Surface.ActiveHigherDimensionalViewContextId.IsEmpty() + ? Surface.ActiveHigherDimensionalViewContextId + : TEXT("none"); + const FString Magic120CellProfileId = + !Surface.Magic120CellViewProfileContractId.IsEmpty() + ? Surface.Magic120CellViewProfileContractId + : TEXT("n/a"); + const FString MagicCube5DProfileId = + !Surface.MagicCube5DViewProfileContractId.IsEmpty() + ? Surface.MagicCube5DViewProfileContractId + : TEXT("n/a"); + + Surface.SummaryLine = + TEXT("Camera, immersive, and dedicated-family view settings are already first-party owned, while XR/controller rebinding still remains unfinished."); + Surface.CameraSettingsLine = FString::Printf( + TEXT("Viewer camera settings: %s | tool %s | orbit/framing/export surface is owned."), + *HyperTwistTrainingPanelWidgetInternal::DescribeReadyState( + Surface.bCameraSettingsReady), + *CameraSettingsToolId + ); + Surface.ImmersiveSettingsLine = FString::Printf( + TEXT("Immersive presence settings: %s | contract immersive-training-presence-control-contract | intensity presets %d | reduced-distraction presets %d."), + *HyperTwistTrainingPanelWidgetInternal::DescribeReadyState( + Surface.bImmersivePresenceSettingsReady), + ImmersivePresenceContract.ImmersionIntensityIds.Num(), + ImmersivePresenceContract.ReducedDistractionPresetIds.Num() + ); + Surface.Magic120CellSettingsLine = FString::Printf( + TEXT("Magic120Cell view settings: %s | profile %s | selectors %d."), + *HyperTwistTrainingPanelWidgetInternal::DescribeReadyState( + Surface.bMagic120CellViewSettingsReady), + *Magic120CellProfileId, + Surface.Magic120CellSelectorCount + ); + Surface.MagicCube5DSettingsLine = FString::Printf( + TEXT("MagicCube5D view settings: %s | profile %s | selectors %d."), + *HyperTwistTrainingPanelWidgetInternal::DescribeReadyState( + Surface.bMagicCube5DViewSettingsReady), + *MagicCube5DProfileId, + Surface.MagicCube5DSelectorCount + ); + Surface.SelectorSettingsLine = FString::Printf( + TEXT("Higher-dimensional selector ownership: %s | active context %s | active selectors %d."), + *HyperTwistTrainingPanelWidgetInternal::DescribeReadyState( + Surface.bHigherDimensionalSelectorSettingsReady), + *ActiveViewContextId, + Surface.ActiveHigherDimensionalSelectorCount + ); + Surface.XrGapLine = + TEXT("XR/controller completion: explicit host decision, dedicated runtime owners, and polished settings/rebinding are not yet shipped."); + Surface.StatusLine = FString::Printf( + TEXT("camera %s | immersive %s | 120-cell %s | 5D %s | selectors %s | XR rebinding not yet shipped"), + Surface.bCameraSettingsReady ? TEXT("ready") : TEXT("missing"), + Surface.bImmersivePresenceSettingsReady ? TEXT("ready") : TEXT("missing"), + Surface.bMagic120CellViewSettingsReady ? TEXT("ready") : TEXT("missing"), + Surface.bMagicCube5DViewSettingsReady ? TEXT("ready") : TEXT("missing"), + Surface.bHigherDimensionalSelectorSettingsReady ? TEXT("ready") : TEXT("partial") + ); + Surface.DetailLine = FString::Printf( + TEXT("%s | %s | %s | %s | %s | %s"), + *Surface.CameraSettingsLine, + *Surface.ImmersiveSettingsLine, + *Surface.Magic120CellSettingsLine, + *Surface.MagicCube5DSettingsLine, + *Surface.SelectorSettingsLine, + *Surface.XrGapLine + ); + + return Surface; +} + FHyperTwistTrainingDeck UHyperTwistTrainingPanelWidget::BuildActiveCoachRecommendedDeck(const int32 MaxCases) { CachedCoachRecommendedDeck = UHyperTwistTrainingRuntimeLibrary::BuildActiveCoachRecommendedDeck( diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h index 248016c..77b8e6f 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h @@ -938,6 +938,9 @@ public: FHyperTwistTrainingControlInputReadinessInspectSurface GetDisplayedControlInputReadinessInspectSurface() const override; + FHyperTwistTrainingControlSettingsOwnershipInspectSurface + GetDisplayedControlSettingsOwnershipInspectSurface() const override; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") FHyperTwistTrainingCoachDashboardGuidanceRationaleInspectSurface GetDisplayedGuidanceRationaleInspectSurface() const; @@ -1658,6 +1661,15 @@ protected: UPROPERTY(Transient) TObjectPtr ControlInputReadinessDetailTextBlock = nullptr; + UPROPERTY(Transient) + TObjectPtr ControlSettingsOwnershipHeaderTextBlock = nullptr; + + UPROPERTY(Transient) + TObjectPtr ControlSettingsOwnershipStatusTextBlock = nullptr; + + UPROPERTY(Transient) + TObjectPtr ControlSettingsOwnershipDetailTextBlock = nullptr; + UPROPERTY(Transient) TObjectPtr RecognitionStatusTextBlock = nullptr; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h index f47da3a..2b8a49d 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h @@ -295,6 +295,10 @@ public: virtual FHyperTwistTrainingControlInputReadinessInspectSurface GetDisplayedControlInputReadinessInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Input") + virtual FHyperTwistTrainingControlSettingsOwnershipInspectSurface + GetDisplayedControlSettingsOwnershipInspectSurface() const; + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach") FHyperTwistTrainingDeck BuildActiveCoachRecommendedDeck(int32 MaxCases); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h index b5633d7..91b83a3 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -10066,6 +10066,100 @@ struct FHyperTwistTrainingControlInputReadinessInspectSurface } }; +USTRUCT(BlueprintType) +struct FHyperTwistTrainingControlSettingsOwnershipInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SummaryLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString StatusLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CameraSettingsLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ImmersiveSettingsLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Magic120CellSettingsLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString MagicCube5DSettingsLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectorSettingsLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString XrGapLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CameraSettingsToolId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ActiveHigherDimensionalViewContextId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Magic120CellViewProfileContractId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString MagicCube5DViewProfileContractId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 Magic120CellSelectorCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 MagicCube5DSelectorCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 ActiveHigherDimensionalSelectorCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bCameraSettingsReady = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bImmersivePresenceSettingsReady = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bMagic120CellViewSettingsReady = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bMagicCube5DViewSettingsReady = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHigherDimensionalSelectorSettingsReady = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bActiveHigherDimensionalSettingsVisible = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bFinishedControllerRebindingReady = false; + + bool IsStructurallyValid() const + { + return !SummaryLine.IsEmpty() + || !StatusLine.IsEmpty() + || !CameraSettingsLine.IsEmpty() + || !ImmersiveSettingsLine.IsEmpty() + || !Magic120CellSettingsLine.IsEmpty() + || !MagicCube5DSettingsLine.IsEmpty() + || !SelectorSettingsLine.IsEmpty() + || bCameraSettingsReady + || bImmersivePresenceSettingsReady + || bMagic120CellViewSettingsReady + || bMagicCube5DViewSettingsReady + || bHigherDimensionalSelectorSettingsReady; + } +}; + USTRUCT(BlueprintType) struct FHyperTwistTrainingCoachDashboardQueueRecoveryStatusInspectSurface { diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistBrowserBridgeObjectTest.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistBrowserBridgeObjectTest.cpp index 03185f2..654e9ab 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistBrowserBridgeObjectTest.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistBrowserBridgeObjectTest.cpp @@ -1100,6 +1100,123 @@ bool FHyperTwistCoachDashboardControlInputReadinessInspectSurfaceTest::RunTest( return true; } +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistTrainingPanelControlSettingsOwnershipInspectSurfaceTest, + "HyperTwist.Browser.TrainingPanel.ControlSettingsOwnershipInspectSurface", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistTrainingPanelControlSettingsOwnershipInspectSurfaceTest::RunTest( + const FString& Parameters +) +{ + UHyperTwistTrainingPanelWidget* TrainingPanel = NewObject(); + TestNotNull(TEXT("The training panel widget must be constructible."), TrainingPanel); + if (TrainingPanel == nullptr) + { + return false; + } + + const FHyperTwistTrainingControlSettingsOwnershipInspectSurface Surface = + TrainingPanel->GetDisplayedControlSettingsOwnershipInspectSurface(); + TestTrue( + TEXT("The control settings ownership surface must be structurally valid."), + Surface.IsStructurallyValid() + ); + TestEqual( + TEXT("The control settings ownership surface must keep a stable headline."), + Surface.Headline, + TEXT("Control settings ownership") + ); + TestTrue( + TEXT("The control settings ownership surface must report the shipped first-party camera, immersive, dedicated-family, and selector ownership lanes."), + Surface.bCameraSettingsReady + && Surface.bImmersivePresenceSettingsReady + && Surface.bMagic120CellViewSettingsReady + && Surface.bMagicCube5DViewSettingsReady + && Surface.bHigherDimensionalSelectorSettingsReady + ); + TestFalse( + TEXT("The control settings ownership surface must keep unfinished XR/controller rebinding truth explicit."), + Surface.bFinishedControllerRebindingReady + ); + TestEqual( + TEXT("The control settings ownership surface must expose the shipped camera settings tool id."), + Surface.CameraSettingsToolId, + TEXT("tool/camera-settings") + ); + TestEqual( + TEXT("The control settings ownership surface must expose the shipped Magic120Cell view profile contract id."), + Surface.Magic120CellViewProfileContractId, + TEXT("magic120cell-focus-view-profile") + ); + TestEqual( + TEXT("The control settings ownership surface must expose the shipped MagicCube5D view profile contract id."), + Surface.MagicCube5DViewProfileContractId, + TEXT("magiccube5d-projection-view-profile") + ); + TestEqual( + TEXT("The control settings ownership surface must expose the current Magic120Cell selector count."), + Surface.Magic120CellSelectorCount, + 4 + ); + TestEqual( + TEXT("The control settings ownership surface must expose the current MagicCube5D selector count."), + Surface.MagicCube5DSelectorCount, + 4 + ); + TestTrue( + TEXT("The control settings ownership surface must say plainly that XR/controller rebinding is not yet shipped."), + Surface.DetailLine.Contains(TEXT("not yet shipped")) + ); + TestTrue( + TEXT("The control settings ownership surface must retain the camera settings tool reference in its detail line."), + Surface.DetailLine.Contains(TEXT("tool/camera-settings")) + ); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistCoachDashboardControlSettingsOwnershipInspectSurfaceTest, + "HyperTwist.Browser.CoachDashboard.ControlSettingsOwnershipInspectSurface", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistCoachDashboardControlSettingsOwnershipInspectSurfaceTest::RunTest( + const FString& Parameters +) +{ + UHyperTwistCoachDashboardWidget* CoachDashboard = NewObject(); + TestNotNull(TEXT("The coach dashboard widget must be constructible."), CoachDashboard); + if (CoachDashboard == nullptr) + { + return false; + } + + CoachDashboard->RefreshCoachDashboardView(); + const FHyperTwistTrainingControlSettingsOwnershipInspectSurface Surface = + CoachDashboard->GetDisplayedControlSettingsOwnershipInspectSurface(); + TestTrue( + TEXT("The coach dashboard control settings ownership surface must stay structurally valid after a view refresh."), + Surface.IsStructurallyValid() + ); + TestEqual( + TEXT("The coach dashboard control settings ownership surface must preserve the diagnostics headline."), + Surface.Headline, + TEXT("Control settings ownership") + ); + TestTrue( + TEXT("The coach dashboard control settings ownership surface must retain the camera settings tool reference in its detail line."), + Surface.DetailLine.Contains(TEXT("tool/camera-settings")) + ); + TestTrue( + TEXT("The coach dashboard control settings ownership surface must retain the dedicated-family view profile references in its detail line."), + Surface.DetailLine.Contains(TEXT("magic120cell-focus-view-profile")) + && Surface.DetailLine.Contains(TEXT("magiccube5d-projection-view-profile")) + ); + return true; +} + IMPLEMENT_SIMPLE_AUTOMATION_TEST( FHyperTwistBrowserWidgetAuthoritativeShellArtifactsTest, "HyperTwist.Browser.Widget.AuthoritativeShellArtifacts", diff --git a/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md b/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md index 3d2db00..86a923c 100644 --- a/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md +++ b/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md @@ -172,6 +172,24 @@ Use these as the current governing docs: `TrainingPanel.ControlInputReadinessInspectSurface`, `CoachDashboard.RuntimeInspectSurface`, and `TrainingPanel.RuntimeInspectSurface` +- that same shipping/browser posture now also carries a native control/settings + ownership inspect surface through `UHyperTwistTrainingPanelWidget` and + `UHyperTwistCoachDashboardWidget`, so the operator can see the current viewer + camera-settings owner, immersive-presence settings, dedicated-family + `Magic120Cell` / `MagicCube5D` view-profile ownership, selector ownership, + and explicit unfinished XR/controller rebinding truth without opening the + browser shell +- Validation evidence on `2026-06-24`: the same primary reverse-SSH + `localhost:22022` lane rebuilt maintained isolated worktree + `C:\HyperTwist_worktrees\phase10validate` with `Result: Succeeded` and + UnrealBuildTool `Total execution time: 4331.11 seconds`, then + `Automation RunTests HyperTwist.Browser` exported + `Saved\AutomationReports\Browser-ControlSettingsOwnership-Verify\index.json` + with `18` `HyperTwist.Browser.*` tests succeeded and `0` failed, including + `CoachDashboard.ControlSettingsOwnershipInspectSurface`, + `TrainingPanel.ControlSettingsOwnershipInspectSurface`, + `CoachDashboard.ControlInputReadinessInspectSurface`, and + `TrainingPanel.ControlInputReadinessInspectSurface` - the same optional full-browser-client branch is now also tightened by a backend-contract matrix packet that fixes transport-neutral operation labels, minimum session or host or bridge identity facts, request or result correlation posture, freshness or reconnect rules, and the owned state/runtime payload anchors a later browser-client implementation must preserve - `MagicTile` `Phase 7C` is now landed separately through the bundled tiling native-behavior proof contract/probe seam, runtime-library proof helpers, and focused Windows validation on diff --git a/docs/ops/HYPERTWIST_UNREAL_INPUT_AND_XR_COMPLETENESS_AUDIT_2026-06-22.md b/docs/ops/HYPERTWIST_UNREAL_INPUT_AND_XR_COMPLETENESS_AUDIT_2026-06-22.md index b0f756f..602c959 100644 --- a/docs/ops/HYPERTWIST_UNREAL_INPUT_AND_XR_COMPLETENESS_AUDIT_2026-06-22.md +++ b/docs/ops/HYPERTWIST_UNREAL_INPUT_AND_XR_COMPLETENESS_AUDIT_2026-06-22.md @@ -14,6 +14,7 @@ HyperTwist currently has real native input ownership for: - classic-cube mouse or touch or keyboard-adjacent play flows - higher-dimensional keyboard interaction in the bounded visible-slice lane +- current camera or immersive or dedicated-family view-settings ownership - `EnhancedInput`-based project posture - broad motion-controller axis configuration at the Unreal project-settings level @@ -25,8 +26,8 @@ truthfully claim: - a fully finished shipping VR/OpenXR product lane - finished controller-specific runtime interaction surfaces across headsets -- user-facing input rebinding or preferences ownership at a polished shipping - standard +- broad user-facing controller rebinding or preferences ownership at a polished + shipping standard - “utmost quality” for native VR controller setup without a dedicated runtime completion packet @@ -85,6 +86,33 @@ truthfully claim: - `CoachDashboard.RuntimeInspectSurface` - `TrainingPanel.RuntimeInspectSurface` +### Partial native control/settings ownership is now real + +- `FHyperTwistTrainingControlSettingsOwnershipInspectSurface` now also exists + in + `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h` +- `UHyperTwistTrainingPanelWidget` and `UHyperTwistCoachDashboardWidget` now + expose that second inspect surface and keep current settings ownership + visible without pretending the full XR/rebinding packet is finished +- the current settings-ownership surface explicitly reports: + - shipped viewer camera-settings owner `tool/camera-settings` + - immersive-presence settings contract presence + - `Magic120Cell` view ownership through + `magic120cell-focus-view-profile` + - `MagicCube5D` view ownership through + `magiccube5d-projection-view-profile` + - higher-dimensional selector ownership + - explicit unfinished XR/controller rebinding truth +- Windows validation on `2026-06-24` rebuilt the maintained validation root + `C:\HyperTwist_worktrees\phase10validate` with `Result: Succeeded`, + UnrealBuildTool `Total execution time: 4331.11 seconds`, then exported + `Saved\AutomationReports\Browser-ControlSettingsOwnership-Verify\index.json` + with all `18` `HyperTwist.Browser.*` tests green, including: + - `CoachDashboard.ControlSettingsOwnershipInspectSurface` + - `TrainingPanel.ControlSettingsOwnershipInspectSurface` + - `CoachDashboard.ControlInputReadinessInspectSurface` + - `TrainingPanel.ControlInputReadinessInspectSurface` + ### Finished XR runtime ownership is not yet proven - `UnrealHyperTwist/UnrealHyperTwist.uproject` currently enables @@ -106,6 +134,8 @@ Current truthful product wording should say: - desktop Unreal simulator: real and shipping - classic input and higher-dimensional keyboard interaction: real and shipping - native operator/training diagnostics already surface current input truth +- camera, immersive, and dedicated-family view settings already have bounded + first-party ownership - immersive/scenic training direction: first-party owned and source-backed - full VR/controller/settings polish lane: not yet complete enough to market as finished @@ -117,6 +147,9 @@ manual: - docs/resources/support surfaces should explicitly distinguish current keyboard and higher-dimensional control ownership from unfinished VR/controller claims +- docs/resources/support surfaces may truthfully describe current camera or + immersive or dedicated-family view settings ownership, but they must not + inflate that into full controller rebinding or headset-runtime completion - public copy should not imply that `EnhancedInput` plus motion-controller axis groundwork already equals a finished OpenXR/runtime or rebinding lane - browser/distribution pages may describe the simulator input posture, but they @@ -129,6 +162,7 @@ quality,” the next clean packet is: 1. explicit native XR host/plugin decision 2. dedicated runtime interaction owner(s) for headset and controller handling -3. user-facing control/settings/rebinding ownership +3. finished controller-specific rebinding/preferences ownership above the + already-landed camera/immersive/view settings surfaces 4. packaged validation on the Windows Unreal lane with headset/controller truth kept explicit 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 39d6a2d..05545ab 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md @@ -146,6 +146,7 @@ Do not collapse those three tiers into one undifferentiated "features" voice. | Rewritten training analytics and report reference grounding | Implemented now | `apache/echarts` retained permissive lane + first-party current code | Current live `Training Analytics` reference side includes four rewritten first-party targets grounded in retained `apache/echarts`: session outcome and progress reporting, analytics data-view and export, timing-trend history and overview interaction, and the optional richer explainer or sidecar boundary. This does not displace the landed `Phase 3R-C` first-party analytics/reporting owner or elevate `ecomfe/echarts-gl` and `ecomfe/zrender` beyond support-only sidecars. | | Browser/spatial/media adjunct surfaces | Implemented now | landed `three.js`, `react-three-fiber`, `xr`, `model-viewer`, `remotion` packets | These are implemented bounded families, and the current Phase 1 browser-runtime landing now includes a first-party authoritative `Content/Browser/index.html` shell, bundled-runtime upgrade path, committed clean-checkout plain-JS fallback runtime, embedded `UHyperTwistBrowserWidget` bridge, the `2026-06-19` runtime-ready queue hardening that retains outbound Unreal shell traffic until the browser runtime is ready, a same-day first-party `Browser Runtime Status` surface with shared boot-state ownership across bundled and fallback shells, a follow-on typed Unreal-side `browser-runtime-status` capture seam that retains the last valid runtime snapshot across unrelated later envelope traffic until explicit reset, a second follow-on typed Unreal-side `hypertwist-runtime-ready` capture seam that raises the original handshake payload out of raw JSON-only handling without changing queue flush behavior, a third same-day native/operator-facing status surface that consumes those typed seams inside Unreal while clearing retained runtime ownership on shell-authority change, a fourth same-day native training/operator diagnostics-panel continuation that wires that typed status ownership into `UHyperTwistTrainingPanelWidget` and the coach dashboard without making the dashboard inspect seam depend on stale rendered strings, a fifth same-day diagnostics-fidelity continuation that now carries bootstrap/runtime-ready timestamps, last command/shell-state receipt timestamps, and fallback reason through the same native operator/training seams, and a later `2026-06-23` control/input readiness continuation that projects shipped keyboard/input truth and unfinished XR/preferences truth through the same native training/operator surfaces. This still is not proof of unlimited browser-shell parity. | | Native control/input readiness inspect surface | Implemented now | landed first-party `2026-06-23` browser/native operator continuation | `UHyperTwistTrainingPanelWidget` and `UHyperTwistCoachDashboardWidget` now expose `FHyperTwistTrainingControlInputReadinessInspectSurface`, including the shipped `classic-wca-keyboard/v1` mapping, classic-cube mouse/touch/shortcut readiness, higher-dimensional dedicated-family runtime-catalog truth, project-level `EnhancedInput` plus motion-controller groundwork facts, immersive-presence contract presence, and explicit unfinished XR/runtime plus preferences truth. The recovered primary reverse-SSH `localhost:22022` lane rebuilt maintained validation worktree `C:\HyperTwist_worktrees\phase10validate` on `2026-06-23` with `Result: Succeeded`, UnrealBuildTool `Total execution time: 1563.53 seconds`, and exported `Saved\AutomationReports\Browser-ControlInputReadiness-Verify\index.json` with all `16` `HyperTwist.Browser.*` tests passing, including `CoachDashboard.ControlInputReadinessInspectSurface` and `TrainingPanel.ControlInputReadinessInspectSurface`. A later same-day quality follow-up then moved the project-input-groundwork inspection behind that surface from raw text scanning into structured Unreal config reads, rebuilt the same maintained validation worktree again with `Result: Succeeded`, UnrealBuildTool `Total execution time: 158.13 seconds`, and re-exported focused browser proof to `Saved\AutomationReports\Browser-ControlInputReadiness-StructuredConfig-Verify` with all `16` `HyperTwist.Browser.*` tests green again. | +| Native control/settings ownership inspect surface | Implemented now | landed first-party `2026-06-24` browser/native operator continuation | `UHyperTwistTrainingPanelWidget` and `UHyperTwistCoachDashboardWidget` now expose `FHyperTwistTrainingControlSettingsOwnershipInspectSurface`, including the shipped viewer camera-settings owner `tool/camera-settings`, the immersive-presence control contract, dedicated-family `magic120cell-focus-view-profile` and `magiccube5d-projection-view-profile` view ownership, higher-dimensional selector ownership, and explicit unfinished XR/controller rebinding truth. The same primary reverse-SSH `localhost:22022` lane rebuilt maintained validation worktree `C:\HyperTwist_worktrees\phase10validate` on `2026-06-24` with `Result: Succeeded`, UnrealBuildTool `Total execution time: 4331.11 seconds`, and then exported `Saved\AutomationReports\Browser-ControlSettingsOwnership-Verify\index.json` with all `18` `HyperTwist.Browser.*` tests passing, including `CoachDashboard.ControlSettingsOwnershipInspectSurface`, `TrainingPanel.ControlSettingsOwnershipInspectSurface`, and the previously landed runtime plus control/input inspect seams. | | Optional full-browser client path above Unreal backend authority | Deep-source grounded retained | landed first-party `Phase 8B` preparation packet + spec/evidence continuation + backend-contract continuation | This branch remains a spec-only first-party option: a browser-owned rendering and input shell may sit above explicit Unreal backend seams while Unreal remains authoritative for puzzle, training, timer, replay, and persistence state. The current continuation now fixes the allowed seam families to catalog, session, action, state, continuity push, replay, persistence status, and runtime health, then further fixes transport-neutral operation labels, minimum identity or freshness requirements, and the owned state/runtime payload anchors that any later browser-client backend implementation must preserve. The landed embedded browser/CEF shell remains the current shipping posture, and this branch stays separate from any native `MagicTile` behavior or renderer widening. | | Rewritten browser spatial scene and renderer reference grounding | Implemented now | `mrdoob/three.js` retained permissive lane + first-party current code | Current live `Browser 3D and XR Support` reference side includes one rewritten first-party target grounded in retained `mrdoob/three.js`: the browser spatial scene and renderer contract. This does not displace the landed `Phase 3R-F` first-party browser spatial owner trio or absorb the adjacent `react-three-fiber` renderer-bridge and `xr` session slices. | | Rewritten React-side browser renderer and event-bridge grounding | Implemented now | `pmndrs/react-three-fiber` retained permissive lane + first-party current code | Current live `Browser 3D and XR Support` reference side includes one rewritten first-party target grounded in retained `react-three-fiber`: the React scene renderer and event bridge. This does not displace the landed `Phase 3R-F` first-party browser spatial owner trio or absorb the adjacent `three.js` scene substrate and `xr` session slices. | diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md index 37b613a..0d2f8b8 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md @@ -211,6 +211,20 @@ Current consolidated milestone snapshot: `TrainingPanel.ControlInputReadinessInspectSurface`, `CoachDashboard.RuntimeInspectSurface`, and `TrainingPanel.RuntimeInspectSurface` +- a same-family `2026-06-24` continuation then added + `FHyperTwistTrainingControlSettingsOwnershipInspectSurface` plus native + training-panel and coach-dashboard ownership for the current viewer + camera-settings tool, immersive-presence settings, dedicated-family + `Magic120Cell` / `MagicCube5D` view-profile ownership, selector ownership, + and explicit unfinished XR/controller rebinding truth; the same primary + reverse-SSH `localhost:22022` lane rebuilt the maintained validation root + `C:\HyperTwist_worktrees\phase10validate` with `Result: Succeeded`, + UnrealBuildTool `Total execution time: 4331.11 seconds`, then exported + `Saved\AutomationReports\Browser-ControlSettingsOwnership-Verify\index.json` + with `18` `HyperTwist.Browser.*` tests succeeded and `0` failed, including + `CoachDashboard.ControlSettingsOwnershipInspectSurface`, + `TrainingPanel.ControlSettingsOwnershipInspectSurface`, and the previously + landed runtime plus control/input inspect seams - the public HyperTwist website/distribution lane is now also live through a first-party `website/` app on `2026-06-22`, with rebranded home/about/resources/pricing/download/legal pages, a protected browser diff --git a/website/src/site-data.ts b/website/src/site-data.ts index dc83cac..dd9a415 100644 --- a/website/src/site-data.ts +++ b/website/src/site-data.ts @@ -279,10 +279,11 @@ export const inputAndDevicePostureCards = [ }, { title: 'Higher-dimensional view controls are already owned', - description: 'Magic120Cell and MagicCube5D already carry first-party projection, focus, symmetry or stereo, and visibility defaults in the packaged runtime.', + description: 'Magic120Cell and MagicCube5D already carry first-party projection, focus, symmetry or stereo, visibility defaults, and visible native settings ownership in the packaged runtime.', bullets: [ 'Magic120Cell keeps symmetry, logical-visibility depth, and center-cell focus posture explicit.', 'MagicCube5D keeps projection-distance, stereo, face-visibility, and focus posture explicit.', + 'The desktop operator/training lane now also surfaces these dedicated-family view owners together with current camera-settings ownership.', 'These controls belong to the dedicated-family desktop runtime lanes, not to the public website.', ], }, @@ -292,7 +293,7 @@ export const inputAndDevicePostureCards = [ bullets: [ 'Project config already carries EnhancedInput plus Vive, Oculus Touch, Mixed Reality, and Valve Index axis groundwork.', 'Current product truth should not overclaim headset-specific runtime ownership or polished user-facing input rebinding.', - 'A later native XR completion packet still needs dedicated runtime owners, user-facing settings, and Windows package validation with controller truth.', + 'A later native XR completion packet still needs dedicated runtime owners, finished controller rebinding, and Windows package validation with controller truth.', ], }, ] as const @@ -321,6 +322,7 @@ export const runtimeControlGuideCards = [ description: 'This keeps the manual useful by being explicit about what is supported now and what still belongs to a later native completion packet.', bullets: [ 'Use keyboard and mouse as the current strong operator-facing control lane.', + 'Treat current camera, immersive, and dedicated-family view settings ownership as real, but still bounded.', 'Do not assume a finished headset-specific VR onboarding, controller rebinding, or broad preferences UI has already landed.', 'Treat future XR/controller/settings widening as a separate native completion packet, not as something the public website should overclaim today.', ], @@ -654,7 +656,7 @@ export const supportFaqs = [ }, { question: 'Can I already customize controls and higher-dimensional view posture?', - answer: 'Partly. The current desktop runtime already owns the classic keyboard profile plus higher-dimensional projection, focus, and visibility defaults, but a broader polished user-facing preferences and rebinding layer is still a later native packet.', + answer: 'Partly. The current desktop runtime already owns the classic keyboard profile, viewer camera settings, immersive-presence settings, and higher-dimensional projection, focus, stereo, symmetry, and visibility defaults, but a broader polished controller rebinding and preferences layer is still a later native packet.', }, { question: 'Can I download a build immediately after sign-in?',