diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 93d693e418fdde59a75556ec96d65e03313e3293..e63ad67079c433a824a63e292b308b483ed38c0d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,6 +3,30 @@ # Virtual Reality & Immersive Visualisation Group. #------------------------------------------------------------------------------- +spec: + inputs: + unreal_version: + description: The Unreal Engine version in the form of "major.minor" + type: string + regex: \d+\.\d+ + default: "5.4" + build_type: + description: The game build type. + type: string + options: ["DebugGame", "Shipping"] + default: "DebugGame" + number_of_old_versions: + description: How many successful pipeline builds of this branch should be stored on the cluster. + type: number + default: 3 + custom_ndisplay_config: + description: Custom nDisplay config stored on the cluster filesystem. + type: string + default: "" + +--- + + # The include file can be change to either be removed or reference a specific commit. include: @@ -41,8 +65,9 @@ include: # Use the CUSTOM_NDISPLAY_CONFIG variable in case you need a custom ndisplay config. These are always located in /home/vrdemo/configs/ndisplay. variables: - UNREAL_VERSION: "5.4" - CUSTOM_NDISPLAY_CONFIG: "aixcave_5_4.ndisplay" + UNREAL_VERSION: $[[ inputs.unreal_version ]] + NUMBER_OF_OLD_VERSIONS: $[[ inputs.number_of_old_versions ]] + CUSTOM_NDISPLAY_CONFIG: $[[ inputs.custom_ndisplay_config ]] stages: - analyze @@ -113,7 +138,7 @@ Build_Windows: GIT_STRATEGY: none GIT_CHECKOUT: "false" # CLIENT_CONFIG: "Shipping" - CLIENT_CONFIG: "DebugGame" + CLIENT_CONFIG: $[[ inputs.build_type ]] needs: - job: "Generate_Project" artifacts: true @@ -134,7 +159,7 @@ Build_Linux: GIT_STRATEGY: none GIT_CHECKOUT: "false" # CLIENT_CONFIG: "Shipping" - CLIENT_CONFIG: "DebugGame" + CLIENT_CONFIG: $[[ inputs.build_type ]] needs: - job: "Generate_Project" artifacts: true @@ -146,16 +171,7 @@ Build_Linux_Without_Cluster: needs: - job: "Generate_Project_Without_Cluster" artifacts: true - -# Deploys to vrdev -.Deploy_Windows: - rules: - - if: $CI_PIPELINE_SOURCE == "web" - - if: $CI_PIPELINE_SOURCE == "schedule" - extends: .Deploy_VRDev_ - needs: - - job: "Build_Windows" - artifacts: true + # Deploys to vrdemo instead of av006de. Use extends: .Deploy_CAVE_ to deploy to legacy av006de Deploy_CAVE: diff --git a/Content/Pawn/BP_RWTHVRPawn_Default.uasset b/Content/Pawn/BP_RWTHVRPawn_Default.uasset index 145ddf5f938d0a3612c7a609aafa75a30d82063f..98bd1d8298820e85ce83fa1eaf0cee4f8d04c159 100644 Binary files a/Content/Pawn/BP_RWTHVRPawn_Default.uasset and b/Content/Pawn/BP_RWTHVRPawn_Default.uasset differ diff --git a/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset b/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset index cba6c2e1875f45603f51e234dbb9b066017654f9..435be5fe5966d3796891186bfc38247df833f47b 100644 Binary files a/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset and b/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset differ diff --git a/Source/RWTHVRToolkit/Private/Core/ClientTransformReplication.cpp b/Source/RWTHVRToolkit/Private/Core/ClientTransformReplication.cpp index 0bce9302ae30860f0211918a620be91e9666ea21..011c83377dbcf497f2df887a00c4ec6250838275 100644 --- a/Source/RWTHVRToolkit/Private/Core/ClientTransformReplication.cpp +++ b/Source/RWTHVRToolkit/Private/Core/ClientTransformReplication.cpp @@ -26,8 +26,8 @@ void UClientTransformReplication::UpdateState(float DeltaTime) // Only do this if we actually replicate the actor if (GetIsReplicated()) { - const FVector Loc = OwningActor->GetActorLocation(); - const FRotator Rot = OwningActor->GetActorRotation(); + const FVector Loc = OwningActor->GetRootComponent()->GetRelativeLocation(); + const FRotator Rot = OwningActor->GetRootComponent()->GetRelativeRotation(); // Only update state if the local state changed if (!Loc.Equals(ReplicatedTransform.Position) || !Rot.Equals(ReplicatedTransform.Rotation)) diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp index 18e515817875cb60c35090b4dbfb4300051b8dac..fac35ab8270c772dcd94b2b67d1808eb4f8b5bd5 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/DirectInteractionComponent.cpp @@ -70,6 +70,13 @@ void UDirectInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tick // Call hover end events on all components that were previously in range, but not anymore for (UInteractableComponent* PrevInteractableComp : PreviousInteractableComponentsInRange) { + // It can happen that a previous component was destroyed + if (!PrevInteractableComp || !PrevInteractableComp->IsValidLowLevel()) + { + ComponentsToRemove.Add(PrevInteractableComp); // might have to use indices here + continue; + } + if (!CurrentInteractableCompsInRange.Contains(PrevInteractableComp)) { ComponentsToRemove.AddUnique(PrevInteractableComp); diff --git a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp index dc9c9022a86fc6e57b1dd6e19927519bca283161..a0b82558ca19ade0331653e513f27486249dd4f4 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp @@ -18,6 +18,10 @@ #include "Utility/RWTHVRUtilities.h" #if PLATFORM_SUPPORTS_CLUSTER +#include "DisplayClusterRootActor.h" +#include "ScalableConfigInterface.h" +#include "IDisplayCluster.h" +#include "Game/IDisplayClusterGameManager.h" #include "Components/DisplayClusterSceneComponentSyncParent.h" #endif @@ -56,11 +60,7 @@ ARWTHVRPawn::ARWTHVRPawn(const FObjectInitializer& ObjectInitializer) : Super(Ob }); } -void ARWTHVRPawn::BeginPlay() -{ - Super::BeginPlay(); - InitialWorldToMeters = GetWorldSettings()->WorldToMeters; -} +void ARWTHVRPawn::BeginPlay() { Super::BeginPlay(); } void ARWTHVRPawn::Tick(float DeltaSeconds) { @@ -75,17 +75,37 @@ void ARWTHVRPawn::Tick(float DeltaSeconds) } /* - * Scales the Pawn while also adjusting the WorldToMeters ratio to adjust for pupillary distance. - * Only supports uniform scaling. + * Scales the Pawn. Only supports uniform scaling. */ void ARWTHVRPawn::SetScale(float NewScale) { - FVector OldScale = GetActorScale(); UniformScale = NewScale; FVector NewScaleVector = FVector(UniformScale, UniformScale, UniformScale); - GetWorldSettings()->WorldToMeters = InitialWorldToMeters * UniformScale; SetActorRelativeScale3D(NewScaleVector); - OnScaleChanged.Broadcast(OldScale, NewScale); + +#if PLATFORM_SUPPORTS_CLUSTER + const ARWTHVRPlayerState* State = GetPlayerState<ARWTHVRPlayerState>(); + if (URWTHVRUtilities::IsRoomMountedMode() && State && State->GetCorrespondingClusterActor()) + { + if (const auto GameMgr = IDisplayCluster::Get().GetGameMgr()) + { + if (const auto ClusterRootActor = GameMgr->GetRootActor()) + { + if (ClusterRootActor->Implements<UScalableConfigInterface>()) + { + IScalableConfigInterface::Execute_OnScaleChanged(ClusterRootActor, NewScale); + } + else + { + UE_LOGFMT(Toolkit, Warning, + "The ClusterRootActor {0} does not implement the ScalableConfigInterface. Scaling the " + "Pawn on the cluster will lead to unintended behavior.", + ClusterRootActor->GetName()); + } + } + } + } +#endif } float ARWTHVRPawn::GetScale() { return UniformScale; } @@ -118,6 +138,12 @@ void ARWTHVRPawn::NotifyControllerChanged() AttachClustertoPawn(); } } + else + { + UE_LOGFMT(Toolkit, Warning, + "ARWTHVRPawn: PlayerState is not a subclass of ARWTHVRPlayerState. Cluster attachment only works " + "with correct PlayerStates!"); + } } } @@ -150,14 +176,18 @@ void ARWTHVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponen if (ARWTHVRPlayerState* State = GetPlayerState<ARWTHVRPlayerState>()) { // Might not be properly synced yet? - const EPlayerType Type = State->GetPlayerType(); + EPlayerType Type = State->GetPlayerType(); // Don't do anything with the type if it's been set to clustertype or anything. // This is already being done when connecting to the server. const bool bClusterType = Type == EPlayerType::nDisplayPrimary || Type == EPlayerType::nDisplaySecondary; - if (!bClusterType && URWTHVRUtilities::IsHeadMountedMode()) + if (!bClusterType) { + if (URWTHVRUtilities::IsHeadMountedMode()) + Type = EPlayerType::HMD; + + UE_LOGFMT(Toolkit, Display, "Pawn: Requesting Player Type {T}...", StaticCast<int8>(Type)); // Could be too early to call this RPC... State->RequestSetPlayerType(Type); } diff --git a/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp b/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp index 0ac047f0c52247b45ec6d78170bf482b88eb6f05..af8fc1089e86f0bdaf6dd63dae95be908bf3fd3c 100644 --- a/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp +++ b/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp @@ -1,6 +1,7 @@ #include "Utility/RWTHVRUtilities.h" #include "AudioDevice.h" +#include "HeadMountedDisplayFunctionLibrary.h" #include "IHeadMountedDisplay.h" #include "IXRTrackingSystem.h" #include "Engine/Engine.h" @@ -16,12 +17,7 @@ DEFINE_LOG_CATEGORY(Toolkit); bool URWTHVRUtilities::IsDesktopMode() { return !IsRoomMountedMode() && !IsHeadMountedMode(); } -bool URWTHVRUtilities::IsHeadMountedMode() -{ - // In editor builds: checks for EdEngine->IsVRPreviewActive() - // In packaged builds: checks for `-vr` in commandline or bStartInVR in UGeneralProjectSettings - return FAudioDevice::CanUseVRAudioDevice(); -} +bool URWTHVRUtilities::IsHeadMountedMode() { return UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled(); } bool URWTHVRUtilities::IsRoomMountedMode() { @@ -38,7 +34,7 @@ bool URWTHVRUtilities::IsPrimaryNode() return URWTHVRClusterUtilities::IsPrimaryNode(); #else return false; -#endif +#endif } float URWTHVRUtilities::GetEyeDistance() diff --git a/Source/RWTHVRToolkit/Public/Core/ClientTransformReplication.h b/Source/RWTHVRToolkit/Public/Core/ClientTransformReplication.h index ac364067efcca3c0c21a6ae940b25ece78914647..c31ed9bd3093670ab88e5c26e38f56a68b86c2f3 100644 --- a/Source/RWTHVRToolkit/Public/Core/ClientTransformReplication.h +++ b/Source/RWTHVRToolkit/Public/Core/ClientTransformReplication.h @@ -56,7 +56,10 @@ protected: // For now, directly apply the transforms: auto* OwningActor = GetOwner(); if (OwningActor && OwningActor->HasValidRootComponent()) - OwningActor->SetActorLocationAndRotation(ReplicatedTransform.Position, ReplicatedTransform.Rotation); + { + OwningActor->SetActorRelativeLocation(ReplicatedTransform.Position); + OwningActor->SetActorRelativeRotation(ReplicatedTransform.Rotation); + } } // Unreliable Server RPC that sends the transform from owning client to the server diff --git a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h index 40eb174f5f82b11a9c30b3130fca1f702a687409..dcd506b1456848cba48f946da63d930b5c651ea1 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h +++ b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h @@ -122,6 +122,5 @@ protected: private: UInputComponent* ActivePlayerInputComponent; - float InitialWorldToMeters; float UniformScale; }; diff --git a/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs b/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs index a949553aaa90bd704c53e9ace2f749073a5441bf..3ca3534e7eb530fa1f3847c8cfc8d4fb18051875 100644 --- a/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs +++ b/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs @@ -38,7 +38,7 @@ public class RWTHVRToolkit : ModuleRules PrivateDependencyModuleNames.AddRange( new string[] { - "NetCore" + "NetCore", "XRBase" } ); if (Target.bBuildEditor == true)