Land bounded OpenXR runtime ownership substrate
This commit is contained in:
parent
951c927ffb
commit
3ed296b893
18 changed files with 1842 additions and 80 deletions
|
|
@ -81,4 +81,50 @@ DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent
|
|||
DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks
|
||||
-ConsoleKeys=Tilde
|
||||
+ConsoleKeys=Tilde
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveForward",Key=Gamepad_LeftY,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveForward",Key=Vive_Left_Trackpad_Y,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveForward",Key=MixedReality_Left_Thumbstick_Y,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveForward",Key=MixedReality_Left_Trackpad_Y,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveForward",Key=OculusTouch_Left_Thumbstick_Y,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveForward",Key=ValveIndex_Left_Thumbstick_Y,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveForward",Key=ValveIndex_Left_Trackpad_Y,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveRight",Key=Gamepad_LeftX,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveRight",Key=Vive_Left_Trackpad_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveRight",Key=MixedReality_Left_Thumbstick_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveRight",Key=MixedReality_Left_Trackpad_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveRight",Key=OculusTouch_Left_Thumbstick_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveRight",Key=ValveIndex_Left_Thumbstick_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_MoveRight",Key=ValveIndex_Left_Trackpad_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_Turn",Key=Gamepad_RightX,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_Turn",Key=Vive_Right_Trackpad_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_Turn",Key=MixedReality_Right_Thumbstick_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_Turn",Key=MixedReality_Right_Trackpad_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_Turn",Key=OculusTouch_Right_Thumbstick_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_Turn",Key=ValveIndex_Right_Thumbstick_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_Turn",Key=ValveIndex_Right_Trackpad_X,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LookPitch",Key=Gamepad_RightY,Scale=-1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LookPitch",Key=Vive_Right_Trackpad_Y,Scale=-1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LookPitch",Key=MixedReality_Right_Thumbstick_Y,Scale=-1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LookPitch",Key=MixedReality_Right_Trackpad_Y,Scale=-1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LookPitch",Key=OculusTouch_Right_Thumbstick_Y,Scale=-1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LookPitch",Key=ValveIndex_Right_Thumbstick_Y,Scale=-1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LookPitch",Key=ValveIndex_Right_Trackpad_Y,Scale=-1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LeftGrip",Key=Gamepad_LeftTriggerAxis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LeftGrip",Key=OculusTouch_Left_Grip_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LeftGrip",Key=ValveIndex_Left_Grip_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_RightGrip",Key=Gamepad_RightTriggerAxis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_RightGrip",Key=OculusTouch_Right_Grip_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_RightGrip",Key=ValveIndex_Right_Grip_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LeftTrigger",Key=Vive_Left_Trigger_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LeftTrigger",Key=MixedReality_Left_Trigger_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LeftTrigger",Key=OculusTouch_Left_Trigger_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_LeftTrigger",Key=ValveIndex_Left_Trigger_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_RightTrigger",Key=Vive_Right_Trigger_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_RightTrigger",Key=MixedReality_Right_Trigger_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_RightTrigger",Key=OculusTouch_Right_Trigger_Axis,Scale=1.000000)
|
||||
+AxisMappings=(AxisName="HyperTwistXr_RightTrigger",Key=ValveIndex_Right_Trigger_Axis,Scale=1.000000)
|
||||
+ActionMappings=(ActionName="HyperTwistXr_Recenter",Key=Home,bShift=False,bCtrl=False,bAlt=False,bCmd=False)
|
||||
+ActionMappings=(ActionName="HyperTwistXr_Recenter",Key=Gamepad_Special_Left,bShift=False,bCtrl=False,bAlt=False,bCmd=False)
|
||||
+ActionMappings=(ActionName="HyperTwistXr_ToggleSnapTurn",Key=Insert,bShift=False,bCtrl=False,bAlt=False,bCmd=False)
|
||||
+ActionMappings=(ActionName="HyperTwistXr_TogglePostureMode",Key=End,bShift=False,bCtrl=False,bAlt=False,bCmd=False)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "HyperTwistTraining/HyperTwistTrainingMagicCube5DLibrary.h"
|
||||
#include "HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h"
|
||||
#include "HyperTwistTraining/HyperTwistTrainingViewerLibrary.h"
|
||||
#include "HyperTwistXR/HyperTwistXrRuntimeLibrary.h"
|
||||
#include "Interfaces/IPluginManager.h"
|
||||
#include "Misc/ConfigCacheIni.h"
|
||||
|
||||
|
|
@ -78,6 +79,19 @@ namespace HyperTwistTrainingPanelWidgetInternal
|
|||
bool bReady = false;
|
||||
};
|
||||
|
||||
struct FXrRuntimeOwnershipFacts
|
||||
{
|
||||
FHyperTwistXrRuntimeOwnershipSurface RuntimeSurface;
|
||||
FHyperTwistXrPreferenceProfile PreferenceProfile;
|
||||
FHyperTwistXrControllerBindingProfile ControllerBindingProfile;
|
||||
bool bRuntimeOwnerReady = false;
|
||||
bool bPreferenceProfileReady = false;
|
||||
bool bControllerBindingProfileReady = false;
|
||||
int32 PreferenceFieldCount = 0;
|
||||
int32 ControllerBindingAxisCount = 0;
|
||||
int32 SupportedControllerFamilyCount = 0;
|
||||
};
|
||||
|
||||
FString DescribeBool(const bool bValue)
|
||||
{
|
||||
return HyperTwistTrainingControlSurfaceFormatting::DescribeBool(bValue);
|
||||
|
|
@ -113,6 +127,28 @@ namespace HyperTwistTrainingPanelWidgetInternal
|
|||
return HyperTwistTrainingControlSurfaceFormatting::DescribeIdOrFallback(Value);
|
||||
}
|
||||
|
||||
FString DescribeIdIfReady(
|
||||
const bool bReady,
|
||||
const FString& Value
|
||||
)
|
||||
{
|
||||
return HyperTwistTrainingControlSurfaceFormatting::DescribeIdIfReady(
|
||||
bReady,
|
||||
Value
|
||||
);
|
||||
}
|
||||
|
||||
int32 DescribeCountIfReady(
|
||||
const bool bReady,
|
||||
const int32 Count
|
||||
)
|
||||
{
|
||||
return HyperTwistTrainingControlSurfaceFormatting::DescribeCountIfReady(
|
||||
bReady,
|
||||
Count
|
||||
);
|
||||
}
|
||||
|
||||
FString DescribeKeyForRoster(const FKey& Key)
|
||||
{
|
||||
return Key.IsValid() ? Key.GetDisplayName().ToString() : TEXT("n/a");
|
||||
|
|
@ -545,6 +581,102 @@ namespace HyperTwistTrainingPanelWidgetInternal
|
|||
);
|
||||
}
|
||||
|
||||
FXrRuntimeOwnershipFacts BuildXrRuntimeOwnershipFacts()
|
||||
{
|
||||
FXrRuntimeOwnershipFacts Facts;
|
||||
Facts.RuntimeSurface =
|
||||
UHyperTwistXrRuntimeLibrary::BuildBundledXrRuntimeOwnershipSurface();
|
||||
Facts.PreferenceProfile =
|
||||
UHyperTwistXrRuntimeLibrary::GetDefaultXrPreferenceProfile();
|
||||
Facts.ControllerBindingProfile =
|
||||
UHyperTwistXrRuntimeLibrary::GetDefaultXrControllerBindingProfile();
|
||||
Facts.bRuntimeOwnerReady = Facts.RuntimeSurface.IsStructurallyValid();
|
||||
Facts.bPreferenceProfileReady = Facts.PreferenceProfile.IsStructurallyValid();
|
||||
Facts.bControllerBindingProfileReady =
|
||||
Facts.ControllerBindingProfile.IsStructurallyValid();
|
||||
Facts.PreferenceFieldCount = Facts.PreferenceProfile.PreferenceFieldTags.Num();
|
||||
Facts.ControllerBindingAxisCount =
|
||||
Facts.ControllerBindingProfile.RequiredAxisNames.Num();
|
||||
Facts.SupportedControllerFamilyCount =
|
||||
Facts.RuntimeSurface.SupportedControllerFamilies.Num();
|
||||
return Facts;
|
||||
}
|
||||
|
||||
FString DescribeXrDominantHand(const EHyperTwistXrDominantHand DominantHand)
|
||||
{
|
||||
return DominantHand == EHyperTwistXrDominantHand::Left
|
||||
? TEXT("left")
|
||||
: TEXT("right");
|
||||
}
|
||||
|
||||
FString DescribeXrPostureMode(const EHyperTwistXrPostureMode PostureMode)
|
||||
{
|
||||
switch (PostureMode)
|
||||
{
|
||||
case EHyperTwistXrPostureMode::Seated:
|
||||
return TEXT("seated");
|
||||
case EHyperTwistXrPostureMode::Hybrid:
|
||||
return TEXT("hybrid");
|
||||
default:
|
||||
return TEXT("standing");
|
||||
}
|
||||
}
|
||||
|
||||
FString BuildXrRuntimeOwnerLine(const FXrRuntimeOwnershipFacts& Facts)
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("Bounded XR runtime owner: %s | runtime %s | preferences %s | bindings %s | motion sources %s/%s | controller families %d."),
|
||||
*DescribeReadyState(Facts.bRuntimeOwnerReady),
|
||||
*DescribeIdIfReady(Facts.bRuntimeOwnerReady, Facts.RuntimeSurface.RuntimeOwnerId),
|
||||
*DescribeIdIfReady(
|
||||
Facts.bPreferenceProfileReady,
|
||||
Facts.PreferenceProfile.ProfileId),
|
||||
*DescribeIdIfReady(
|
||||
Facts.bControllerBindingProfileReady,
|
||||
Facts.ControllerBindingProfile.ProfileId),
|
||||
*DescribeIdIfReady(Facts.bRuntimeOwnerReady, Facts.RuntimeSurface.LeftMotionSourceId),
|
||||
*DescribeIdIfReady(Facts.bRuntimeOwnerReady, Facts.RuntimeSurface.RightMotionSourceId),
|
||||
DescribeCountIfReady(
|
||||
Facts.bRuntimeOwnerReady,
|
||||
Facts.SupportedControllerFamilyCount)
|
||||
);
|
||||
}
|
||||
|
||||
FString BuildXrPreferenceOwnerLine(const FXrRuntimeOwnershipFacts& Facts)
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("XR preference ownership: %s | profile %s | posture %s | dominant hand %s | snap turn %.0f | world scale %.0f | preference fields %d."),
|
||||
*DescribeReadyState(Facts.bPreferenceProfileReady),
|
||||
*DescribeIdIfReady(
|
||||
Facts.bPreferenceProfileReady,
|
||||
Facts.PreferenceProfile.ProfileId),
|
||||
*DescribeXrPostureMode(Facts.PreferenceProfile.PostureMode),
|
||||
*DescribeXrDominantHand(Facts.PreferenceProfile.DominantHand),
|
||||
Facts.PreferenceProfile.SnapTurnDegrees,
|
||||
Facts.PreferenceProfile.WorldToMetersScale,
|
||||
DescribeCountIfReady(
|
||||
Facts.bPreferenceProfileReady,
|
||||
Facts.PreferenceFieldCount)
|
||||
);
|
||||
}
|
||||
|
||||
FString BuildXrControllerBindingLine(const FXrRuntimeOwnershipFacts& Facts)
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("XR controller bindings: %s | profile %s | required axes %d | families %d."),
|
||||
*DescribeReadyState(Facts.bControllerBindingProfileReady),
|
||||
*DescribeIdIfReady(
|
||||
Facts.bControllerBindingProfileReady,
|
||||
Facts.ControllerBindingProfile.ProfileId),
|
||||
DescribeCountIfReady(
|
||||
Facts.bControllerBindingProfileReady,
|
||||
Facts.ControllerBindingAxisCount),
|
||||
DescribeCountIfReady(
|
||||
Facts.bControllerBindingProfileReady,
|
||||
Facts.SupportedControllerFamilyCount)
|
||||
);
|
||||
}
|
||||
|
||||
const FXrControllerBoundaryFacts& GetXrControllerBoundaryFacts()
|
||||
{
|
||||
static const FXrControllerBoundaryFacts CachedFacts = []()
|
||||
|
|
@ -558,13 +690,13 @@ namespace HyperTwistTrainingPanelWidgetInternal
|
|||
|
||||
FString BuildControlInputXrBoundaryLine()
|
||||
{
|
||||
return TEXT("Current XR host/plugin decision: desktop-hosted No-Go on native OpenXR/controller widening; any future reopen packet would need dedicated headset/controller runtime owners, user-facing settings/rebinding, and Windows package validation.");
|
||||
return TEXT("Current XR host/plugin decision: bounded OpenXR runtime ownership is now first-party-owned inside the desktop simulator, but full native controller widening remains desktop-hosted No-Go until polished settings/rebinding follow-through and Windows packaged controller validation are complete.");
|
||||
}
|
||||
|
||||
FString BuildControlSettingsXrBoundaryLine(const bool bOpenXrProjectPluginEnabled)
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("XR/controller completion: the host decision is already fixed to desktop-hosted No-Go; project OpenXR plugin %s; dedicated runtime owners, polished settings/rebinding, and packaged controller proof are not yet shipped."),
|
||||
TEXT("XR/controller completion: the broader host decision remains desktop-hosted No-Go; project OpenXR plugin %s; bounded runtime owners now exist, but polished settings/rebinding follow-through and packaged controller proof are not yet shipped."),
|
||||
bOpenXrProjectPluginEnabled ? TEXT("enabled") : TEXT("not enabled")
|
||||
);
|
||||
}
|
||||
|
|
@ -572,7 +704,7 @@ namespace HyperTwistTrainingPanelWidgetInternal
|
|||
FString BuildControlProfileRosterXrBoundaryLine(const bool bOpenXrProjectPluginEnabled)
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("Controller rebinding: not yet shipped; the current native roster ends at keyboard, scenic presence presets, and dedicated family selector/view profiles, the project OpenXR plugin is %s, and the XR host decision remains desktop-hosted No-Go on native OpenXR/controller widening."),
|
||||
TEXT("Controller rebinding: not yet shipped; the current native roster now includes a bounded OpenXR runtime plus controller binding profile, but the project OpenXR plugin is %s and the broader XR host decision remains desktop-hosted No-Go until packaged proof and richer settings/rebinding are complete."),
|
||||
bOpenXrProjectPluginEnabled ? TEXT("enabled") : TEXT("not enabled")
|
||||
);
|
||||
}
|
||||
|
|
@ -1305,8 +1437,24 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface(
|
|||
HyperTwistTrainingPanelWidgetInternal::BuildImmersiveSessionRecallFacts();
|
||||
const bool bImmersiveSessionRecallReady =
|
||||
ImmersiveSessionRecallFacts.bReady;
|
||||
const bool bBoundedPreferencesContinuityReady =
|
||||
bCameraSettingsContinuityReady && bImmersiveSessionRecallReady;
|
||||
const HyperTwistTrainingPanelWidgetInternal::FXrRuntimeOwnershipFacts
|
||||
XrRuntimeOwnershipFacts =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrRuntimeOwnershipFacts();
|
||||
Surface.XrRuntimeOwnerId = XrRuntimeOwnershipFacts.RuntimeSurface.RuntimeOwnerId;
|
||||
Surface.XrPreferenceProfileId = XrRuntimeOwnershipFacts.PreferenceProfile.ProfileId;
|
||||
Surface.XrControllerBindingProfileId =
|
||||
XrRuntimeOwnershipFacts.ControllerBindingProfile.ProfileId;
|
||||
Surface.XrPreferenceFieldCount = XrRuntimeOwnershipFacts.PreferenceFieldCount;
|
||||
Surface.XrControllerBindingAxisCount =
|
||||
XrRuntimeOwnershipFacts.ControllerBindingAxisCount;
|
||||
Surface.XrSupportedControllerFamilyCount =
|
||||
XrRuntimeOwnershipFacts.SupportedControllerFamilyCount;
|
||||
Surface.bBoundedXrRuntimeOwnerReady =
|
||||
XrRuntimeOwnershipFacts.bRuntimeOwnerReady;
|
||||
Surface.bXrPreferenceProfileReady =
|
||||
XrRuntimeOwnershipFacts.bPreferenceProfileReady;
|
||||
Surface.bXrControllerBindingProfileReady =
|
||||
XrRuntimeOwnershipFacts.bControllerBindingProfileReady;
|
||||
|
||||
Surface.bFinishedXrRuntimeReady = false;
|
||||
Surface.bFinishedPreferencesReady = false;
|
||||
|
|
@ -1323,7 +1471,7 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface(
|
|||
XrBoundaryFacts.bRequiresWindowsPackagedControllerValidationForReopen;
|
||||
|
||||
Surface.SummaryLine = FString::Printf(
|
||||
TEXT("Keyboard and mouse lanes are ready today; XR/controller groundwork exists, the project OpenXR plugin is %s, and finished XR runtime remains intentionally unshipped."),
|
||||
TEXT("Keyboard and mouse lanes are ready today; bounded OpenXR runtime ownership, controller bindings, and preference profiles now exist, the project OpenXR plugin is %s, and finished packaged XR proof remains intentionally unshipped."),
|
||||
Surface.bOpenXrProjectPluginEnabled ? TEXT("enabled") : TEXT("not enabled")
|
||||
);
|
||||
Surface.ClassicCubeStatusLine = FString::Printf(
|
||||
|
|
@ -1364,7 +1512,7 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface(
|
|||
? FString::Join(InputGroundworkFacts.MotionControllerFamilies, TEXT(", "))
|
||||
: FString(TEXT("none"));
|
||||
Surface.XrStatusLine = FString::Printf(
|
||||
TEXT("XR groundwork: EnhancedInput config %s | motion controls %s | controller families %d (%s) | OpenXR project plugin %s | immersive presence contract %s | finished XR runtime not yet shipped."),
|
||||
TEXT("XR groundwork: EnhancedInput config %s | motion controls %s | controller families %d (%s) | OpenXR project plugin %s | immersive presence contract %s | bounded runtime owner %s (%s) | controller binding %s (%s) | finished XR runtime not yet shipped."),
|
||||
*HyperTwistTrainingPanelWidgetInternal::DescribeBool(
|
||||
Surface.bEnhancedInputProjectGroundworkPresent),
|
||||
*HyperTwistTrainingPanelWidgetInternal::DescribeBool(
|
||||
|
|
@ -1374,7 +1522,15 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface(
|
|||
*HyperTwistTrainingPanelWidgetInternal::DescribeBool(
|
||||
Surface.bOpenXrProjectPluginEnabled),
|
||||
*HyperTwistTrainingPanelWidgetInternal::DescribeBool(
|
||||
Surface.bImmersivePresenceContractReady)
|
||||
Surface.bImmersivePresenceContractReady),
|
||||
*HyperTwistTrainingPanelWidgetInternal::DescribeBool(
|
||||
Surface.bBoundedXrRuntimeOwnerReady),
|
||||
*HyperTwistTrainingPanelWidgetInternal::DescribeIdOrFallback(
|
||||
Surface.XrRuntimeOwnerId),
|
||||
*HyperTwistTrainingPanelWidgetInternal::DescribeBool(
|
||||
Surface.bXrControllerBindingProfileReady),
|
||||
*HyperTwistTrainingPanelWidgetInternal::DescribeIdOrFallback(
|
||||
Surface.XrControllerBindingProfileId)
|
||||
);
|
||||
Surface.PreferencesStatusLine =
|
||||
HyperTwistTrainingControlSurfaceFormatting::BuildControlInputPreferencesStatusLine(
|
||||
|
|
@ -1385,6 +1541,18 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface(
|
|||
ImmersiveSessionRecallFacts.Boundary.RecallScopeIds.Num(),
|
||||
ImmersiveSessionRecallFacts.Boundary.PreferenceFieldTags.Num()
|
||||
);
|
||||
Surface.XrRuntimeOwnerLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrRuntimeOwnerLine(
|
||||
XrRuntimeOwnershipFacts
|
||||
);
|
||||
Surface.XrPreferenceOwnerLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrPreferenceOwnerLine(
|
||||
XrRuntimeOwnershipFacts
|
||||
);
|
||||
Surface.XrControllerBindingLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrControllerBindingLine(
|
||||
XrRuntimeOwnershipFacts
|
||||
);
|
||||
Surface.NextPacketLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildControlInputXrBoundaryLine();
|
||||
Surface.StatusLine = FString::Printf(
|
||||
|
|
@ -1405,7 +1573,7 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface(
|
|||
: TEXT("limited")
|
||||
);
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("%s | %s | %s | %s | %s | %s | %s | %s"),
|
||||
TEXT("%s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s"),
|
||||
*Surface.ClassicCubeStatusLine,
|
||||
*Surface.ClassicCubePointerLine,
|
||||
*Surface.ClassicCubeActionShortcutLine,
|
||||
|
|
@ -1413,6 +1581,9 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlInputReadinessInspectSurface(
|
|||
*Surface.HigherDimensionalStatusLine,
|
||||
*Surface.XrStatusLine,
|
||||
*Surface.PreferencesStatusLine,
|
||||
*Surface.XrRuntimeOwnerLine,
|
||||
*Surface.XrPreferenceOwnerLine,
|
||||
*Surface.XrControllerBindingLine,
|
||||
*Surface.NextPacketLine
|
||||
);
|
||||
return Surface;
|
||||
|
|
@ -1605,6 +1776,22 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
|
|||
);
|
||||
Surface.bRepositoryBackedSelectorRecallReady = SelectorRecallFacts.bReady;
|
||||
Surface.RecalledHigherDimensionalSelectorCount = SelectorRecallFacts.SelectorCount;
|
||||
const HyperTwistTrainingPanelWidgetInternal::FXrRuntimeOwnershipFacts
|
||||
XrRuntimeOwnershipFacts =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrRuntimeOwnershipFacts();
|
||||
Surface.XrRuntimeOwnerId = XrRuntimeOwnershipFacts.RuntimeSurface.RuntimeOwnerId;
|
||||
Surface.XrPreferenceProfileId = XrRuntimeOwnershipFacts.PreferenceProfile.ProfileId;
|
||||
Surface.XrControllerBindingProfileId =
|
||||
XrRuntimeOwnershipFacts.ControllerBindingProfile.ProfileId;
|
||||
Surface.XrPreferenceFieldCount = XrRuntimeOwnershipFacts.PreferenceFieldCount;
|
||||
Surface.XrControllerBindingAxisCount =
|
||||
XrRuntimeOwnershipFacts.ControllerBindingAxisCount;
|
||||
Surface.XrSupportedControllerFamilyCount =
|
||||
XrRuntimeOwnershipFacts.SupportedControllerFamilyCount;
|
||||
Surface.bXrPreferenceProfileReady =
|
||||
XrRuntimeOwnershipFacts.bPreferenceProfileReady;
|
||||
Surface.bXrControllerBindingProfileReady =
|
||||
XrRuntimeOwnershipFacts.bControllerBindingProfileReady;
|
||||
|
||||
Surface.bHigherDimensionalSelectorSettingsReady =
|
||||
Surface.bMagic120CellViewSettingsReady
|
||||
|
|
@ -1635,7 +1822,7 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
|
|||
&& Surface.MagicCube5DSelectorCount > 0;
|
||||
|
||||
Surface.SummaryLine =
|
||||
TEXT("Camera, immersive, and dedicated-family projection, selector, continuity, and persistence settings are already first-party owned, while XR/controller rebinding still remains unfinished.");
|
||||
TEXT("Camera, immersive, dedicated-family, and bounded XR preference settings are already first-party owned, while packaged controller proof and broader rebinding polish still remain unfinished.");
|
||||
Surface.CameraSettingsLine =
|
||||
HyperTwistTrainingControlSurfaceFormatting::BuildControlSettingsCameraSettingsLine(
|
||||
Surface.bCameraSettingsReady,
|
||||
|
|
@ -1711,6 +1898,10 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
|
|||
HyperTwistTrainingPanelWidgetInternal::BuildSelectorRecallLine(
|
||||
SelectorRecallFacts
|
||||
);
|
||||
Surface.XrSettingsOwnershipLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrPreferenceOwnerLine(
|
||||
XrRuntimeOwnershipFacts
|
||||
);
|
||||
Surface.XrGapLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildControlSettingsXrBoundaryLine(
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
|
|
@ -1730,13 +1921,14 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
|
|||
Surface.bRepositoryBackedSelectorRecallReady
|
||||
);
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("%s | %s | %s | %s | %s | %s | %s"),
|
||||
TEXT("%s | %s | %s | %s | %s | %s | %s | %s"),
|
||||
*Surface.CameraSettingsLine,
|
||||
*Surface.ImmersiveSettingsLine,
|
||||
*Surface.Magic120CellSettingsLine,
|
||||
*Surface.MagicCube5DSettingsLine,
|
||||
*Surface.SelectorSettingsLine,
|
||||
*Surface.SelectorRecallLine,
|
||||
*Surface.XrSettingsOwnershipLine,
|
||||
*Surface.XrGapLine
|
||||
);
|
||||
|
||||
|
|
@ -1891,6 +2083,22 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlProfileRosterInspectSurface()
|
|||
);
|
||||
Surface.bRepositoryBackedSelectorRecallReady = SelectorRecallFacts.bReady;
|
||||
Surface.RecalledHigherDimensionalSelectorCount = SelectorRecallFacts.SelectorCount;
|
||||
const HyperTwistTrainingPanelWidgetInternal::FXrRuntimeOwnershipFacts
|
||||
XrRuntimeOwnershipFacts =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrRuntimeOwnershipFacts();
|
||||
Surface.XrRuntimeOwnerId = XrRuntimeOwnershipFacts.RuntimeSurface.RuntimeOwnerId;
|
||||
Surface.XrPreferenceProfileId = XrRuntimeOwnershipFacts.PreferenceProfile.ProfileId;
|
||||
Surface.XrControllerBindingProfileId =
|
||||
XrRuntimeOwnershipFacts.ControllerBindingProfile.ProfileId;
|
||||
Surface.XrPreferenceFieldCount = XrRuntimeOwnershipFacts.PreferenceFieldCount;
|
||||
Surface.XrControllerBindingAxisCount =
|
||||
XrRuntimeOwnershipFacts.ControllerBindingAxisCount;
|
||||
Surface.XrSupportedControllerFamilyCount =
|
||||
XrRuntimeOwnershipFacts.SupportedControllerFamilyCount;
|
||||
Surface.bXrPreferenceProfileReady =
|
||||
XrRuntimeOwnershipFacts.bPreferenceProfileReady;
|
||||
Surface.bXrControllerBindingProfileReady =
|
||||
XrRuntimeOwnershipFacts.bControllerBindingProfileReady;
|
||||
|
||||
Surface.bFinishedControllerRebindingReady = false;
|
||||
Surface.bOpenXrProjectPluginEnabled =
|
||||
|
|
@ -1949,7 +2157,7 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlProfileRosterInspectSurface()
|
|||
? Surface.ActiveHigherDimensionalInteractiveSceneSurfaceId
|
||||
: TEXT("none");
|
||||
Surface.SummaryLine =
|
||||
TEXT("The shipped selectable roster currently covers the classic keyboard mapping, scenic immersive presets, bounded camera or immersive continuity, and dedicated 120-cell/5D view-selector families, while controller rebinding still remains unfinished.");
|
||||
TEXT("The shipped selectable roster currently covers the classic keyboard mapping, scenic immersive presets, bounded XR controller profiles, bounded camera or immersive continuity, and dedicated 120-cell/5D view-selector families, while controller rebinding still remains unfinished.");
|
||||
Surface.ClassicKeyboardProfileLine = FString::Printf(
|
||||
TEXT("Classic keyboard profile: %s | bindings %d | ctrl suppressed %s | alt suppressed %s | meta suppressed %s | repeat suppressed %s."),
|
||||
*ClassicKeyboardProfileName,
|
||||
|
|
@ -2015,6 +2223,10 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlProfileRosterInspectSurface()
|
|||
Surface.ImmersiveSessionRecallScopeCount,
|
||||
Surface.ImmersiveSessionRecallPreferenceFieldTagCount
|
||||
);
|
||||
Surface.XrControllerProfileLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildXrControllerBindingLine(
|
||||
XrRuntimeOwnershipFacts
|
||||
);
|
||||
Surface.PreferencesGapLine =
|
||||
HyperTwistTrainingPanelWidgetInternal::BuildControlProfileRosterXrBoundaryLine(
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
|
|
@ -2031,7 +2243,7 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlProfileRosterInspectSurface()
|
|||
Surface.bImmersiveSessionRecallReady
|
||||
);
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("%s | %s | %s | %s | %s | %s | %s | %s | %s"),
|
||||
TEXT("%s | %s | %s | %s | %s | %s | %s | %s | %s | %s"),
|
||||
*Surface.ClassicKeyboardProfileLine,
|
||||
*Surface.ClassicKeyboardMoveRosterLine,
|
||||
*Surface.ImmersivePresenceProfileLine,
|
||||
|
|
@ -2040,6 +2252,7 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlProfileRosterInspectSurface()
|
|||
*Surface.ActiveHigherDimensionalProfileLine,
|
||||
*Surface.SelectorRecallLine,
|
||||
*Surface.PreferencesContinuityLine,
|
||||
*Surface.XrControllerProfileLine,
|
||||
*Surface.PreferencesGapLine
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
#include "HyperTwistXR/HyperTwistXrRuntimeLibrary.h"
|
||||
|
||||
namespace HyperTwistXrRuntimeLibraryInternal
|
||||
{
|
||||
FHyperTwistTrainingSourceAttribution MakeFirstPartyAttribution(
|
||||
const FString& TrackId,
|
||||
const FString& Notes
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingSourceAttribution Attribution;
|
||||
Attribution.SourceMode = EHyperTwistTrainingSourceMode::FirstParty;
|
||||
Attribution.SourceTrackId = TrackId;
|
||||
Attribution.SourceNotes = Notes;
|
||||
return Attribution;
|
||||
}
|
||||
}
|
||||
|
||||
FHyperTwistXrPreferenceProfile UHyperTwistXrRuntimeLibrary::GetDefaultXrPreferenceProfile()
|
||||
{
|
||||
using namespace HyperTwistXrRuntimeLibraryInternal;
|
||||
|
||||
FHyperTwistXrPreferenceProfile Profile;
|
||||
Profile.ProfileId = TEXT("xr-openxr-training-preferences/v1");
|
||||
Profile.Title = TEXT("OpenXR desktop-training preferences");
|
||||
Profile.Summary = TEXT("First-party desktop-hosted OpenXR preference bundle for locomotion, comfort, posture, world scale, and dominant-hand defaults beneath the still-bounded XR runtime lane.");
|
||||
Profile.PreferenceFieldTags =
|
||||
{
|
||||
TEXT("movement speed"),
|
||||
TEXT("vertical adjustment"),
|
||||
TEXT("snap turn"),
|
||||
TEXT("smooth turn fallback"),
|
||||
TEXT("pointer length"),
|
||||
TEXT("world scale"),
|
||||
TEXT("dominant hand"),
|
||||
TEXT("posture mode")
|
||||
};
|
||||
Profile.ComfortSurfaceTags =
|
||||
{
|
||||
TEXT("comfort vignette strength"),
|
||||
TEXT("seated height offset"),
|
||||
TEXT("snap-turn comfort"),
|
||||
TEXT("world-scale recenter")
|
||||
};
|
||||
Profile.ExplicitExclusions =
|
||||
{
|
||||
TEXT("platform-global guardian ownership"),
|
||||
TEXT("cross-title cloud remap storage"),
|
||||
TEXT("generic social VR avatar shell")
|
||||
};
|
||||
Profile.SourceAttribution = MakeFirstPartyAttribution(
|
||||
TEXT("first-party/xr-openxr-training-preferences"),
|
||||
TEXT("Owns first-party XR training preferences for HyperTwist without promoting the remaining packaged-controller validation gate to finished product status.")
|
||||
);
|
||||
return Profile;
|
||||
}
|
||||
|
||||
FHyperTwistXrControllerBindingProfile
|
||||
UHyperTwistXrRuntimeLibrary::GetDefaultXrControllerBindingProfile()
|
||||
{
|
||||
using namespace HyperTwistXrRuntimeLibraryInternal;
|
||||
|
||||
FHyperTwistXrControllerBindingProfile Profile;
|
||||
Profile.ProfileId = TEXT("xr-openxr-motion-controllers/v1");
|
||||
Profile.Title = TEXT("OpenXR motion-controller binding profile");
|
||||
Profile.Summary = TEXT("First-party motion-controller axis profile for locomotion, turning, grip, and trigger ownership inside the bounded HyperTwist XR training lane.");
|
||||
Profile.RequiredAxisNames =
|
||||
{
|
||||
TEXT("HyperTwistXr_MoveForward"),
|
||||
TEXT("HyperTwistXr_MoveRight"),
|
||||
TEXT("HyperTwistXr_Turn"),
|
||||
TEXT("HyperTwistXr_LookPitch"),
|
||||
TEXT("HyperTwistXr_LeftGrip"),
|
||||
TEXT("HyperTwistXr_RightGrip"),
|
||||
TEXT("HyperTwistXr_LeftTrigger"),
|
||||
TEXT("HyperTwistXr_RightTrigger")
|
||||
};
|
||||
Profile.ControllerFamilyIds =
|
||||
{
|
||||
TEXT("controller/vive"),
|
||||
TEXT("controller/mixed-reality"),
|
||||
TEXT("controller/oculus-touch"),
|
||||
TEXT("controller/valve-index")
|
||||
};
|
||||
Profile.InteractionSurfaceTags =
|
||||
{
|
||||
TEXT("camera-aligned locomotion vector"),
|
||||
TEXT("snap-turn ownership"),
|
||||
TEXT("trigger and grip value capture"),
|
||||
TEXT("bounded desktop-hosted XR interaction")
|
||||
};
|
||||
Profile.ExplicitExclusions =
|
||||
{
|
||||
TEXT("platform-global controller remap UI"),
|
||||
TEXT("vendor-specific hand-tracking ownership"),
|
||||
TEXT("full room-scale locomotion sandbox")
|
||||
};
|
||||
Profile.SourceAttribution = MakeFirstPartyAttribution(
|
||||
TEXT("first-party/xr-openxr-motion-controller-bindings"),
|
||||
TEXT("Owns the HyperTwist OpenXR motion-controller binding substrate for the desktop-hosted simulator without claiming finished cross-device rebinding polish.")
|
||||
);
|
||||
return Profile;
|
||||
}
|
||||
|
||||
FHyperTwistXrRuntimeOwnershipSurface
|
||||
UHyperTwistXrRuntimeLibrary::BuildBundledXrRuntimeOwnershipSurface()
|
||||
{
|
||||
using namespace HyperTwistXrRuntimeLibraryInternal;
|
||||
|
||||
const FHyperTwistXrPreferenceProfile PreferenceProfile = GetDefaultXrPreferenceProfile();
|
||||
const FHyperTwistXrControllerBindingProfile BindingProfile =
|
||||
GetDefaultXrControllerBindingProfile();
|
||||
|
||||
FHyperTwistXrRuntimeOwnershipSurface Surface;
|
||||
Surface.RuntimeOwnerId = TEXT("xr/openxr-desktop-training-runtime-owner");
|
||||
Surface.Title = TEXT("Desktop-hosted OpenXR training runtime owner");
|
||||
Surface.Summary = TEXT("Bounded first-party OpenXR runtime owner for motion-controller anchors, camera-aligned locomotion, comfort-aware turning, and preference-driven desktop XR training posture beneath the still-open packaged-controller proof gate.");
|
||||
Surface.PreferenceProfileId = PreferenceProfile.ProfileId;
|
||||
Surface.ControllerBindingProfileId = BindingProfile.ProfileId;
|
||||
Surface.WorldAnchorContractId = TEXT("immersive-training-world-anchor-contract");
|
||||
Surface.LeftMotionSourceId = TEXT("Left");
|
||||
Surface.RightMotionSourceId = TEXT("Right");
|
||||
Surface.RequiredPackageIds =
|
||||
{
|
||||
TEXT("package/hypertwist-immersive-environment-shell"),
|
||||
TEXT("package/hypertwist-immersive-world-anchors"),
|
||||
TEXT("package/hypertwist-immersive-focus-presence-controls")
|
||||
};
|
||||
Surface.RequiredSurfaceTags =
|
||||
{
|
||||
TEXT("motion-controller pose anchors"),
|
||||
TEXT("camera-aligned locomotion vector"),
|
||||
TEXT("training-world recenter"),
|
||||
TEXT("bounded trigger and grip interaction")
|
||||
};
|
||||
Surface.SupportedControllerFamilies = BindingProfile.ControllerFamilyIds;
|
||||
Surface.ExplicitExclusions =
|
||||
{
|
||||
TEXT("platform-global guardian ownership"),
|
||||
TEXT("generic social VR hub ownership"),
|
||||
TEXT("launch-tier packaged controller certification ownership")
|
||||
};
|
||||
Surface.SourceAttribution = MakeFirstPartyAttribution(
|
||||
TEXT("first-party/xr-openxr-runtime-owner"),
|
||||
TEXT("Owns the bounded OpenXR runtime-owner seam for HyperTwist desktop XR training while keeping finished controller validation and cross-device launch certification outside the current packet.")
|
||||
);
|
||||
return Surface;
|
||||
}
|
||||
|
|
@ -0,0 +1,486 @@
|
|||
#include "HyperTwistXR/HyperTwistXrTrainingPawn.h"
|
||||
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Components/SceneComponent.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "HeadMountedDisplayFunctionLibrary.h"
|
||||
#include "InputCoreTypes.h"
|
||||
#include "MotionControllerComponent.h"
|
||||
|
||||
namespace HyperTwistXrTrainingPawnInternal
|
||||
{
|
||||
constexpr float SeatedHeightOffset = -42.0f;
|
||||
constexpr float HybridHeightOffset = -20.0f;
|
||||
constexpr float DesktopFallbackPitchMin = -65.0f;
|
||||
constexpr float DesktopFallbackPitchMax = 65.0f;
|
||||
|
||||
FVector BuildPlanarDirection(const FVector& RawDirection)
|
||||
{
|
||||
FVector Result = FVector::VectorPlaneProject(RawDirection, FVector::UpVector);
|
||||
Result.Normalize();
|
||||
return Result;
|
||||
}
|
||||
|
||||
float ApplyDeadZone(const float Value, const float DeadZone)
|
||||
{
|
||||
return FMath::Abs(Value) >= DeadZone ? Value : 0.0f;
|
||||
}
|
||||
|
||||
const TCHAR* DescribeDominantHand(const EHyperTwistXrDominantHand DominantHand)
|
||||
{
|
||||
return DominantHand == EHyperTwistXrDominantHand::Left
|
||||
? TEXT("left")
|
||||
: TEXT("right");
|
||||
}
|
||||
|
||||
const TCHAR* DescribePostureMode(const EHyperTwistXrPostureMode PostureMode)
|
||||
{
|
||||
switch (PostureMode)
|
||||
{
|
||||
case EHyperTwistXrPostureMode::Seated:
|
||||
return TEXT("seated");
|
||||
case EHyperTwistXrPostureMode::Hybrid:
|
||||
return TEXT("hybrid");
|
||||
default:
|
||||
return TEXT("standing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AHyperTwistXrTrainingPawn::AHyperTwistXrTrainingPawn()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
AutoPossessPlayer = EAutoReceiveInput::Player0;
|
||||
|
||||
SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
|
||||
SetRootComponent(SceneRoot);
|
||||
|
||||
VROrigin = CreateDefaultSubobject<USceneComponent>(TEXT("VROrigin"));
|
||||
VROrigin->SetupAttachment(SceneRoot);
|
||||
|
||||
CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
|
||||
CameraComponent->SetupAttachment(VROrigin);
|
||||
|
||||
LeftController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("LeftController"));
|
||||
LeftController->SetupAttachment(VROrigin);
|
||||
LeftController->SetTrackingMotionSource(TEXT("Left"));
|
||||
|
||||
RightController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("RightController"));
|
||||
RightController->SetupAttachment(VROrigin);
|
||||
RightController->SetTrackingMotionSource(TEXT("Right"));
|
||||
|
||||
LeftPointerAnchor = CreateDefaultSubobject<USceneComponent>(TEXT("LeftPointerAnchor"));
|
||||
LeftPointerAnchor->SetupAttachment(LeftController);
|
||||
|
||||
RightPointerAnchor = CreateDefaultSubobject<USceneComponent>(TEXT("RightPointerAnchor"));
|
||||
RightPointerAnchor->SetupAttachment(RightController);
|
||||
|
||||
ActivePreferenceProfile = UHyperTwistXrRuntimeLibrary::GetDefaultXrPreferenceProfile();
|
||||
ActiveControllerBindingProfile =
|
||||
UHyperTwistXrRuntimeLibrary::GetDefaultXrControllerBindingProfile();
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
ApplyPreferenceProfile(ActivePreferenceProfile);
|
||||
if (bAutoResetOrientationOnBeginPlay)
|
||||
{
|
||||
ResetXrOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::Tick(const float DeltaSeconds)
|
||||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
|
||||
RefreshHeadMountedDisplayState();
|
||||
UpdateSmoothLocomotion(DeltaSeconds);
|
||||
UpdateTurn(DeltaSeconds);
|
||||
UpdateDesktopFallbackPitch(DeltaSeconds);
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::SetupPlayerInputComponent(
|
||||
UInputComponent* PlayerInputComponent
|
||||
)
|
||||
{
|
||||
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||
if (PlayerInputComponent == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_MoveForward"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleMoveForward
|
||||
);
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_MoveRight"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleMoveRight
|
||||
);
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_Turn"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleTurnAxis
|
||||
);
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_LookPitch"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleLookPitchAxis
|
||||
);
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_LeftGrip"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleLeftGripAxis
|
||||
);
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_RightGrip"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleRightGripAxis
|
||||
);
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_LeftTrigger"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleLeftTriggerAxis
|
||||
);
|
||||
PlayerInputComponent->BindAxis(
|
||||
TEXT("HyperTwistXr_RightTrigger"),
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleRightTriggerAxis
|
||||
);
|
||||
PlayerInputComponent->BindAction(
|
||||
TEXT("HyperTwistXr_Recenter"),
|
||||
IE_Pressed,
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::ResetXrOrigin
|
||||
);
|
||||
PlayerInputComponent->BindAction(
|
||||
TEXT("HyperTwistXr_ToggleSnapTurn"),
|
||||
IE_Pressed,
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleToggleSnapTurn
|
||||
);
|
||||
PlayerInputComponent->BindAction(
|
||||
TEXT("HyperTwistXr_TogglePostureMode"),
|
||||
IE_Pressed,
|
||||
this,
|
||||
&AHyperTwistXrTrainingPawn::HandleTogglePostureMode
|
||||
);
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::ApplyPreferenceProfile(
|
||||
const FHyperTwistXrPreferenceProfile& PreferenceProfile
|
||||
)
|
||||
{
|
||||
if (!PreferenceProfile.IsStructurallyValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ActivePreferenceProfile = PreferenceProfile;
|
||||
ApplyPostureOffset();
|
||||
ApplyPointerAnchors();
|
||||
|
||||
if (GetWorld() != nullptr)
|
||||
{
|
||||
UHeadMountedDisplayFunctionLibrary::SetWorldToMetersScale(
|
||||
this,
|
||||
ActivePreferenceProfile.WorldToMetersScale
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::SetDominantHand(
|
||||
const EHyperTwistXrDominantHand DominantHand
|
||||
)
|
||||
{
|
||||
ActivePreferenceProfile.DominantHand = DominantHand;
|
||||
ApplyPointerAnchors();
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::SetPostureMode(
|
||||
const EHyperTwistXrPostureMode PostureMode
|
||||
)
|
||||
{
|
||||
ActivePreferenceProfile.PostureMode = PostureMode;
|
||||
ApplyPostureOffset();
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::SetSnapTurnEnabled(const bool bEnabled)
|
||||
{
|
||||
ActivePreferenceProfile.bSnapTurnEnabled = bEnabled;
|
||||
ActivePreferenceProfile.bSmoothTurnFallbackEnabled = !bEnabled;
|
||||
bSnapTurnLatchOpen = true;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::ResetXrOrigin()
|
||||
{
|
||||
DesktopFallbackPitchDegrees = 0.0f;
|
||||
ApplyDesktopFallbackRotation();
|
||||
ApplyPostureOffset();
|
||||
UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
|
||||
}
|
||||
|
||||
FHyperTwistXrRuntimeOwnershipSurface
|
||||
AHyperTwistXrTrainingPawn::GetBoundedRuntimeOwnershipSurface() const
|
||||
{
|
||||
return UHyperTwistXrRuntimeLibrary::BuildBundledXrRuntimeOwnershipSurface();
|
||||
}
|
||||
|
||||
FString AHyperTwistXrTrainingPawn::BuildRuntimeStatusLine() const
|
||||
{
|
||||
const FHyperTwistXrRuntimeOwnershipSurface RuntimeSurface =
|
||||
GetBoundedRuntimeOwnershipSurface();
|
||||
return FString::Printf(
|
||||
TEXT("OpenXR runtime owner %s | preferences %s | bindings %s | HMD connected %s | HMD enabled %s | posture %s | dominant hand %s | snap turn %s | smooth locomotion %s | grip %.2f/%.2f | trigger %.2f/%.2f"),
|
||||
*RuntimeSurface.RuntimeOwnerId,
|
||||
*ActivePreferenceProfile.ProfileId,
|
||||
*ActiveControllerBindingProfile.ProfileId,
|
||||
bHeadMountedDisplayConnected ? TEXT("yes") : TEXT("no"),
|
||||
bHeadMountedDisplayEnabled ? TEXT("yes") : TEXT("no"),
|
||||
HyperTwistXrTrainingPawnInternal::DescribePostureMode(
|
||||
ActivePreferenceProfile.PostureMode),
|
||||
HyperTwistXrTrainingPawnInternal::DescribeDominantHand(
|
||||
ActivePreferenceProfile.DominantHand),
|
||||
ActivePreferenceProfile.bSnapTurnEnabled ? TEXT("on") : TEXT("off"),
|
||||
ActivePreferenceProfile.bSmoothLocomotionEnabled ? TEXT("on") : TEXT("off"),
|
||||
LeftGripValue,
|
||||
RightGripValue,
|
||||
LeftTriggerValue,
|
||||
RightTriggerValue
|
||||
);
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::ApplyPostureOffset()
|
||||
{
|
||||
if (VROrigin == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float HeightOffset = 0.0f;
|
||||
switch (ActivePreferenceProfile.PostureMode)
|
||||
{
|
||||
case EHyperTwistXrPostureMode::Seated:
|
||||
HeightOffset = HyperTwistXrTrainingPawnInternal::SeatedHeightOffset;
|
||||
break;
|
||||
case EHyperTwistXrPostureMode::Hybrid:
|
||||
HeightOffset = HyperTwistXrTrainingPawnInternal::HybridHeightOffset;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
VROrigin->SetRelativeLocation(FVector(0.0f, 0.0f, HeightOffset));
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::ApplyPointerAnchors()
|
||||
{
|
||||
if (LeftPointerAnchor != nullptr)
|
||||
{
|
||||
LeftPointerAnchor->SetRelativeLocation(
|
||||
FVector(ActivePreferenceProfile.PointerLengthUnits, 0.0f, 0.0f)
|
||||
);
|
||||
}
|
||||
|
||||
if (RightPointerAnchor != nullptr)
|
||||
{
|
||||
RightPointerAnchor->SetRelativeLocation(
|
||||
FVector(ActivePreferenceProfile.PointerLengthUnits, 0.0f, 0.0f)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::ApplyDesktopFallbackRotation()
|
||||
{
|
||||
if (VROrigin == nullptr || bHeadMountedDisplayEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FRotator CurrentRotation = VROrigin->GetRelativeRotation();
|
||||
VROrigin->SetRelativeRotation(
|
||||
FRotator(
|
||||
DesktopFallbackPitchDegrees,
|
||||
CurrentRotation.Yaw,
|
||||
CurrentRotation.Roll
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::RefreshHeadMountedDisplayState()
|
||||
{
|
||||
bHeadMountedDisplayConnected =
|
||||
UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayConnected();
|
||||
bHeadMountedDisplayEnabled =
|
||||
UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled();
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::UpdateSmoothLocomotion(const float DeltaSeconds)
|
||||
{
|
||||
if (!ActivePreferenceProfile.bSmoothLocomotionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float MoveForward = HyperTwistXrTrainingPawnInternal::ApplyDeadZone(
|
||||
PendingMoveForward,
|
||||
ActivePreferenceProfile.ControllerDeadZone
|
||||
);
|
||||
const float MoveRight = HyperTwistXrTrainingPawnInternal::ApplyDeadZone(
|
||||
PendingMoveRight,
|
||||
ActivePreferenceProfile.ControllerDeadZone
|
||||
);
|
||||
if (FMath::IsNearlyZero(MoveForward) && FMath::IsNearlyZero(MoveRight))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FVector ForwardDirection = HyperTwistXrTrainingPawnInternal::BuildPlanarDirection(
|
||||
CameraComponent != nullptr ? CameraComponent->GetForwardVector() : GetActorForwardVector()
|
||||
);
|
||||
const FVector RightDirection = HyperTwistXrTrainingPawnInternal::BuildPlanarDirection(
|
||||
CameraComponent != nullptr ? CameraComponent->GetRightVector() : GetActorRightVector()
|
||||
);
|
||||
const FVector Delta =
|
||||
(ForwardDirection * MoveForward + RightDirection * MoveRight)
|
||||
* ActivePreferenceProfile.MoveSpeedUnitsPerSecond
|
||||
* DeltaSeconds;
|
||||
AddActorWorldOffset(Delta, true);
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::UpdateTurn(const float DeltaSeconds)
|
||||
{
|
||||
const float TurnValue = HyperTwistXrTrainingPawnInternal::ApplyDeadZone(
|
||||
PendingTurnAxis,
|
||||
ActivePreferenceProfile.ControllerDeadZone
|
||||
);
|
||||
if (FMath::IsNearlyZero(TurnValue))
|
||||
{
|
||||
bSnapTurnLatchOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ActivePreferenceProfile.bSnapTurnEnabled)
|
||||
{
|
||||
if (bSnapTurnLatchOpen
|
||||
&& FMath::Abs(TurnValue) >= ActivePreferenceProfile.SnapTurnAxisThreshold)
|
||||
{
|
||||
const float Direction = TurnValue > 0.0f ? 1.0f : -1.0f;
|
||||
AddActorWorldRotation(
|
||||
FRotator(0.0f, Direction * ActivePreferenceProfile.SnapTurnDegrees, 0.0f)
|
||||
);
|
||||
bSnapTurnLatchOpen = false;
|
||||
}
|
||||
|
||||
if (FMath::Abs(TurnValue) <= ActivePreferenceProfile.SnapTurnResetThreshold)
|
||||
{
|
||||
bSnapTurnLatchOpen = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ActivePreferenceProfile.bSmoothTurnFallbackEnabled)
|
||||
{
|
||||
AddActorWorldRotation(
|
||||
FRotator(
|
||||
0.0f,
|
||||
TurnValue * ActivePreferenceProfile.SmoothTurnDegreesPerSecond * DeltaSeconds,
|
||||
0.0f
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::UpdateDesktopFallbackPitch(const float DeltaSeconds)
|
||||
{
|
||||
if (bHeadMountedDisplayEnabled || VROrigin == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float PitchValue = HyperTwistXrTrainingPawnInternal::ApplyDeadZone(
|
||||
PendingLookPitchAxis,
|
||||
ActivePreferenceProfile.ControllerDeadZone
|
||||
);
|
||||
if (FMath::IsNearlyZero(PitchValue))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DesktopFallbackPitchDegrees = FMath::Clamp(
|
||||
DesktopFallbackPitchDegrees
|
||||
+ PitchValue * ActivePreferenceProfile.SmoothTurnDegreesPerSecond * DeltaSeconds,
|
||||
HyperTwistXrTrainingPawnInternal::DesktopFallbackPitchMin,
|
||||
HyperTwistXrTrainingPawnInternal::DesktopFallbackPitchMax
|
||||
);
|
||||
ApplyDesktopFallbackRotation();
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleMoveForward(const float Value)
|
||||
{
|
||||
PendingMoveForward = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleMoveRight(const float Value)
|
||||
{
|
||||
PendingMoveRight = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleTurnAxis(const float Value)
|
||||
{
|
||||
PendingTurnAxis = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleLookPitchAxis(const float Value)
|
||||
{
|
||||
PendingLookPitchAxis = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleLeftGripAxis(const float Value)
|
||||
{
|
||||
LeftGripValue = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleRightGripAxis(const float Value)
|
||||
{
|
||||
RightGripValue = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleLeftTriggerAxis(const float Value)
|
||||
{
|
||||
LeftTriggerValue = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleRightTriggerAxis(const float Value)
|
||||
{
|
||||
RightTriggerValue = Value;
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleToggleSnapTurn()
|
||||
{
|
||||
SetSnapTurnEnabled(!ActivePreferenceProfile.bSnapTurnEnabled);
|
||||
if (!ActivePreferenceProfile.bSnapTurnEnabled)
|
||||
{
|
||||
ActivePreferenceProfile.bSmoothTurnFallbackEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AHyperTwistXrTrainingPawn::HandleTogglePostureMode()
|
||||
{
|
||||
switch (ActivePreferenceProfile.PostureMode)
|
||||
{
|
||||
case EHyperTwistXrPostureMode::Standing:
|
||||
SetPostureMode(EHyperTwistXrPostureMode::Seated);
|
||||
break;
|
||||
case EHyperTwistXrPostureMode::Seated:
|
||||
SetPostureMode(EHyperTwistXrPostureMode::Hybrid);
|
||||
break;
|
||||
default:
|
||||
SetPostureMode(EHyperTwistXrPostureMode::Standing);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -10015,6 +10015,15 @@ struct FHyperTwistTrainingControlInputReadinessInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreferencesStatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrRuntimeOwnerLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrPreferenceOwnerLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrControllerBindingLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString NextPacketLine;
|
||||
|
||||
|
|
@ -10024,9 +10033,27 @@ struct FHyperTwistTrainingControlInputReadinessInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString KeyboardProfileName;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrRuntimeOwnerId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrPreferenceProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrControllerBindingProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 MotionControllerFamilyCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrPreferenceFieldCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrControllerBindingAxisCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrSupportedControllerFamilyCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bOpenXrProjectPluginEnabled = false;
|
||||
|
||||
|
|
@ -10057,6 +10084,15 @@ struct FHyperTwistTrainingControlInputReadinessInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bImmersivePresenceContractReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundedXrRuntimeOwnerReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bXrPreferenceProfileReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bXrControllerBindingProfileReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bFinishedXrRuntimeReady = false;
|
||||
|
||||
|
|
@ -10128,6 +10164,9 @@ struct FHyperTwistTrainingControlSettingsOwnershipInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SelectorRecallLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrSettingsOwnershipLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrGapLine;
|
||||
|
||||
|
|
@ -10146,6 +10185,15 @@ struct FHyperTwistTrainingControlSettingsOwnershipInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ImmersiveSessionRecallBoundaryId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrRuntimeOwnerId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrPreferenceProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrControllerBindingProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveHigherDimensionalViewContextId;
|
||||
|
||||
|
|
@ -10242,6 +10290,15 @@ struct FHyperTwistTrainingControlSettingsOwnershipInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ImmersiveSessionRecallResetSurfaceTagCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrPreferenceFieldCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrControllerBindingAxisCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrSupportedControllerFamilyCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCameraSettingsReady = false;
|
||||
|
||||
|
|
@ -10275,6 +10332,12 @@ struct FHyperTwistTrainingControlSettingsOwnershipInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRepositoryBackedSelectorRecallReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bXrPreferenceProfileReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bXrControllerBindingProfileReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bFinishedControllerRebindingReady = false;
|
||||
|
||||
|
|
@ -10356,6 +10419,9 @@ struct FHyperTwistTrainingControlProfileRosterInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreferencesContinuityLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrControllerProfileLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreferencesGapLine;
|
||||
|
||||
|
|
@ -10374,6 +10440,15 @@ struct FHyperTwistTrainingControlProfileRosterInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ImmersiveSessionRecallBoundaryId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrRuntimeOwnerId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrPreferenceProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString XrControllerBindingProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Magic120CellRuntimeProfileContractId;
|
||||
|
||||
|
|
@ -10425,6 +10500,15 @@ struct FHyperTwistTrainingControlProfileRosterInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ImmersiveSessionRecallPreferenceFieldTagCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrPreferenceFieldCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrControllerBindingAxisCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 XrSupportedControllerFamilyCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bClassicKeyboardProfileReady = false;
|
||||
|
||||
|
|
@ -10449,6 +10533,12 @@ struct FHyperTwistTrainingControlProfileRosterInspectSurface
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRepositoryBackedSelectorRecallReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bXrPreferenceProfileReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bXrControllerBindingProfileReady = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bFinishedControllerRebindingReady = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,234 @@
|
|||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "HyperTwistTraining/HyperTwistTrainingTypes.h"
|
||||
#include "HyperTwistXrRuntimeLibrary.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistXrDominantHand : uint8
|
||||
{
|
||||
Right UMETA(DisplayName = "Right"),
|
||||
Left UMETA(DisplayName = "Left")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistXrPostureMode : uint8
|
||||
{
|
||||
Standing UMETA(DisplayName = "Standing"),
|
||||
Seated UMETA(DisplayName = "Seated"),
|
||||
Hybrid UMETA(DisplayName = "Hybrid")
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistXrPreferenceProfile
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Title;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistXrDominantHand DominantHand = EHyperTwistXrDominantHand::Right;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistXrPostureMode PostureMode = EHyperTwistXrPostureMode::Standing;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float MoveSpeedUnitsPerSecond = 220.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float VerticalAdjustmentUnitsPerSecond = 120.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float SnapTurnDegrees = 30.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float SnapTurnAxisThreshold = 0.65f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float SnapTurnResetThreshold = 0.25f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float SmoothTurnDegreesPerSecond = 90.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float PointerLengthUnits = 180.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float WorldToMetersScale = 100.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float ComfortVignetteStrength = 0.35f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float ControllerDeadZone = 0.15f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSmoothLocomotionEnabled = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSnapTurnEnabled = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSmoothTurnFallbackEnabled = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bAllowVerticalAdjustment = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bMirrorSpectatorView = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHapticsEnabled = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> PreferenceFieldTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> ComfortSurfaceTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> ExplicitExclusions;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingSourceAttribution SourceAttribution;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !ProfileId.IsEmpty()
|
||||
&& !Title.IsEmpty()
|
||||
&& SourceAttribution.IsStructurallyValid();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistXrControllerBindingProfile
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Title;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> RequiredAxisNames;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> ControllerFamilyIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> InteractionSurfaceTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> ExplicitExclusions;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingSourceAttribution SourceAttribution;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !ProfileId.IsEmpty()
|
||||
&& !Title.IsEmpty()
|
||||
&& RequiredAxisNames.Num() > 0
|
||||
&& SourceAttribution.IsStructurallyValid();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistXrRuntimeOwnershipSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RuntimeOwnerId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Title;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Summary;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreferenceProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ControllerBindingProfileId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString WorldAnchorContractId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LeftMotionSourceId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RightMotionSourceId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> RequiredPackageIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> RequiredSurfaceTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> SupportedControllerFamilies;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> ExplicitExclusions;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingSourceAttribution SourceAttribution;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bOpenXrPluginRequired = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bMotionControllerComponentsRequired = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bDesktopFallbackAllowed = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bComfortProfileReady = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bControllerBindingsReady = true;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !RuntimeOwnerId.IsEmpty()
|
||||
&& !Title.IsEmpty()
|
||||
&& !PreferenceProfileId.IsEmpty()
|
||||
&& !ControllerBindingProfileId.IsEmpty()
|
||||
&& !LeftMotionSourceId.IsEmpty()
|
||||
&& !RightMotionSourceId.IsEmpty()
|
||||
&& SourceAttribution.IsStructurallyValid();
|
||||
}
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class UNREALHYPERTWIST_API UHyperTwistXrRuntimeLibrary : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|XR")
|
||||
static FHyperTwistXrPreferenceProfile GetDefaultXrPreferenceProfile();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|XR")
|
||||
static FHyperTwistXrControllerBindingProfile GetDefaultXrControllerBindingProfile();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|XR")
|
||||
static FHyperTwistXrRuntimeOwnershipSurface BuildBundledXrRuntimeOwnershipSurface();
|
||||
};
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "HyperTwistXR/HyperTwistXrRuntimeLibrary.h"
|
||||
#include "HyperTwistXrTrainingPawn.generated.h"
|
||||
|
||||
class UCameraComponent;
|
||||
class UMotionControllerComponent;
|
||||
class USceneComponent;
|
||||
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class UNREALHYPERTWIST_API AHyperTwistXrTrainingPawn : public APawn
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AHyperTwistXrTrainingPawn();
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|XR|Preferences")
|
||||
FHyperTwistXrPreferenceProfile ActivePreferenceProfile;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|XR|Bindings")
|
||||
FHyperTwistXrControllerBindingProfile ActiveControllerBindingProfile;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|XR|Runtime")
|
||||
bool bAutoResetOrientationOnBeginPlay = true;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
TObjectPtr<USceneComponent> SceneRoot = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
TObjectPtr<USceneComponent> VROrigin = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
TObjectPtr<UCameraComponent> CameraComponent = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
TObjectPtr<UMotionControllerComponent> LeftController = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
TObjectPtr<UMotionControllerComponent> RightController = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
TObjectPtr<USceneComponent> LeftPointerAnchor = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
TObjectPtr<USceneComponent> RightPointerAnchor = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
bool bHeadMountedDisplayConnected = false;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
bool bHeadMountedDisplayEnabled = false;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
float LeftGripValue = 0.0f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
float RightGripValue = 0.0f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
float LeftTriggerValue = 0.0f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|XR|Runtime")
|
||||
float RightTriggerValue = 0.0f;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
|
||||
void ApplyPreferenceProfile(const FHyperTwistXrPreferenceProfile& PreferenceProfile);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
|
||||
void SetDominantHand(EHyperTwistXrDominantHand DominantHand);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
|
||||
void SetPostureMode(EHyperTwistXrPostureMode PostureMode);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
|
||||
void SetSnapTurnEnabled(bool bEnabled);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|XR|Preferences")
|
||||
void ResetXrOrigin();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|XR|Runtime")
|
||||
FHyperTwistXrRuntimeOwnershipSurface GetBoundedRuntimeOwnershipSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|XR|Runtime")
|
||||
FString BuildRuntimeStatusLine() const;
|
||||
|
||||
protected:
|
||||
void ApplyPostureOffset();
|
||||
void ApplyPointerAnchors();
|
||||
void ApplyDesktopFallbackRotation();
|
||||
void RefreshHeadMountedDisplayState();
|
||||
void UpdateSmoothLocomotion(float DeltaSeconds);
|
||||
void UpdateTurn(float DeltaSeconds);
|
||||
void UpdateDesktopFallbackPitch(float DeltaSeconds);
|
||||
|
||||
void HandleMoveForward(float Value);
|
||||
void HandleMoveRight(float Value);
|
||||
void HandleTurnAxis(float Value);
|
||||
void HandleLookPitchAxis(float Value);
|
||||
void HandleLeftGripAxis(float Value);
|
||||
void HandleRightGripAxis(float Value);
|
||||
void HandleLeftTriggerAxis(float Value);
|
||||
void HandleRightTriggerAxis(float Value);
|
||||
void HandleToggleSnapTurn();
|
||||
void HandleTogglePostureMode();
|
||||
|
||||
float PendingMoveForward = 0.0f;
|
||||
float PendingMoveRight = 0.0f;
|
||||
float PendingTurnAxis = 0.0f;
|
||||
float PendingLookPitchAxis = 0.0f;
|
||||
float DesktopFallbackPitchDegrees = 0.0f;
|
||||
bool bSnapTurnLatchOpen = true;
|
||||
};
|
||||
|
|
@ -1147,7 +1147,7 @@ bool FHyperTwistTrainingPanelControlInputReadinessInspectSurfaceTest::RunTest(
|
|||
&& Surface.bMotionControllerGroundworkPresent
|
||||
&& Surface.bImmersivePresenceContractReady
|
||||
);
|
||||
TestFalse(
|
||||
TestTrue(
|
||||
TEXT("The control/input readiness surface must keep the current project OpenXR plugin posture explicit."),
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
);
|
||||
|
|
@ -1155,6 +1155,18 @@ bool FHyperTwistTrainingPanelControlInputReadinessInspectSurfaceTest::RunTest(
|
|||
TEXT("The control/input readiness surface must keep unfinished XR/runtime and preferences truth explicit."),
|
||||
Surface.bFinishedXrRuntimeReady || Surface.bFinishedPreferencesReady
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The control/input readiness surface must expose the bounded XR runtime owner, preference profile, and controller binding profile."),
|
||||
Surface.bBoundedXrRuntimeOwnerReady
|
||||
&& Surface.bXrPreferenceProfileReady
|
||||
&& Surface.bXrControllerBindingProfileReady
|
||||
&& Surface.XrRuntimeOwnerId == TEXT("xr/openxr-desktop-training-runtime-owner")
|
||||
&& Surface.XrPreferenceProfileId == TEXT("xr-openxr-training-preferences/v1")
|
||||
&& Surface.XrControllerBindingProfileId == TEXT("xr-openxr-motion-controllers/v1")
|
||||
&& Surface.XrPreferenceFieldCount == 8
|
||||
&& Surface.XrControllerBindingAxisCount == 8
|
||||
&& Surface.XrSupportedControllerFamilyCount == 4
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The control/input readiness surface must now expose bounded non-XR preferences continuity for camera export and immersive session recall."),
|
||||
Surface.PreferencesStatusLine.Contains(TEXT("artifact/camera-export-json"))
|
||||
|
|
@ -1177,7 +1189,9 @@ bool FHyperTwistTrainingPanelControlInputReadinessInspectSurfaceTest::RunTest(
|
|||
TestTrue(
|
||||
TEXT("The control/input readiness surface must say plainly that finished XR runtime is not yet shipped."),
|
||||
Surface.XrStatusLine.Contains(TEXT("not yet shipped"))
|
||||
&& Surface.XrStatusLine.Contains(TEXT("OpenXR project plugin no"))
|
||||
&& Surface.XrStatusLine.Contains(TEXT("OpenXR project plugin yes"))
|
||||
&& Surface.XrStatusLine.Contains(TEXT("xr/openxr-desktop-training-runtime-owner"))
|
||||
&& Surface.XrStatusLine.Contains(TEXT("xr-openxr-motion-controllers/v1"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The control/input readiness surface must retain the fixed No-Go host decision and the later settings/rebinding follow-through."),
|
||||
|
|
@ -1187,6 +1201,8 @@ bool FHyperTwistTrainingPanelControlInputReadinessInspectSurfaceTest::RunTest(
|
|||
TestTrue(
|
||||
TEXT("The control/input readiness detail line must surface the fixed No-Go host decision operators actually need to see."),
|
||||
Surface.DetailLine.Contains(TEXT("No-Go"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr-openxr-training-preferences/v1"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr-openxr-motion-controllers/v1"))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1240,17 +1256,30 @@ bool FHyperTwistCoachDashboardControlInputReadinessInspectSurfaceTest::RunTest(
|
|||
TestTrue(
|
||||
TEXT("The coach dashboard control/input readiness surface must retain the unfinished XR/runtime truth in its detail line."),
|
||||
Surface.DetailLine.Contains(TEXT("not yet shipped"))
|
||||
&& Surface.DetailLine.Contains(TEXT("OpenXR project plugin no"))
|
||||
&& Surface.DetailLine.Contains(TEXT("OpenXR project plugin yes"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr/openxr-desktop-training-runtime-owner"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/input readiness surface must retain the bounded non-XR preferences continuity ids in its detail line."),
|
||||
Surface.DetailLine.Contains(TEXT("artifact/camera-export-json"))
|
||||
&& Surface.DetailLine.Contains(TEXT("immersive-training-session-recall-boundary"))
|
||||
);
|
||||
TestFalse(
|
||||
TEXT("The coach dashboard control/input readiness surface must preserve the explicit disabled OpenXR project plugin truth."),
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/input readiness surface must preserve the explicit enabled OpenXR project plugin truth."),
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/input readiness surface must expose the bounded XR runtime owner, preference profile, and controller binding profile."),
|
||||
Surface.bBoundedXrRuntimeOwnerReady
|
||||
&& Surface.bXrPreferenceProfileReady
|
||||
&& Surface.bXrControllerBindingProfileReady
|
||||
&& Surface.XrRuntimeOwnerId == TEXT("xr/openxr-desktop-training-runtime-owner")
|
||||
&& Surface.XrPreferenceProfileId == TEXT("xr-openxr-training-preferences/v1")
|
||||
&& Surface.XrControllerBindingProfileId == TEXT("xr-openxr-motion-controllers/v1")
|
||||
&& Surface.XrPreferenceFieldCount == 8
|
||||
&& Surface.XrControllerBindingAxisCount == 8
|
||||
&& Surface.XrSupportedControllerFamilyCount == 4
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The coach dashboard control/input readiness surface must preserve the structured XR host decision id."),
|
||||
Surface.XrHostDecisionId,
|
||||
|
|
@ -1267,6 +1296,7 @@ bool FHyperTwistCoachDashboardControlInputReadinessInspectSurfaceTest::RunTest(
|
|||
TEXT("The coach dashboard control/input readiness surface must keep the fixed No-Go host decision visible in its rendered detail line."),
|
||||
Surface.DetailLine.Contains(TEXT("No-Go"))
|
||||
&& Surface.DetailLine.Contains(TEXT("settings/rebinding"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr-openxr-motion-controllers/v1"))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1311,8 +1341,8 @@ bool FHyperTwistTrainingPanelControlSettingsOwnershipInspectSurfaceTest::RunTest
|
|||
TEXT("The control settings ownership surface must keep unfinished XR/controller rebinding truth explicit."),
|
||||
Surface.bFinishedControllerRebindingReady
|
||||
);
|
||||
TestFalse(
|
||||
TEXT("The control settings ownership surface must keep the current disabled OpenXR project plugin posture explicit."),
|
||||
TestTrue(
|
||||
TEXT("The control settings ownership surface must keep the current enabled OpenXR project plugin posture explicit."),
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
);
|
||||
TestEqual(
|
||||
|
|
@ -1352,6 +1382,17 @@ bool FHyperTwistTrainingPanelControlSettingsOwnershipInspectSurfaceTest::RunTest
|
|||
&& Surface.ImmersiveSessionRecallPreferenceFieldTagCount == 5
|
||||
&& Surface.ImmersiveSessionRecallResetSurfaceTagCount == 3
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The control settings ownership surface must expose the bounded XR preference and controller-profile ownership packet."),
|
||||
Surface.bXrPreferenceProfileReady
|
||||
&& Surface.bXrControllerBindingProfileReady
|
||||
&& Surface.XrRuntimeOwnerId == TEXT("xr/openxr-desktop-training-runtime-owner")
|
||||
&& Surface.XrPreferenceProfileId == TEXT("xr-openxr-training-preferences/v1")
|
||||
&& Surface.XrControllerBindingProfileId == TEXT("xr-openxr-motion-controllers/v1")
|
||||
&& Surface.XrPreferenceFieldCount == 8
|
||||
&& Surface.XrControllerBindingAxisCount == 8
|
||||
&& Surface.XrSupportedControllerFamilyCount == 4
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The control settings ownership surface must keep the default active higher-dimensional view context explicit when no live session is attached."),
|
||||
Surface.ActiveHigherDimensionalViewContextId,
|
||||
|
|
@ -1454,7 +1495,8 @@ bool FHyperTwistTrainingPanelControlSettingsOwnershipInspectSurfaceTest::RunTest
|
|||
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"))
|
||||
&& Surface.DetailLine.Contains(TEXT("project OpenXR plugin not enabled"))
|
||||
&& Surface.DetailLine.Contains(TEXT("project OpenXR plugin enabled"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr-openxr-training-preferences/v1"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The control settings ownership surface must keep the fixed desktop-hosted No-Go posture visible."),
|
||||
|
|
@ -1573,8 +1615,9 @@ bool FHyperTwistCoachDashboardControlSettingsOwnershipInspectSurfaceTest::RunTes
|
|||
&& Surface.DetailLine.Contains(TEXT("phase6c/magiccube5d/family-owned-scene-state"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control settings ownership surface must keep the rendered disabled OpenXR project plugin truth explicit."),
|
||||
Surface.DetailLine.Contains(TEXT("project OpenXR plugin not enabled"))
|
||||
TEXT("The coach dashboard control settings ownership surface must keep the rendered enabled OpenXR project plugin truth explicit."),
|
||||
Surface.DetailLine.Contains(TEXT("project OpenXR plugin enabled"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr-openxr-training-preferences/v1"))
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The coach dashboard control settings ownership surface must preserve the structured XR host decision id."),
|
||||
|
|
@ -1609,10 +1652,21 @@ bool FHyperTwistCoachDashboardControlSettingsOwnershipInspectSurfaceTest::RunTes
|
|||
Surface.MagicCube5DFocusSurfaceTagCount,
|
||||
5
|
||||
);
|
||||
TestFalse(
|
||||
TEXT("The coach dashboard control settings ownership surface must preserve the explicit disabled OpenXR project plugin posture."),
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control settings ownership surface must preserve the explicit enabled OpenXR project plugin posture."),
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control settings ownership surface must expose the bounded XR preference and controller binding packet."),
|
||||
Surface.bXrPreferenceProfileReady
|
||||
&& Surface.bXrControllerBindingProfileReady
|
||||
&& Surface.XrRuntimeOwnerId == TEXT("xr/openxr-desktop-training-runtime-owner")
|
||||
&& Surface.XrPreferenceProfileId == TEXT("xr-openxr-training-preferences/v1")
|
||||
&& Surface.XrControllerBindingProfileId == TEXT("xr-openxr-motion-controllers/v1")
|
||||
&& Surface.XrPreferenceFieldCount == 8
|
||||
&& Surface.XrControllerBindingAxisCount == 8
|
||||
&& Surface.XrSupportedControllerFamilyCount == 4
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control settings ownership surface must preserve the structured No-Go decision and reopen requirements."),
|
||||
Surface.bNativeOpenXrControllerWideningNoGo
|
||||
|
|
@ -1700,10 +1754,21 @@ bool FHyperTwistTrainingPanelControlProfileRosterInspectSurfaceTest::RunTest(
|
|||
TEXT("The control/profile roster surface must keep unfinished controller rebinding truth explicit."),
|
||||
Surface.bFinishedControllerRebindingReady
|
||||
);
|
||||
TestFalse(
|
||||
TEXT("The control/profile roster surface must keep the current disabled OpenXR project plugin posture explicit."),
|
||||
TestTrue(
|
||||
TEXT("The control/profile roster surface must keep the current enabled OpenXR project plugin posture explicit."),
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The control/profile roster surface must expose the bounded XR controller profile packet."),
|
||||
Surface.bXrPreferenceProfileReady
|
||||
&& Surface.bXrControllerBindingProfileReady
|
||||
&& Surface.XrRuntimeOwnerId == TEXT("xr/openxr-desktop-training-runtime-owner")
|
||||
&& Surface.XrPreferenceProfileId == TEXT("xr-openxr-training-preferences/v1")
|
||||
&& Surface.XrControllerBindingProfileId == TEXT("xr-openxr-motion-controllers/v1")
|
||||
&& Surface.XrPreferenceFieldCount == 8
|
||||
&& Surface.XrControllerBindingAxisCount == 8
|
||||
&& Surface.XrSupportedControllerFamilyCount == 4
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The control/profile roster surface must expose a stable structured XR host decision id."),
|
||||
Surface.XrHostDecisionId,
|
||||
|
|
@ -1719,7 +1784,8 @@ bool FHyperTwistTrainingPanelControlProfileRosterInspectSurfaceTest::RunTest(
|
|||
TestTrue(
|
||||
TEXT("The control/profile roster surface must say plainly that controller rebinding is not yet shipped."),
|
||||
Surface.DetailLine.Contains(TEXT("not yet shipped"))
|
||||
&& Surface.DetailLine.Contains(TEXT("project OpenXR plugin is not enabled"))
|
||||
&& Surface.DetailLine.Contains(TEXT("project OpenXR plugin is enabled"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr-openxr-motion-controllers/v1"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The control/profile roster surface must keep the fixed No-Go host decision visible alongside the unfinished controller rebinding truth."),
|
||||
|
|
@ -1822,10 +1888,21 @@ bool FHyperTwistCoachDashboardControlProfileRosterInspectSurfaceTest::RunTest(
|
|||
Surface.XrHostDecisionId,
|
||||
TEXT("desktop-hosted-openxr-controller-widening-no-go")
|
||||
);
|
||||
TestFalse(
|
||||
TEXT("The coach dashboard control/profile roster surface must preserve the explicit disabled OpenXR project plugin posture."),
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/profile roster surface must preserve the explicit enabled OpenXR project plugin posture."),
|
||||
Surface.bOpenXrProjectPluginEnabled
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/profile roster surface must expose the bounded XR controller profile packet."),
|
||||
Surface.bXrPreferenceProfileReady
|
||||
&& Surface.bXrControllerBindingProfileReady
|
||||
&& Surface.XrRuntimeOwnerId == TEXT("xr/openxr-desktop-training-runtime-owner")
|
||||
&& Surface.XrPreferenceProfileId == TEXT("xr-openxr-training-preferences/v1")
|
||||
&& Surface.XrControllerBindingProfileId == TEXT("xr-openxr-motion-controllers/v1")
|
||||
&& Surface.XrPreferenceFieldCount == 8
|
||||
&& Surface.XrControllerBindingAxisCount == 8
|
||||
&& Surface.XrSupportedControllerFamilyCount == 4
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/profile roster surface must preserve the structured No-Go decision and reopen requirements."),
|
||||
Surface.bNativeOpenXrControllerWideningNoGo
|
||||
|
|
@ -1834,8 +1911,9 @@ bool FHyperTwistCoachDashboardControlProfileRosterInspectSurfaceTest::RunTest(
|
|||
&& Surface.bRequiresWindowsPackagedControllerValidationForReopen
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/profile roster surface must keep the rendered disabled OpenXR project plugin truth explicit."),
|
||||
Surface.DetailLine.Contains(TEXT("project OpenXR plugin is not enabled"))
|
||||
TEXT("The coach dashboard control/profile roster surface must keep the rendered enabled OpenXR project plugin truth explicit."),
|
||||
Surface.DetailLine.Contains(TEXT("project OpenXR plugin is enabled"))
|
||||
&& Surface.DetailLine.Contains(TEXT("xr-openxr-motion-controllers/v1"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The coach dashboard control/profile roster surface must keep the fixed No-Go host decision visible in its rendered detail line."),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
// Copyright HyperTwist, Inc. All Rights Reserved.
|
||||
|
||||
#include "Misc/AutomationTest.h"
|
||||
|
||||
#include "HyperTwistXR/HyperTwistXrRuntimeLibrary.h"
|
||||
#include "HyperTwistXR/HyperTwistXrTrainingPawn.h"
|
||||
|
||||
#if WITH_AUTOMATION_TESTS
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistXrRuntimeOwnershipSurfaceTest,
|
||||
"HyperTwist.FirstParty.XR.RuntimeOwnershipSurface",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistXrRuntimeOwnershipSurfaceTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistXrRuntimeOwnershipSurface Surface =
|
||||
UHyperTwistXrRuntimeLibrary::BuildBundledXrRuntimeOwnershipSurface();
|
||||
TestTrue(
|
||||
TEXT("The bounded XR runtime ownership surface must be structurally valid."),
|
||||
Surface.IsStructurallyValid()
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The bounded XR runtime ownership id must stay stable."),
|
||||
Surface.RuntimeOwnerId,
|
||||
FString(TEXT("xr/openxr-desktop-training-runtime-owner"))
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The bounded XR runtime ownership surface must keep the left motion source stable."),
|
||||
Surface.LeftMotionSourceId,
|
||||
FString(TEXT("Left"))
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The bounded XR runtime ownership surface must keep the right motion source stable."),
|
||||
Surface.RightMotionSourceId,
|
||||
FString(TEXT("Right"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The bounded XR runtime ownership surface must preserve the first-party interaction tags."),
|
||||
Surface.RequiredSurfaceTags.Contains(TEXT("motion-controller pose anchors"))
|
||||
&& Surface.RequiredSurfaceTags.Contains(TEXT("camera-aligned locomotion vector"))
|
||||
&& Surface.RequiredSurfaceTags.Contains(TEXT("training-world recenter"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The bounded XR runtime ownership surface must preserve the staged exclusions."),
|
||||
Surface.ExplicitExclusions.Contains(TEXT("platform-global guardian ownership"))
|
||||
&& Surface.ExplicitExclusions.Contains(TEXT("launch-tier packaged controller certification ownership"))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistXrPreferenceAndBindingProfileTest,
|
||||
"HyperTwist.FirstParty.XR.PreferenceAndBindingProfiles",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistXrPreferenceAndBindingProfileTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const FHyperTwistXrPreferenceProfile PreferenceProfile =
|
||||
UHyperTwistXrRuntimeLibrary::GetDefaultXrPreferenceProfile();
|
||||
TestTrue(
|
||||
TEXT("The XR preference profile must be structurally valid."),
|
||||
PreferenceProfile.IsStructurallyValid()
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The XR preference profile id must stay stable."),
|
||||
PreferenceProfile.ProfileId,
|
||||
FString(TEXT("xr-openxr-training-preferences/v1"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The XR preference profile must preserve the owned preference-field roster."),
|
||||
PreferenceProfile.PreferenceFieldTags.Contains(TEXT("movement speed"))
|
||||
&& PreferenceProfile.PreferenceFieldTags.Contains(TEXT("snap turn"))
|
||||
&& PreferenceProfile.PreferenceFieldTags.Contains(TEXT("world scale"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The XR preference profile must preserve comfort-surface tags."),
|
||||
PreferenceProfile.ComfortSurfaceTags.Contains(TEXT("comfort vignette strength"))
|
||||
&& PreferenceProfile.ComfortSurfaceTags.Contains(TEXT("seated height offset"))
|
||||
);
|
||||
|
||||
const FHyperTwistXrControllerBindingProfile BindingProfile =
|
||||
UHyperTwistXrRuntimeLibrary::GetDefaultXrControllerBindingProfile();
|
||||
TestTrue(
|
||||
TEXT("The XR controller binding profile must be structurally valid."),
|
||||
BindingProfile.IsStructurallyValid()
|
||||
);
|
||||
TestEqual(
|
||||
TEXT("The XR controller binding profile id must stay stable."),
|
||||
BindingProfile.ProfileId,
|
||||
FString(TEXT("xr-openxr-motion-controllers/v1"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The XR controller binding profile must preserve the owned axis roster."),
|
||||
BindingProfile.RequiredAxisNames.Contains(TEXT("HyperTwistXr_MoveForward"))
|
||||
&& BindingProfile.RequiredAxisNames.Contains(TEXT("HyperTwistXr_Turn"))
|
||||
&& BindingProfile.RequiredAxisNames.Contains(TEXT("HyperTwistXr_RightTrigger"))
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The XR controller binding profile must preserve the supported controller families."),
|
||||
BindingProfile.ControllerFamilyIds.Contains(TEXT("controller/oculus-touch"))
|
||||
&& BindingProfile.ControllerFamilyIds.Contains(TEXT("controller/valve-index"))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||
FHyperTwistXrTrainingPawnDefaultsTest,
|
||||
"HyperTwist.FirstParty.XR.TrainingPawnDefaults",
|
||||
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
|
||||
)
|
||||
|
||||
bool FHyperTwistXrTrainingPawnDefaultsTest::RunTest(const FString& Parameters)
|
||||
{
|
||||
const AHyperTwistXrTrainingPawn* PawnDefaults = GetDefault<AHyperTwistXrTrainingPawn>();
|
||||
TestNotNull(TEXT("The XR training pawn defaults must exist."), PawnDefaults);
|
||||
if (PawnDefaults == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TestNotNull(
|
||||
TEXT("The XR training pawn must allocate a scene root."),
|
||||
PawnDefaults->SceneRoot.Get()
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The XR training pawn must allocate a VR origin."),
|
||||
PawnDefaults->VROrigin.Get()
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The XR training pawn must allocate a camera."),
|
||||
PawnDefaults->CameraComponent.Get()
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The XR training pawn must allocate a left controller."),
|
||||
PawnDefaults->LeftController.Get()
|
||||
);
|
||||
TestNotNull(
|
||||
TEXT("The XR training pawn must allocate a right controller."),
|
||||
PawnDefaults->RightController.Get()
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The XR training pawn must start with a valid owned preference profile and binding profile."),
|
||||
PawnDefaults->ActivePreferenceProfile.IsStructurallyValid()
|
||||
&& PawnDefaults->ActiveControllerBindingProfile.IsStructurallyValid()
|
||||
);
|
||||
TestTrue(
|
||||
TEXT("The XR training pawn must preserve the bounded runtime ownership line."),
|
||||
PawnDefaults->BuildRuntimeStatusLine().Contains(TEXT("xr/openxr-desktop-training-runtime-owner"))
|
||||
&& PawnDefaults->BuildRuntimeStatusLine().Contains(TEXT("xr-openxr-training-preferences/v1"))
|
||||
&& PawnDefaults->BuildRuntimeStatusLine().Contains(TEXT("xr-openxr-motion-controllers/v1"))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -9,7 +9,7 @@ public class UnrealHyperTwist : ModuleRules
|
|||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "Json", "JsonUtilities", "UMG", "Voice", "ProceduralMeshComponent" });
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "Json", "JsonUtilities", "UMG", "Voice", "ProceduralMeshComponent", "HeadMountedDisplay", "XRBase" });
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[] { "Slate", "SlateCore", "HTTP", "WebBrowser", "WebBrowserWidget", "Projects" }
|
||||
|
|
|
|||
|
|
@ -58,6 +58,14 @@
|
|||
"Name": "WebBrowserWidget",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "XRBase",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "OpenXR",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "MovieRenderPipeline",
|
||||
"Enabled": true,
|
||||
|
|
|
|||
|
|
@ -9,38 +9,56 @@ leaving “maybe XR is already basically there” ambiguity in the Unreal lane.
|
|||
|
||||
## Current decision
|
||||
|
||||
Current decision: `No-Go` on native OpenXR/controller runtime widening in the
|
||||
shipping HyperTwist lane.
|
||||
Current decision: `No-Go` on broader native OpenXR/controller runtime widening
|
||||
beyond the newly landed bounded desktop-training owner seam in the shipping
|
||||
HyperTwist lane.
|
||||
|
||||
Current authoritative host posture:
|
||||
|
||||
- the shipping immersive lane remains a desktop-hosted Unreal training runtime
|
||||
with scenic presence, comfort, posture, and session-local settings ownership
|
||||
- the project does **not** currently enable an `OpenXR` plugin stack in
|
||||
`UnrealHyperTwist.uproject`
|
||||
- the project does **not** currently prove a first-party headset/controller
|
||||
runtime owner such as a dedicated VR pawn plus
|
||||
`MotionControllerComponent`-driven interaction surface
|
||||
- the newly landed native control/input and control/settings inspect surfaces
|
||||
must be treated as truthful bounded ownership around the desktop simulator,
|
||||
not as proof of a finished XR runtime
|
||||
- the project now **does** enable a deliberately bounded `OpenXR` + `XRBase`
|
||||
plugin stack in `UnrealHyperTwist.uproject`
|
||||
- the project now **does** prove a first-party bounded runtime owner through a
|
||||
dedicated XR training pawn plus `MotionControllerComponent`-driven anchors,
|
||||
controller-binding ownership, and preference-profile ownership
|
||||
- that bounded runtime-owner substrate must still be treated as truthful
|
||||
desktop-simulator ownership, not as proof of a finished launch-tier
|
||||
XR/controller product
|
||||
- polished user-facing rebinding/settings ownership and packaged
|
||||
headset/controller proof remain unfinished and continue to hold the wider
|
||||
lane closed
|
||||
|
||||
## Evidence checked
|
||||
|
||||
### Project plugin posture
|
||||
|
||||
- `UnrealHyperTwist/UnrealHyperTwist.uproject` currently enables:
|
||||
- `OpenXR`
|
||||
- `XRBase`
|
||||
- `RemoteControl`
|
||||
- `ProceduralMeshComponent`
|
||||
- `WebBrowserWidget`
|
||||
- editor-only tooling such as `MovieRenderPipeline`,
|
||||
`PythonScriptPlugin`, and `ModelingToolsEditorMode`
|
||||
- that file does **not** currently declare an enabled `OpenXR` plugin
|
||||
|
||||
### Runtime ownership posture
|
||||
|
||||
- `UnrealHyperTwist/Config/DefaultInput.ini` still proves real
|
||||
`EnhancedInput` and broad motion-controller axis groundwork
|
||||
- `UnrealHyperTwist/Config/DefaultInput.ini` now proves real bounded
|
||||
controller-axis and action ownership across the current controller-family
|
||||
roster instead of only broad motion-controller groundwork
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistXR/HyperTwistXrRuntimeLibrary.h`
|
||||
and `.../Private/HyperTwistXR/HyperTwistXrRuntimeLibrary.cpp` now define the
|
||||
first-party bounded runtime-owner, preference-profile, and controller-binding
|
||||
contracts:
|
||||
- `xr/openxr-desktop-training-runtime-owner`
|
||||
- `xr-openxr-training-preferences/v1`
|
||||
- `xr-openxr-motion-controllers/v1`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistXR/HyperTwistXrTrainingPawn.h`
|
||||
and `.../Private/HyperTwistXR/HyperTwistXrTrainingPawn.cpp` now provide a
|
||||
bounded first-party XR training pawn with camera, controller anchors,
|
||||
posture switching, desktop fallback pitch handling, recentering, and status
|
||||
reporting
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingImmersiveEnvironmentLibrary.cpp`
|
||||
keeps the immersive lane explicitly bounded to scenic training ownership
|
||||
- the same immersive library explicitly excludes:
|
||||
|
|
@ -80,6 +98,18 @@ Current authoritative host posture:
|
|||
99.38 seconds`, and exported
|
||||
`Saved\AutomationReports\Browser-XrPluginProjectPosture-Verify\index.json`
|
||||
with all `20` `HyperTwist.Browser.*` tests green
|
||||
- a later same-family bounded-runtime-owner follow-up on `2026-07-01` then
|
||||
carried the real first-party runtime-owner packet into those same native
|
||||
inspect surfaces as stable structured ids plus counts, rebuilt the exact
|
||||
source state on maintained validation root
|
||||
`C:\HyperTwist_worktrees\phase10validate` with:
|
||||
- `Result: Succeeded`
|
||||
- UnrealBuildTool `Total execution time: 124.26 seconds`
|
||||
then exported:
|
||||
- `Saved\AutomationReports\XR-BoundedRuntimeOwner-20260701-Final\index.json`
|
||||
with `3` focused XR tests succeeded
|
||||
- `Saved\AutomationReports\Browser-XrBoundedRuntime-20260701-Final\index.json`
|
||||
with all `26` `HyperTwist.Browser.*` tests succeeded
|
||||
|
||||
## Interpretation
|
||||
|
||||
|
|
@ -89,37 +119,39 @@ HyperTwist already owns:
|
|||
- scenic immersive training presentation
|
||||
- session-local presence and comfort posture
|
||||
- current camera and dedicated-family view settings ownership
|
||||
- a bounded OpenXR runtime-owner substrate for desktop training, including
|
||||
first-party runtime owner, controller bindings, preference ownership, and XR
|
||||
training pawn scaffolding
|
||||
|
||||
HyperTwist does **not** yet own:
|
||||
|
||||
- headset-runtime plugin posture
|
||||
- controller interaction runtime ownership
|
||||
- polished controller rebinding/preferences ownership
|
||||
- packaged XR/controller proof
|
||||
- packaged headset/controller proof
|
||||
- broader launch-tier cross-device XR completion
|
||||
|
||||
Therefore the current truthful host decision is:
|
||||
|
||||
- keep the immersive lane desktop-hosted
|
||||
- keep `OpenXR` disabled by default in the shipping branch
|
||||
- do not market VR/controller support as finished
|
||||
- do not let browser-side retained XR grounding imply native XR completion
|
||||
- keep the broader controller-widening branch closed until the remaining
|
||||
settings/rebinding and packaged-proof requirements are actually met
|
||||
|
||||
## Reopen criteria
|
||||
|
||||
Future native XR widening may reopen only when all of the following are true:
|
||||
|
||||
1. the exact plugin stack is chosen explicitly and checked in
|
||||
2. first-party runtime owners for headset/controller interaction are present
|
||||
3. controller bindings and rebinding/preferences ownership are first-party and
|
||||
user-visible
|
||||
4. Windows build plus focused automation plus packaged validation prove that
|
||||
lane
|
||||
5. public/product copy is updated only after those proofs exist
|
||||
1. polished controller bindings plus rebinding/preferences ownership are
|
||||
first-party and user-visible
|
||||
2. Windows build plus focused automation plus packaged validation prove actual
|
||||
headset/controller behavior on the shipping lane
|
||||
3. public/product copy is updated only after those proofs exist
|
||||
|
||||
## Immediate consequence
|
||||
|
||||
No native XR implementation packet is currently open by default.
|
||||
|
||||
If the project later reopens this lane, the first implementation packet should
|
||||
be a bounded native plugin/runtime-owner slice, not public marketing widening
|
||||
and not speculative controller polish in the absence of a chosen runtime host.
|
||||
be finished user-facing controller settings/rebinding ownership plus packaged
|
||||
controller proof above the now-landed bounded runtime-owner substrate, not
|
||||
public marketing widening.
|
||||
|
|
|
|||
|
|
@ -324,22 +324,70 @@ truthfully claim:
|
|||
- `TrainingPanel.ControlProfileRosterInspectSurface`
|
||||
- `TrainingPanel.ControlSettingsOwnershipInspectSurface`
|
||||
|
||||
### Finished XR runtime ownership is not yet proven
|
||||
### Bounded OpenXR runtime ownership now exists on the desktop-hosted lane
|
||||
|
||||
- `UnrealHyperTwist/UnrealHyperTwist.uproject` currently enables
|
||||
`WebBrowserWidget`, `ProceduralMeshComponent`, `RemoteControl`, and editor
|
||||
tooling plugins, but this audit did not find an enabled `OpenXR` plugin
|
||||
declaration or a headset-specific runtime plugin stack in the project file
|
||||
- a focused source search did not surface first-party runtime classes such as a
|
||||
dedicated VR pawn or `MotionControllerComponent`-driven interaction owner
|
||||
that would justify stronger shipping claims
|
||||
- a later same-family `2026-07-01` bounded-runtime-owner follow-up then moved
|
||||
the native XR lane from “plugin posture and grounded boundary only” into a
|
||||
real first-party bounded runtime-owner substrate without reopening the
|
||||
broader desktop-hosted `No-Go` posture:
|
||||
- `UnrealHyperTwist/UnrealHyperTwist.uproject` now enables both `OpenXR`
|
||||
and `XRBase`
|
||||
- `UnrealHyperTwist/UnrealHyperTwist.Build.cs` now carries the matching
|
||||
runtime module dependencies
|
||||
- `UnrealHyperTwist/Config/DefaultInput.ini` now owns explicit OpenXR-ready
|
||||
controller axes and actions across the currently bounded controller-family
|
||||
roster
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistXR/HyperTwistXrRuntimeLibrary.h`
|
||||
and `.../Private/HyperTwistXR/HyperTwistXrRuntimeLibrary.cpp` now define
|
||||
the first-party runtime-owner, preference-profile, and controller-binding
|
||||
contracts:
|
||||
- `xr/openxr-desktop-training-runtime-owner`
|
||||
- `xr-openxr-training-preferences/v1`
|
||||
- `xr-openxr-motion-controllers/v1`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistXR/HyperTwistXrTrainingPawn.h`
|
||||
and `.../Private/HyperTwistXR/HyperTwistXrTrainingPawn.cpp` now provide a
|
||||
bounded first-party training pawn with `CameraComponent`,
|
||||
`MotionControllerComponent` anchors, desktop fallback pitch handling,
|
||||
posture switching, recentering, and owned runtime status reporting
|
||||
- the native control/input, control/settings, and control/profile inspect
|
||||
surfaces now also expose that bounded runtime-owner packet in structured
|
||||
fields and rendered operator lines, including the stable ids, preference
|
||||
field count `8`, required binding-axis count `8`, and supported controller
|
||||
family count `4`
|
||||
- the maintained reverse-SSH Windows lane then revalidated that exact-source
|
||||
state on `C:\HyperTwist_worktrees\phase10validate`:
|
||||
- final exact-source editor build:
|
||||
- `Result: Succeeded`
|
||||
- UnrealBuildTool `Total execution time: 124.26 seconds`
|
||||
- focused XR automation export:
|
||||
- `Saved\AutomationReports\XR-BoundedRuntimeOwner-20260701-Final\index.json`
|
||||
- `3` tests performed
|
||||
- `3` succeeded
|
||||
- full browser automation export:
|
||||
- `Saved\AutomationReports\Browser-XrBoundedRuntime-20260701-Final\index.json`
|
||||
- `26` `HyperTwist.Browser.*` tests succeeded
|
||||
- that same follow-up matters for this audit because native Unreal now owns a
|
||||
real bounded OpenXR runtime-owner seam instead of only negative boundary
|
||||
wording, while still keeping the broader widening doctrine honest
|
||||
|
||||
### Finished launch-tier XR/controller ownership is still not proven
|
||||
|
||||
- the earlier `2026-06-22` finding that the shipping branch did not yet enable
|
||||
`OpenXR` is now historically superseded by the bounded-runtime-owner packet
|
||||
above; current source truth is that the desktop-hosted branch now carries a
|
||||
deliberately bounded `OpenXR` + `XRBase` stack plus first-party runtime-owner
|
||||
classes
|
||||
- that later exact-source state still does **not** yet prove:
|
||||
- packaged headset/controller behavior on the Windows lane
|
||||
- polished user-facing controller rebinding/settings ownership
|
||||
- broader launch-tier cross-device XR completion
|
||||
- `HyperTwistTrainingImmersiveEnvironmentLibrary.cpp` clearly establishes a
|
||||
first-party immersive/scenic environment direction, but it also explicitly
|
||||
keeps scope bounded away from platform-global XR settings or generic VR shell
|
||||
ownership
|
||||
- the current explicit decision packet on `2026-06-24` therefore fixes the
|
||||
host/plugin posture to desktop-hosted scenic immersive training with a
|
||||
current `No-Go` on native OpenXR/controller runtime widening
|
||||
- the current explicit decision packet therefore still fixes the broader
|
||||
desktop-hosted `No-Go` on native OpenXR/controller widening beyond the newly
|
||||
landed bounded runtime-owner seam
|
||||
|
||||
## Product-language consequence
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,37 @@ This note records the concrete cutover path for replacing the current
|
|||
placeholder `hypertwist.app` page with the first-party HyperTwist website plus
|
||||
auth-server lane already shipped in the repo.
|
||||
|
||||
## Latest live-origin truth on `2026-07-01`
|
||||
|
||||
The historical placeholder-era cutover notes below remain useful as deployment
|
||||
history, but they are no longer the current live reading.
|
||||
|
||||
Current direct live checks now show:
|
||||
|
||||
- `https://hypertwist.app/` returns the first-party site shell, including meta
|
||||
marker `hypertwist-site-shell=first-party-website-v1`
|
||||
- `https://hypertwist.app/api/auth/health` returns JSON with:
|
||||
- `ok: true`
|
||||
- `service: hypertwist-auth-server`
|
||||
- `runtime.public_origin_ready: true`
|
||||
- `launch.posture: preview`
|
||||
- `https://hypertwist.app/api/releases/manifest` returns the first-party
|
||||
release manifest JSON and currently keeps the Windows lane at preview
|
||||
posture with packaged-validation summary attached but no public download URL
|
||||
|
||||
Current truthful interpretation:
|
||||
|
||||
- the placeholder rollout page is gone
|
||||
- the first-party same-origin website/auth-server deployment is live
|
||||
- the live public origin is still a preview deployment rather than full public
|
||||
launch because the current auth/launch JSON still reports missing Windows
|
||||
download, checkout, billing-map, and webhook-secret launch requirements
|
||||
- a plain repo push is not itself a production deploy; live website changes are
|
||||
only published after
|
||||
`npm run run:vps-same-origin-live-deploy -- --manifest <file> --identity-file <key>`
|
||||
or an equivalent CI job that invokes the same helper and revalidates the
|
||||
public origin
|
||||
|
||||
This is the next operator step after:
|
||||
|
||||
- the public website implementation packet
|
||||
|
|
@ -323,16 +354,11 @@ curl --silent --show-error https://hypertwist.app/api/releases/manifest
|
|||
curl --silent --show-error https://hypertwist.app/ | rg "hypertwist-site-shell|id=\"root\""
|
||||
```
|
||||
|
||||
As of the latest repo-side proof on `2026-06-22`, those live checks still
|
||||
returned the placeholder rollout page, so the rendered bundle is ready but the
|
||||
public-host cutover has not yet been applied.
|
||||
|
||||
That remaining cutover gap is now narrower than before: an isolated VPS-local
|
||||
staging proof on the same host succeeded on `3011` for `/health`,
|
||||
`/api/auth/health`, `/api/releases/manifest`, and the first-party shell marker,
|
||||
and the new first-party staging-proof helper now reproduces that flow
|
||||
programmatically, so the remaining work is root-owned enablement and vhost
|
||||
replacement rather than unresolved repo-side runtime behavior.
|
||||
That `2026-06-22` placeholder-era gap is now historically closed: the live
|
||||
origin currently serves the first-party shell and JSON health/manifest routes.
|
||||
The remaining gap is no longer host cutover; it is launch-tier value
|
||||
completion and keeping future site changes paired with the real live-deploy
|
||||
helper instead of assuming a repo push alone is production publication.
|
||||
|
||||
### 7. Run the first-party readiness verifier
|
||||
|
||||
|
|
|
|||
|
|
@ -1116,6 +1116,56 @@ Current audit note:
|
|||
- `scripts/run-hypertwist-gitnexus-status.sh`
|
||||
- bounded mirror `Status: up-to-date`
|
||||
|
||||
## Latest bounded OpenXR runtime-owner follow-up (`2026-07-01`)
|
||||
|
||||
- the next same-family native continuation then finally moved the XR lane from
|
||||
“explicit plugin posture and fixed `No-Go` wording” into a real first-party
|
||||
bounded runtime-owner substrate without pretending the wider branch had
|
||||
reopened:
|
||||
- `UnrealHyperTwist.uproject` now enables `OpenXR` plus `XRBase`
|
||||
- `UnrealHyperTwist.Build.cs` now carries the matching runtime module
|
||||
dependencies
|
||||
- `DefaultInput.ini` now owns explicit OpenXR-ready controller axes/actions
|
||||
across the bounded controller-family roster
|
||||
- new first-party runtime-owner/profile code now lives under
|
||||
`Source/UnrealHyperTwist/Public/HyperTwistXR/` and
|
||||
`.../Private/HyperTwistXR/`
|
||||
- the landed stable ids are:
|
||||
- `xr/openxr-desktop-training-runtime-owner`
|
||||
- `xr-openxr-training-preferences/v1`
|
||||
- `xr-openxr-motion-controllers/v1`
|
||||
- the native control/input, control/settings, and control/profile inspect
|
||||
surfaces now all carry those ids plus stable counts in structured state and
|
||||
rendered lines
|
||||
- one adjacent quality follow-up in the same packet then tightened the bounded
|
||||
pawn itself:
|
||||
- desktop recenter now clears fallback pitch instead of leaving a carried
|
||||
non-HMD look angle behind
|
||||
- the runtime status line now keeps the owned runtime, preference, and
|
||||
controller-profile ids visible together
|
||||
- the fallback-rotation path now lives in one helper instead of duplicating
|
||||
inline rotation writes
|
||||
- the maintained reverse-SSH Windows lane then revalidated the exact-source
|
||||
state on `C:\HyperTwist_worktrees\phase10validate`:
|
||||
- final editor build:
|
||||
- `Result: Succeeded`
|
||||
- UnrealBuildTool `Total execution time: 124.26 seconds`
|
||||
- focused XR automation:
|
||||
- `Saved\AutomationReports\XR-BoundedRuntimeOwner-20260701-Final\index.json`
|
||||
- `3` tests succeeded
|
||||
- full browser automation:
|
||||
- `Saved\AutomationReports\Browser-XrBoundedRuntime-20260701-Final\index.json`
|
||||
- all `26` `HyperTwist.Browser.*` tests succeeded
|
||||
- current truthful reading after this continuation:
|
||||
- HyperTwist now owns a real bounded desktop-training OpenXR runtime-owner
|
||||
seam
|
||||
- the broader desktop-hosted XR/controller widening branch still remains
|
||||
closed until polished rebinding/settings ownership and packaged
|
||||
headset/controller proof exist
|
||||
- this is the right intermediate state to document publicly because it is
|
||||
stronger than the older negative-only wording and still honest about the
|
||||
remaining gap
|
||||
|
||||
## Latest public/manual follow-up (`2026-06-25`)
|
||||
|
||||
- the public website now carries one shared release-reference bundle across the
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -156,6 +156,29 @@ scene ownership into the native control-profile roster seam, so the selectable
|
|||
roster truth now stays aligned with the sibling control-settings and active
|
||||
runtime surfaces instead of leaving those facts implied.
|
||||
|
||||
The next same-family `2026-07-01` follow-up then moved the XR side of that
|
||||
statement forward too without overclaiming launch-tier completion:
|
||||
|
||||
- the desktop-hosted branch now enables `OpenXR` plus `XRBase`
|
||||
- first-party bounded runtime-owner/profile ownership now exists through:
|
||||
- `xr/openxr-desktop-training-runtime-owner`
|
||||
- `xr-openxr-training-preferences/v1`
|
||||
- `xr-openxr-motion-controllers/v1`
|
||||
- a dedicated `AHyperTwistXrTrainingPawn` now owns bounded camera/controller
|
||||
anchors, posture switching, recentering, and desktop fallback pitch handling
|
||||
- the maintained Windows validation lane then re-proved the exact-source state
|
||||
with:
|
||||
- editor build `Result: Succeeded`, UnrealBuildTool `Total execution time:
|
||||
124.26 seconds`
|
||||
- focused XR automation `XR-BoundedRuntimeOwner-20260701-Final`: `3/3`
|
||||
green
|
||||
- full browser automation `Browser-XrBoundedRuntime-20260701-Final`:
|
||||
`26/26` `HyperTwist.Browser.*` green
|
||||
|
||||
That is real bounded runtime ownership, but it is still not the same thing as
|
||||
finished launch-tier controller rebinding, packaged headset proof, or generic
|
||||
marketed VR completion.
|
||||
|
||||
Canonical audit note:
|
||||
|
||||
- `C:\HyperTwist\docs\ops\HYPERTWIST_UNREAL_INPUT_AND_XR_COMPLETENESS_AUDIT_2026-06-22.md`
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ Before using these templates:
|
|||
to stage the committed checkout, upload the rendered bundle, install env,
|
||||
build the site, replace the live `systemd` plus `nginx` files, and validate
|
||||
the public origin through the same readiness lane
|
||||
- a plain git push does **not** publish `https://hypertwist.app` by itself;
|
||||
production changes are only live after this helper, or a CI job that invokes
|
||||
the same helper, has completed and the public origin has been revalidated
|
||||
- set `publicOrigin` to the exact live origin that should own both the website
|
||||
and auth cookies; for the canonical production lane that value is
|
||||
`https://hypertwist.app`
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue