diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a04763c60e0f5c014a1dc04395d381df66262c53..bc970ad30f9378b3c57200a74021f755d3166261 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -80,8 +80,21 @@ Generate_Project: variables: RUN_SETUP: "false" GEN_DEPENDENCIES: "( - [master@UnrealDTrackPlugin]='https://github.com/VRGroupRWTH/UnrealDTrackPlugin.git')" + [master@UnrealDTrackPlugin]='https://github.com/VRGroupRWTH/UnrealDTrackPlugin.git' + [dev/5.3@RWTHVRCluster]='https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/rwth-vr-cluster-plugin.git' + )" +Generate_Project_Without_Cluster: + extends: Generate_Project + variables: + GEN_DEPENDENCIES: "( + [master@UnrealDTrackPlugin]='https://github.com/VRGroupRWTH/UnrealDTrackPlugin.git' + )" + script: # if we don't do this, cooking will for some reason fail even though it should use the correct fallback + - !reference [Generate_Project, script] + - echo "Generating without cluster mode, removing nDisplay configs..." + - cd ${CI_PROJECT_DIR} + - sed -i '/DisplayCluster/d' Config/Linux/LinuxEngine.ini Build_Windows: rules: @@ -124,6 +137,14 @@ Build_Linux: - job: "Generate_Project" artifacts: true + +# Builds for linux without the cluster plugin +Build_Linux_Without_Cluster: + extends: Build_Linux + needs: + - job: "Generate_Project_Without_Cluster" + artifacts: true + # Deploys to vrdev Deploy_Windows: rules: diff --git a/Content/Examples/ContentExamples/ToolkitExamples.umap b/Content/Examples/ContentExamples/ToolkitExamples.umap index c6e4c2d650345e901032eb8d009b9d65375209a0..a06be8deb09551c44e5a20209bb91bedffd98f8b 100644 Binary files a/Content/Examples/ContentExamples/ToolkitExamples.umap and b/Content/Examples/ContentExamples/ToolkitExamples.umap differ diff --git a/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset b/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset index 591070e44ae18b1c035eba19b12492d94c47c7e2..c56c9e266eacda82f508acf1eb330c1499818321 100644 Binary files a/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset and b/Content/Pawn/Base/BP_RWTHVRPawn_Base.uasset differ diff --git a/Content/RWTHVRCluster/BP_CaveSetup.uasset b/Content/RWTHVRCluster/BP_CaveSetup.uasset deleted file mode 100644 index fd882f7f9f9860373421e60fafde5f5b0c03a0cb..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/BP_CaveSetup.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/BP_CaveOverlay.uasset b/Content/RWTHVRCluster/CAVEOverlay/BP_CaveOverlay.uasset deleted file mode 100644 index ab15ee9eb49fa5f0687da7bfff83330b505d4e03..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/BP_CaveOverlay.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/DoorOverlay.uasset b/Content/RWTHVRCluster/CAVEOverlay/DoorOverlay.uasset deleted file mode 100644 index 02f7992b4b6af7ca25e44a5f2f04618957fcaf28..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/DoorOverlay.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/Sign.uasset b/Content/RWTHVRCluster/CAVEOverlay/Sign.uasset deleted file mode 100644 index dba01725bd6912569f4dc77222176010a5698385..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/Sign.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/StopMaterial.uasset b/Content/RWTHVRCluster/CAVEOverlay/StopMaterial.uasset deleted file mode 100644 index 02124fe5bf6a340eba994fd314f01de1a1998b4f..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/StopMaterial.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/StopSign.uasset b/Content/RWTHVRCluster/CAVEOverlay/StopSign.uasset deleted file mode 100644 index e047f7cbd9dc8502782a3fd32df6d1ecf05ffc66..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/StopSign.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/Stripes.uasset b/Content/RWTHVRCluster/CAVEOverlay/Stripes.uasset deleted file mode 100644 index 4406d788871cb62ff42293d6f7b8fb00c942a7ff..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/Stripes.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/CAVEOverlay/TapeMesh.uasset b/Content/RWTHVRCluster/CAVEOverlay/TapeMesh.uasset deleted file mode 100644 index 3cfc67f040145f93432b9c08551fbea851bb3acb..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/CAVEOverlay/TapeMesh.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/Config/aixcave.uasset b/Content/RWTHVRCluster/Config/aixcave.uasset deleted file mode 100644 index 52a33ae06135eef2201a8f1dc59094d3b8cbb73a..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/Config/aixcave.uasset and /dev/null differ diff --git a/Content/RWTHVRCluster/Config/aixcave_two_player.uasset b/Content/RWTHVRCluster/Config/aixcave_two_player.uasset deleted file mode 100644 index f55c6f86b133bd41711850009ee28765f435949c..0000000000000000000000000000000000000000 Binary files a/Content/RWTHVRCluster/Config/aixcave_two_player.uasset and /dev/null differ diff --git a/RWTHVRToolkit.uplugin b/RWTHVRToolkit.uplugin index 7f4a21c631b5af94e1d029792a9a56cb818fe251..4827226d981eeb2cd82d5e1593448f72f33755ff 100644 --- a/RWTHVRToolkit.uplugin +++ b/RWTHVRToolkit.uplugin @@ -15,15 +15,6 @@ "Installed": false, "EnabledByDefault": true, "Modules": [ - { - "Name": "RWTHVRCluster", - "Type": "Runtime", - "LoadingPhase": "Default", - "WhitelistPlatforms": [ - "Win64", - "Linux" - ] - }, { "Name": "RWTHVRToolkit", "Type": "Runtime", @@ -37,22 +28,18 @@ ], "Plugins": [ { - "Name": "nDisplay", - "Enabled": true + "Name": "RWTHVRCluster", + "Enabled": true, + "Optional": true, + "SupportedTargetPlatforms": [ + "Win64", + "Linux" + ] }, { "Name": "LiveLink", "Enabled": true }, - { - "Name": "LiveLinkOvernDisplay", - "Enabled": true - }, - { - "Name": "DTrackPlugin", - "Enabled": true, - "Optional": true - }, { "Name": "EnhancedInput", "Enabled": true @@ -62,9 +49,8 @@ "Enabled": true }, { - "Name": "Switchboard", - "Enabled": true, - "Optional": true + "Name": "XRBase", + "Enabled": true } ] } diff --git a/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp b/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp deleted file mode 100644 index 08d44b21a4e33283daa9a6a29b556beec0289cfa..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp +++ /dev/null @@ -1,357 +0,0 @@ -#include "CAVEOverlay/CAVEOverlayController.h" - -#include "CoreMinimal.h" -#include "EnhancedInputComponent.h" -#include "IDisplayCluster.h" -#include "MotionControllerComponent.h" -#include "Camera/CameraComponent.h" -#include "CAVEOverlay/DoorOverlayData.h" -#include "Cluster/DisplayClusterClusterEvent.h" -#include "Cluster/IDisplayClusterClusterManager.h" -#include "Components/StaticMeshComponent.h" -#include "Engine/CollisionProfile.h" -#include "Logging/StructuredLog.h" -#include "Materials/MaterialInstanceDynamic.h" -#include "Pawn/RWTHVRPawn.h" -#include "Utility/RWTHVRUtilities.h" - - -DEFINE_LOG_CATEGORY(LogCAVEOverlay); - -// Helper function to check if a string is contained within an array of strings, ignoring case. -bool ContainsFString(const TArray<FString>& Array, const FString& Entry) -{ - for (FString Current_Entry : Array) - { - if (Current_Entry.Equals(Entry, ESearchCase::IgnoreCase)) - return true; - } - return false; -} - -UStaticMeshComponent* ACAVEOverlayController::CreateMeshComponent(const FName& Name, USceneComponent* Parent) -{ - UStaticMeshComponent* Result = CreateDefaultSubobject<UStaticMeshComponent>(Name); - Result->SetupAttachment(Parent); - Result->SetVisibility(false); - Result->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName); - return Result; -} - -// Sets default values -ACAVEOverlayController::ACAVEOverlayController() -{ - // Set this actor to call Tick() every frame. - PrimaryActorTick.bCanEverTick = true; - bAllowTickBeforeBeginPlay = false; - - // Creation of sub-components - Root = CreateDefaultSubobject<USceneComponent>("DefaultSceneRoot"); - SetRootComponent(Root); - - Tape = CreateMeshComponent("Tape", Root); - SignRightHand = CreateMeshComponent("SignRightHand", Root); - SignLeftHand = CreateMeshComponent("SignLeftHand", Root); -} - -void ACAVEOverlayController::CycleDoorType() -{ - DoorCurrentMode = static_cast<EDoorMode>((DoorCurrentMode + 1) % DOOR_NUM_MODES); - - // Send out a cluster event to the whole cluster that the door mode has been changed - if (auto* const Manager = IDisplayCluster::Get().GetClusterMgr()) - { - FDisplayClusterClusterEventJson cluster_event; - cluster_event.Name = "CAVEOverlay Change Door to " + DoorModeNames[DoorCurrentMode]; - cluster_event.Type = "DoorChange"; - cluster_event.Category = "CAVEOverlay"; - cluster_event.Parameters.Add("NewDoorState", FString::FromInt(DoorCurrentMode)); - Manager->EmitClusterEventJson(cluster_event, true); - } -} - -void ACAVEOverlayController::HandleClusterEvent(const FDisplayClusterClusterEventJson& Event) -{ - if (Event.Category.Equals("CAVEOverlay") && Event.Type.Equals("DoorChange") && - Event.Parameters.Contains("NewDoorState")) - { - SetDoorMode(static_cast<EDoorMode>(FCString::Atoi(*Event.Parameters["NewDoorState"]))); - } -} - -void ACAVEOverlayController::SetDoorMode(const EDoorMode NewMode) -{ - DoorCurrentMode = NewMode; - switch (DoorCurrentMode) - { - case EDoorMode::DOOR_DEBUG: - case EDoorMode::DOOR_PARTIALLY_OPEN: - DoorCurrentOpeningWidthAbsolute = DoorOpeningWidthAbsolute; - if (ScreenType == SCREEN_DOOR) - Overlay->BlackBox->SetRenderScale(FVector2D(0, 1)); - if (ScreenType == SCREEN_DOOR_PARTIAL) - Overlay->BlackBox->SetRenderScale(FVector2D(DoorOpeningWidthRelative, 1)); - if (ScreenType == SCREEN_PRIMARY) - Overlay->BlackBox->SetRenderScale(FVector2D(0, 1)); - - Overlay->BlackBox->SetVisibility(ESlateVisibility::Visible); - break; - case EDoorMode::DOOR_OPEN: - DoorCurrentOpeningWidthAbsolute = WallDistance * 2; - if (ScreenType == SCREEN_DOOR) - Overlay->BlackBox->SetRenderScale(FVector2D(1, 1)); - if (ScreenType == SCREEN_DOOR_PARTIAL) - Overlay->BlackBox->SetRenderScale(FVector2D(1, 1)); - if (ScreenType == SCREEN_PRIMARY) - Overlay->BlackBox->SetRenderScale(FVector2D(0, 1)); - - Overlay->BlackBox->SetVisibility(ESlateVisibility::Visible); - break; - case EDoorMode::DOOR_CLOSED: - DoorCurrentOpeningWidthAbsolute = 0; - if (ScreenType == SCREEN_DOOR) - Overlay->BlackBox->SetRenderScale(FVector2D(0, 1)); - if (ScreenType == SCREEN_DOOR_PARTIAL) - Overlay->BlackBox->SetRenderScale(FVector2D(0, 1)); - if (ScreenType == SCREEN_PRIMARY) - Overlay->BlackBox->SetRenderScale(FVector2D(0, 1)); - - Overlay->BlackBox->SetVisibility(ESlateVisibility::Hidden); - break; - default:; - } - - // On the secondary nodes that are not the door, hide the overlay completely - // It might make more sense to just not add it there... - if (ScreenType == SCREEN_NORMAL) - Overlay->BlackBox->SetRenderScale(FVector2D(0, 1)); - - UE_LOGFMT(LogCAVEOverlay, Log, "Switched door state to {State}. New opening width is {Width}.", - *DoorModeNames[DoorCurrentMode], DoorCurrentOpeningWidthAbsolute); - - // On the primary node, show which door mode is currently active. - if (ScreenType == SCREEN_PRIMARY) - { - Overlay->CornerText->SetText(FText::FromString(DoorModeNames[DoorCurrentMode])); - } -} - -// Called when the game starts or when spawned -void ACAVEOverlayController::BeginPlay() -{ - Super::BeginPlay(); - - // Don't do anything if we're a dedicated server. We shouldn't even exist there. - if (GetNetMode() == NM_DedicatedServer) - return; - - // Currently, there is no support for multi-user systems in general, as we only depend on the local pawn. - // In a MU setting, the relevant pawn isn't our local one, but the primary node's pawn. - if (GetNetMode() != NM_Standalone) - return; - - // This should return the respective client's local playercontroller or, if we're a listen server, our own PC. - auto* PC = GetWorld() ? GetWorld()->GetFirstPlayerController() : nullptr; - - // it can happen that the PC is valid, but we have no player attached to it yet. - // Check for this - however, we should work around it by somehow getting notified when that happens. - // Not sure which place would be best... - const bool bValidPC = PC && PC->GetLocalPlayer(); - - if (!bValidPC || !URWTHVRUtilities::IsRoomMountedMode()) - return; - - // Input config - if (URWTHVRUtilities::IsPrimaryNode()) - { - if (CycleDoorTypeInputAction == nullptr) - { - UE_LOGFMT(LogCAVEOverlay, Error, "Input action and mapping not set in CaveOverlayController!"); - return; - } - - UEnhancedInputComponent* Input = Cast<UEnhancedInputComponent>(PC->InputComponent); - Input->BindAction(CycleDoorTypeInputAction, ETriggerEvent::Triggered, this, - &ACAVEOverlayController::CycleDoorType); - } - - // Bind the cluster events that manage the door state. - IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); - if (ClusterManager && !ClusterEventListenerDelegate.IsBound()) - { - ClusterEventListenerDelegate = - FOnClusterEventJsonListener::CreateUObject(this, &ACAVEOverlayController::HandleClusterEvent); - ClusterManager->AddClusterEventJsonListener(ClusterEventListenerDelegate); - } - - // Determine the screen-type for later usage - if (IDisplayCluster::Get().GetClusterMgr()->GetNodeId().Equals(ScreenMain, ESearchCase::IgnoreCase)) - { - ScreenType = SCREEN_PRIMARY; - } - else if (ContainsFString(ScreensDoor, IDisplayCluster::Get().GetClusterMgr()->GetNodeId())) - { - ScreenType = SCREEN_DOOR; - } - else if (ContainsFString(ScreensDoorPartial, IDisplayCluster::Get().GetClusterMgr()->GetNodeId())) - { - ScreenType = SCREEN_DOOR_PARTIAL; - } - else - { - ScreenType = SCREEN_NORMAL; - } - - // Create and add widget to local playercontroller. - if (!OverlayClass) - { - UE_LOGFMT(LogCAVEOverlay, Error, "OverlayClass not set in CaveOverlayController!"); - return; - } - - Overlay = CreateWidget<UDoorOverlayData>(PC, OverlayClass); - Overlay->AddToViewport(0); - - // Set the default door mode (partially open) - SetDoorMode(DoorCurrentMode); - - // Set Text to "" until someone presses the key for the first time - Overlay->CornerText->SetText(FText::FromString("")); - - // Get the pawn so we can have access to head and hand positions - VRPawn = Cast<ARWTHVRPawn>(PC->GetPawnOrSpectator()); - if (VRPawn) - { - // we're good to go! - bInitialized = true; - } - else - { - UE_LOGFMT(LogCAVEOverlay, Error, "No VirtualRealityPawn found which we could attach to!"); - } - - // Create dynamic materials at runtime - TapeMaterialDynamic = Tape->CreateDynamicMaterialInstance(0); - RightSignMaterialDynamic = SignRightHand->CreateDynamicMaterialInstance(0); - LeftSignMaterialDynamic = SignLeftHand->CreateDynamicMaterialInstance(0); - - UE_LOGFMT(LogCAVEOverlay, Display, "CaveOverlay Initialization was successfull."); -} - -void ACAVEOverlayController::EndPlay(const EEndPlayReason::Type EndPlayReason) -{ - IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); - if (ClusterManager && ClusterEventListenerDelegate.IsBound()) - { - ClusterManager->RemoveClusterEventJsonListener(ClusterEventListenerDelegate); - } - - Super::EndPlay(EndPlayReason); -} - -double ACAVEOverlayController::CalculateOpacityFromPosition(const FVector& Position) const -{ - // Calculate opacity value depending on how far we are from the walls. Further away == lower opacity, - // fully opaque when WallFadeDistance away from the wall. Could just use a lerp here.. - return FMath::Max( - FMath::Clamp((FMath::Abs(Position.X) - (WallDistance - WallCloseDistance)) / WallFadeDistance, 0.0, 1.0), - FMath::Clamp((FMath::Abs(Position.Y) - (WallDistance - WallCloseDistance)) / WallFadeDistance, 0.0, 1.0)); -} - -bool ACAVEOverlayController::PositionInDoorOpening(const FVector& Position) const -{ - // The position of the corner with 10cm of buffer. In negative direction because the door is in negative direction - // of the cave - const float CornerValue = -(WallDistance + 10); - - // Check whether our X position is within the door zone. This zone starts 10cm further away from the wall - // than the WallCloseDistance, and ends 10cm outside of the wall (door). As the door is in negative X direction, - // the signs need to be negated. - const bool bXWithinDoor = - FMath::IsWithinInclusive(Position.X, CornerValue, -(WallDistance - WallCloseDistance - 10)); - - // Checks whether our Y position is between the lower corner with some overlap and - // the door corner (CornerValue + DoorCurrentOpeningWidthAbsolute) - const bool bYWithinDoor = - FMath::IsWithinInclusive(Position.Y, CornerValue, CornerValue + DoorCurrentOpeningWidthAbsolute); - return bXWithinDoor && bYWithinDoor; -} - -void ACAVEOverlayController::SetSignsForHand(UStaticMeshComponent* Sign, const FVector& HandPosition, - UMaterialInstanceDynamic* HandMaterial) const -{ - const bool bHandIsCloseToWall = - FMath::IsWithinInclusive(HandPosition.GetAbsMax(), WallDistance - WallCloseDistance, WallDistance); - if (bHandIsCloseToWall && !PositionInDoorOpening(HandPosition)) - { - Sign->SetVisibility(true); - HandMaterial->SetScalarParameterValue("SignOpacity", CalculateOpacityFromPosition(HandPosition)); - - // Which wall are we closest to? This is the wall we project the sign onto - const bool bXWallCloser = FMath::Abs(HandPosition.X) > FMath::Abs(HandPosition.Y); - - // Set the position towards the closest wall to the wall itself, keep the other positions - const double X = bXWallCloser ? FMath::Sign(HandPosition.X) * WallDistance : HandPosition.X; - const double Y = bXWallCloser ? HandPosition.Y : FMath::Sign(HandPosition.Y) * WallDistance; - const double Z = HandPosition.Z; - - // Rotate the sign by 90° if we're on a side wall - const auto Rot = bXWallCloser ? FRotator(0, 0, 0) : FRotator(0, 90, 0); - const auto Pos = FVector(X, Y, Z); - Sign->SetRelativeLocationAndRotation(Pos, Rot); - } - else - { - Sign->SetVisibility(false); - } -} - -void ACAVEOverlayController::Tick(float DeltaTime) -{ - Super::Tick(DeltaTime); - - // If we're not yet initialized, do nothing. This shouldn't really happen as we only spawn on the cave anyway - if (!bInitialized) - { - return; - } - - // Head/Tape Logic - const FVector HeadPosition = VRPawn->HeadCameraComponent->GetRelativeTransform().GetLocation(); - const bool bHeadIsCloseToWall = - FMath::IsWithinInclusive(HeadPosition.GetAbsMax(), WallDistance - WallCloseDistance, WallDistance); - - // Only show the tape when close to a wall and not within the door opening - if (bHeadIsCloseToWall && !PositionInDoorOpening(HeadPosition)) - { - Tape->SetVisibility(true); - - // Offset the tape in z direction to always be at head height - Tape->SetRelativeLocation(HeadPosition * FVector(0, 0, 1)); - - TapeMaterialDynamic->SetScalarParameterValue("BarrierOpacity", CalculateOpacityFromPosition(HeadPosition)); - - if (FMath::IsWithin(FVector2D(HeadPosition).GetAbsMax(), WallDistance - WallWarningDistance, WallDistance)) - { - // in warning distance == red tape - TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 0, 0)); - } - else - { - // otherwise we're just yellow - TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 1, 0)); - } - } - else - { - Tape->SetVisibility(false); - } - - // Hand Logic - const FVector RightPosition = VRPawn->RightHand->GetRelativeTransform().GetLocation(); - const FVector LeftPosition = VRPawn->LeftHand->GetRelativeTransform().GetLocation(); - - // Set the position rotation, opacity, visibility of the hand warning signs. - SetSignsForHand(SignRightHand, RightPosition, RightSignMaterialDynamic); - SetSignsForHand(SignLeftHand, LeftPosition, LeftSignMaterialDynamic); -} diff --git a/Source/RWTHVRCluster/Private/CaveSetup.cpp b/Source/RWTHVRCluster/Private/CaveSetup.cpp deleted file mode 100644 index c39e47d4997863ee26b9fe5065c327efc6aa669f..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Private/CaveSetup.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "CaveSetup.h" - -#include "Logging/StructuredLog.h" -#include "Utility/RWTHVRUtilities.h" - - -// Sets default values -ACaveSetup::ACaveSetup() -{ - PrimaryActorTick.bCanEverTick = false; - SetActorEnableCollision(false); - - // Actor needs to replicate, as it is attached to the pawn on the server. - bReplicates = true; -} - -// Called when the game starts or when spawned -void ACaveSetup::BeginPlay() -{ - Super::BeginPlay(); - - if (!URWTHVRUtilities::IsRoomMountedMode()) - { - return; - } - - // Spawn all actors that are set in the blueprint asset. - for (const auto ActorClass : ActorsToSpawnOnCave) - { - if (const auto World = GetWorld()) - { - const auto Actor = World->SpawnActor(ActorClass); - Actor->AttachToActor(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale); - UE_LOGFMT(LogTemp, Display, "CaveSetup: Spawned Actor {Actor} on the Cave and attached it.", - Actor->GetName()); - } - } - - // Apply the DTrack LiveLink Preset. Only do this if we are the primaryNode - - if (URWTHVRUtilities::IsPrimaryNode()) - { - if (LiveLinkPresetToApplyOnCave && LiveLinkPresetToApplyOnCave->IsValidLowLevelFast()) - { - LiveLinkPresetToApplyOnCave->ApplyToClientLatent(); - - UE_LOGFMT(LogTemp, Display, "CaveSetup: Applied LiveLinkPreset {Preset} to Client.", - LiveLinkPresetToApplyOnCave->GetName()); - } - } -} diff --git a/Source/RWTHVRCluster/Private/ClusterConsole/ClusterConsole.cpp b/Source/RWTHVRCluster/Private/ClusterConsole/ClusterConsole.cpp deleted file mode 100644 index a0a7c49523e7191163cb53a5c290f9459c73f3f1..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Private/ClusterConsole/ClusterConsole.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "ClusterConsole/ClusterConsole.h" - -#include "IDisplayCluster.h" -#include "Cluster/DisplayClusterClusterEvent.h" - -void FClusterConsole::Register() -{ - /* Registering console command */ - ClusterConsoleCommand = IConsoleManager::Get().RegisterConsoleCommand( - TEXT("ClusterExecute"), - TEXT("<Your Command> - Execute commands on every node of the nDisplay cluster by prepending ClusterExecute"), - FConsoleCommandWithArgsDelegate::CreateLambda( - [](const TArray<FString>& Args) - { - if (IDisplayCluster::Get().GetClusterMgr() == nullptr || Args.Num() == 0) - return; - - /* Emitting cluster event */ - FDisplayClusterClusterEventJson ClusterEvent; - ClusterEvent.Name = "ClusterExecute " + Args[0]; - ClusterEvent.Type = Args[0]; - ClusterEvent.Category = "NDisplayClusterExecute"; - ClusterEvent.Parameters.Add("Command", FString::Join(Args, TEXT(" "))); - - IDisplayCluster::Get().GetClusterMgr()->EmitClusterEventJson(ClusterEvent, false); - })); - - /* Register cluster event handling */ - const IDisplayCluster* DisplayCluster = FModuleManager::LoadModulePtr<IDisplayCluster>(IDisplayCluster::ModuleName); - if (DisplayCluster && !ClusterEventListenerDelegate.IsBound()) - { - ClusterEventListenerDelegate = FOnClusterEventJsonListener::CreateLambda( - [](const FDisplayClusterClusterEventJson& Event) - { - /* Actual handling */ - if (Event.Category.Equals("NDisplayClusterExecute") && Event.Parameters.Contains("Command") && GEngine) - { - GEngine->Exec(GEngine->GetCurrentPlayWorld(), *Event.Parameters["Command"]); - } - }); - DisplayCluster->GetClusterMgr()->AddClusterEventJsonListener(ClusterEventListenerDelegate); - } -} - -void FClusterConsole::Unregister() const -{ - IConsoleManager::Get().UnregisterConsoleObject(ClusterConsoleCommand); - IDisplayCluster::Get().GetClusterMgr()->RemoveClusterEventJsonListener(ClusterEventListenerDelegate); -} diff --git a/Source/RWTHVRCluster/Private/RWTHVRCluster.cpp b/Source/RWTHVRCluster/Private/RWTHVRCluster.cpp deleted file mode 100644 index 3f0955de6db6984ba796eb5c6ae793141456c25e..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Private/RWTHVRCluster.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "RWTHVRCluster.h" - -#define LOCTEXT_NAMESPACE "FRWTHVRClusterModule" - -void FRWTHVRClusterModule::StartupModule() { ClusterConsole.Register(); } - -void FRWTHVRClusterModule::ShutdownModule() { ClusterConsole.Unregister(); } - -#undef LOCTEXT_NAMESPACE - -IMPLEMENT_MODULE(FRWTHVRClusterModule, RWTHVRCluster) diff --git a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h b/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h deleted file mode 100644 index 148897a8713c726bc9583de176cf04040b657074..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "GameFramework/Actor.h" -#include "CAVEOverlay/DoorOverlayData.h" -#include "Cluster/IDisplayClusterClusterManager.h" -#include "Pawn/RWTHVRPawn.h" -#include "CAVEOverlayController.generated.h" - -DECLARE_LOG_CATEGORY_EXTERN(LogCAVEOverlay, Log, All); - -/** - * Actor which controls the cave overlay. The overlay displays a warning tape around the cave - * when the user moves their head too close to the wall, and a warning sign when the hands are - * too close. - */ -UCLASS() -class RWTHVRCLUSTER_API ACAVEOverlayController : public AActor -{ - GENERATED_BODY() - -public: - ACAVEOverlayController(); - -protected: - virtual void BeginPlay() override; - virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; - -private: - // Types of cave screens defined in the cluster config. - enum EScreen_Type - { - // the primary node screen - SCREEN_PRIMARY, - // any secondary node screen - SCREEN_NORMAL, - // the screens that cover the partially opened door - SCREEN_DOOR_PARTIAL, - // additional screens that cover the door - SCREEN_DOOR - }; - - // which screen type this node is running on - EScreen_Type ScreenType = SCREEN_NORMAL; - - // which additional node names define the screens that cover the door - const TArray<FString> ScreensDoor = {"node_bul_left_eye", "node_bul_right_eye", "node_bll_left_eye", - "node_bll_right_eye"}; - - // which node names define the screens that cover the partial door - const TArray<FString> ScreensDoorPartial = {"node_bur_left_eye", "node_bur_right_eye", "node_blr_left_eye", - "node_blr_right_eye"}; - - const FString ScreenMain = "node_main"; - - // Door Mode - enum EDoorMode - { - DOOR_PARTIALLY_OPEN = 0, - DOOR_OPEN = 1, - DOOR_CLOSED = 2, - DOOR_DEBUG = 3, - DOOR_NUM_MODES = 4 - }; - - const FString DoorModeNames[DOOR_NUM_MODES] = {"Partially Open", "Open", "Closed", "Debug"}; - EDoorMode DoorCurrentMode = DOOR_PARTIALLY_OPEN; - const float DoorOpeningWidthRelative = 0.522; //%, used for the overlay width on the screen - const float DoorOpeningWidthAbsolute = 165; // cm, used for the non tape part at the door - const float WallDistance = 262.5; // cm, distance from center to a wall, *2 = wall width - const float WallCloseDistance = 75; // cm, the distance considered to be too close to the walls - const float WallFadeDistance = 35; // cm, the distance over which the tape is faded - const float WallWarningDistance = 40; // cm, distance on which the tape turns red, measured from wall - float DoorCurrentOpeningWidthAbsolute = 0; - - // Helper function to create a mesh component in the constructor - UStaticMeshComponent* CreateMeshComponent(const FName& Name, USceneComponent* Parent); - - // Calculates opacity value used for the dynamic materials of the tape and sign. The closer the more opaque. - double CalculateOpacityFromPosition(const FVector& Position) const; - - // Check whether the given position is within the door area of the (partially) open door. - bool PositionInDoorOpening(const FVector& Position) const; - - // Sets the position, orientation and opacity/visibility of the Sign according to the HandPosition. - void SetSignsForHand(UStaticMeshComponent* Sign, const FVector& HandPosition, - UMaterialInstanceDynamic* HandMaterial) const; - - // Only calculate positions and material values when we're fully initialized. - bool bInitialized = false; - - // Reference to the currently active pawn that we're tracking positions of. - UPROPERTY() - ARWTHVRPawn* VRPawn; - - // Cluster Events - FOnClusterEventJsonListener ClusterEventListenerDelegate; - void HandleClusterEvent(const FDisplayClusterClusterEventJson& Event); - -public: - virtual void Tick(float DeltaTime) override; - - // Change door mode manually between open, partially open and closed. - void CycleDoorType(); - void SetDoorMode(EDoorMode M); - - // Root component - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) - USceneComponent* Root; - - // Tape Static Mesh component. Reference to static mesh needs to be set in the corresponding BP. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) - UStaticMeshComponent* Tape; - - // Right Hand Sign Static Mesh component. Reference to static mesh needs to be set in the corresponding BP. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) - UStaticMeshComponent* SignRightHand; - - // Left Hand Sign Static Mesh component. Reference to static mesh needs to be set in the corresponding BP. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "CAVEOverlay", meta = (AllowPrivateAccess = "true")) - UStaticMeshComponent* SignLeftHand; - - // UI Overlay - UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "CAVEOverlay") - TSubclassOf<UDoorOverlayData> OverlayClass; - - // UI Overlay - UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "CAVEOverlay") - UInputAction* CycleDoorTypeInputAction; - - UPROPERTY() - UDoorOverlayData* Overlay; - - // Dynamic Materials to control opacity - UPROPERTY() - UMaterialInstanceDynamic* TapeMaterialDynamic; - - UPROPERTY() - UMaterialInstanceDynamic* RightSignMaterialDynamic; - - UPROPERTY() - UMaterialInstanceDynamic* LeftSignMaterialDynamic; -}; diff --git a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlaySettings.h b/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlaySettings.h deleted file mode 100644 index eee4b554ffa439a6d1f743144fa44689de5193d7..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlaySettings.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "CoreMinimal.h" -#include "Engine/DeveloperSettings.h" -#include "CAVEOverlaySettings.generated.h" - -UENUM(BlueprintType) -enum DefaultActivationType -{ - DefaultActivationType_OFF UMETA(DisplayName = "Off by default"), - DefaultActivationType_ON UMETA(DisplayName = "On by default") -}; - -UCLASS(config = Game, defaultconfig, meta = (DisplayName = "CAVE Overlay")) -class RWTHVRCLUSTER_API UCAVEOverlaySettings : public UDeveloperSettings -{ - GENERATED_BODY() - -public: - UPROPERTY(EditAnywhere, config, Category = "General", meta = (DisplayName = "Default Activation Type")) - TEnumAsByte<DefaultActivationType> DefaultActivationType = DefaultActivationType_ON; - - UPROPERTY(EditAnywhere, config, Category = Maps, meta = (AllowedClasses = "/Script/Engine.World")) - TArray<FSoftObjectPath> ExcludedMaps; -}; diff --git a/Source/RWTHVRCluster/Public/CAVEOverlay/DoorOverlayData.h b/Source/RWTHVRCluster/Public/CAVEOverlay/DoorOverlayData.h deleted file mode 100644 index b4a0fada65f6f01d398e73a33de60b4fec4dc307..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/CAVEOverlay/DoorOverlayData.h +++ /dev/null @@ -1,27 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Blueprint/UserWidget.h" -#include "Components/TextBlock.h" -#include "Components/Border.h" -#include "DoorOverlayData.generated.h" - -/** - * Used as a parent-class in the overlay widget. Like this we can access the UMG properties in C++ - */ -UCLASS() -class RWTHVRCLUSTER_API UDoorOverlayData : public UUserWidget -{ - GENERATED_BODY() - -public: - // These declarations are magically bound to the UMG blueprints elements, - // if they are named the same - UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) - UTextBlock* CornerText; - - UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) - UBorder* BlackBox; -}; diff --git a/Source/RWTHVRCluster/Public/CaveSetup.h b/Source/RWTHVRCluster/Public/CaveSetup.h deleted file mode 100644 index 793d72c9ff419ce35aade0784a2d076cbff3a37e..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/CaveSetup.h +++ /dev/null @@ -1,33 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "LiveLinkPreset.h" -#include "GameFramework/Actor.h" -#include "CaveSetup.generated.h" - -/** - * Simple Actor that needs to be added to the level which spawns Cave-related actors - * such as the CaveOverlay. - * It attaches itself to the Primary Node's Pawn and then replicates on the server. - */ - -UCLASS(hideCategories = (Rendering, Input, Actor, Base, Collision, Shape, Physics, HLOD)) -class RWTHVRCLUSTER_API ACaveSetup : public AActor -{ - GENERATED_BODY() - -public: - ACaveSetup(); - - UPROPERTY(EditAnywhere) - TArray<UClass*> ActorsToSpawnOnCave; - - UPROPERTY(EditAnywhere, BlueprintReadWrite) - ULiveLinkPreset* LiveLinkPresetToApplyOnCave; - -protected: - // Called when the game starts or when spawned - virtual void BeginPlay() override; -}; diff --git a/Source/RWTHVRCluster/Public/ClusterConsole/ClusterConsole.h b/Source/RWTHVRCluster/Public/ClusterConsole/ClusterConsole.h deleted file mode 100644 index f09a948c64f5b82b1c50c62cfb5b4a7ca86118a8..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/ClusterConsole/ClusterConsole.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "HAL/IConsoleManager.h" -#include "Cluster/IDisplayClusterClusterManager.h" -#include "ClusterConsole.generated.h" - -/** - * The ClusterConsole provides the console command "ClusterExecute" - * The code catches your command, broadcasts it to every nDisplay node and executes it everywhere - * - * This class has to be registered and unregistered. This can easily be done in every StartupModule/ShutdownModule - * functions. - */ -USTRUCT() -struct RWTHVRCLUSTER_API FClusterConsole -{ - GENERATED_BODY() - -private: - /* Used for ClusterExecute console command */ - IConsoleCommand* ClusterConsoleCommand = nullptr; - FOnClusterEventJsonListener ClusterEventListenerDelegate; - -public: - void Register(); - void Unregister() const; -}; diff --git a/Source/RWTHVRCluster/Public/Events/DisplayClusterEventParameterHelper.h b/Source/RWTHVRCluster/Public/Events/DisplayClusterEventParameterHelper.h deleted file mode 100644 index 49500b767751ada9db7d935be95de34311540ad5..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/Events/DisplayClusterEventParameterHelper.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "Serialization/MemoryReader.h" -#include "Serialization/MemoryWriter.h" -#include "type_traits" - -template <typename ParameterType, typename... RemainingParameterTypes> -inline void SerializeParameters(FMemoryWriter* MemoryWriter, ParameterType&& Parameter, - RemainingParameterTypes&&... RemainingParameters) -{ - using NonConstType = typename std::remove_cv_t<typename TRemoveReference<ParameterType>::Type>; - // const_cast because the same operator (<<) is used for reading and writing - (*MemoryWriter) << const_cast<NonConstType&>(Parameter); - SerializeParameters(MemoryWriter, Forward<RemainingParameterTypes>(RemainingParameters)...); -} - -inline void SerializeParameters(FMemoryWriter* MemoryWriter) {} - -// This is a wrapper function to recursively fill the argument tuple. This overload is only used if the index indicating -// the currently handled attribute is less than the number of total attributes. I.e., if the attribute index is valid. -template <int CurrentIndex, typename... ArgTypes> -inline typename TEnableIf<(CurrentIndex < sizeof...(ArgTypes))>::Type -FillArgumentTuple(FMemoryReader* MemoryReader, TTuple<ArgTypes...>* ArgumentTuple) -{ - // Read the "<<" as ">>" operator here. FArchive uses the same for both and decides based on an internal type on - // what to do. So this statement parses the bytes that were passed into reader and puts the parsed object into the - // tuple at index CurrentIndex. - (*MemoryReader) << ArgumentTuple->template Get<CurrentIndex>(); - - // Recursive call for the remaining attributes. - FillArgumentTuple<CurrentIndex + 1>(MemoryReader, Forward<TTuple<ArgTypes...>*>(ArgumentTuple)); -} - -// The overload that is called if we are "passed the end" of attributes. -template <int CurrentIndex, typename... ArgTypes> -inline typename TEnableIf<(CurrentIndex >= sizeof...(ArgTypes))>::Type -FillArgumentTuple(FMemoryReader* MemoryReader, TTuple<ArgTypes...>* ArgumentTuple) -{ -} - -template <typename RetType, typename... ArgTypes> -inline RetType CallDelegateWithParameterMap(const TDelegate<RetType, ArgTypes...>& Delegate, - const TMap<FString, FString>& Parameters) -{ - // Create a tuple that holds all arguments. This assumes that all argument types are default constructible. However, - // all types that overload the FArchive "<<" operator probably are. - TTuple<typename std::remove_cv_t<typename TRemoveReference<ArgTypes>::Type>...> ArgumentTuple; - - // This call will parse the string map and fill all values in the tuple appropriately. - FillArgumentTuple<0>(&ArgumentTuple, Parameters); - - // The lambda function is only necessary because delegates do not overload the ()-operator but use the Execute() - // method instead. So, the lambda acts as a wrapper. - return ArgumentTuple.ApplyBefore([Delegate](ArgTypes&&... Arguments) - { Delegate.Execute(Forward<ArgTypes>(Arguments)...); }); -} diff --git a/Source/RWTHVRCluster/Public/Events/DisplayClusterEventWrapper.h b/Source/RWTHVRCluster/Public/Events/DisplayClusterEventWrapper.h deleted file mode 100644 index e08fed921287bbad6a76367e590cc21e2b476b5d..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/Events/DisplayClusterEventWrapper.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once - -#include "IDisplayCluster.h" -#include "Cluster/IDisplayClusterClusterManager.h" -#include "Cluster/DisplayClusterClusterEvent.h" -#include "DisplayClusterEventParameterHelper.h" -#include "Templates/IsInvocable.h" - -static constexpr int32 CLUSTER_EVENT_WRAPPER_EVENT_ID = 1337420; - -template <typename MemberFunctionType, MemberFunctionType MemberFunction> -class ClusterEventWrapperEvent; - -template <typename ObjectType, typename ReturnType, typename... ArgTypes, - ReturnType (ObjectType::*MemberFunction)(ArgTypes...)> -class ClusterEventWrapperEvent<ReturnType (ObjectType::*)(ArgTypes...), MemberFunction> -{ - static_assert(TIsDerivedFrom<ObjectType, UObject>::IsDerived, "Object needs to derive from UObject"); - -public: - using MemberFunctionType = decltype(MemberFunction); - - ClusterEventWrapperEvent(const TCHAR* MethodName) : MethodName{MethodName} {} - - void Attach(ObjectType* NewObject) - { - checkf(Object == nullptr, TEXT("The event is already attached.")); - Object = NewObject; - ObjectId = Object->GetUniqueID(); - - EDisplayClusterOperationMode OperationMode = IDisplayCluster::Get().GetOperationMode(); - if (OperationMode == EDisplayClusterOperationMode::Cluster) - { - IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); - check(ClusterManager != nullptr); - - check(!ClusterEventListenerDelegate.IsBound()); - ClusterEventListenerDelegate = FOnClusterEventBinaryListener::CreateLambda( - [this](const FDisplayClusterClusterEventBinary& Event) - { - if (Event.EventId != CLUSTER_EVENT_WRAPPER_EVENT_ID) - { - return; - } - - FMemoryReader MemoryReader(Event.EventData); - - uint32 EventObjectId; - // This reads the value! - MemoryReader << EventObjectId; - if (EventObjectId != ObjectId) - { - // Event does not belong to this object. - return; - } - - FString EventMethodName; - // This reads the value! - MemoryReader << EventMethodName; - if (EventMethodName != MethodName) - { - // This event does not belong to this method. - return; - } - - // Create a tuple that holds all arguments. This assumes that all - // argument types are default constructible. However, all - // types that overload the FArchive "<<" operator probably are. - TTuple<typename std::remove_cv_t<typename TRemoveReference<ArgTypes>::Type>...> ArgumentTuple; - - // This call will deserialze the values and fill all values in the tuple appropriately. - FillArgumentTuple<0>(&MemoryReader, &ArgumentTuple); - - ArgumentTuple.ApplyBefore([this](const ArgTypes&... Arguments) - { (Object->*MemberFunction)(Forward<const ArgTypes&>(Arguments)...); }); - }); - ClusterManager->AddClusterEventBinaryListener(ClusterEventListenerDelegate); - } - } - - void Detach() - { - checkf(Object != nullptr, TEXT("The event was never attached.")); - - EDisplayClusterOperationMode OperationMode = IDisplayCluster::Get().GetOperationMode(); - if (OperationMode == EDisplayClusterOperationMode::Cluster) - { - IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); - check(ClusterManager != nullptr); - - // check(ClusterEventListenerDelegate.IsBound()); - ClusterManager->RemoveClusterEventBinaryListener(ClusterEventListenerDelegate); - } - } - - void Send(ArgTypes... Arguments) - { - checkf(Object != nullptr, TEXT("The event was not attached.")); - - EDisplayClusterOperationMode OperationMode = IDisplayCluster::Get().GetOperationMode(); - if (OperationMode != EDisplayClusterOperationMode::Cluster) - { - (Object->*MemberFunction)(Forward<ArgTypes>(Arguments)...); - } - else - { - IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); - check(ClusterManager != nullptr); - - FDisplayClusterClusterEventBinary ClusterEvent; - ClusterEvent.EventId = CLUSTER_EVENT_WRAPPER_EVENT_ID; - ClusterEvent.bShouldDiscardOnRepeat = false; - - FMemoryWriter MemoryWriter(ClusterEvent.EventData); - MemoryWriter << ObjectId; - MemoryWriter << const_cast<FString&>(MethodName); - SerializeParameters(&MemoryWriter, Forward<ArgTypes>(Arguments)...); - - ClusterManager->EmitClusterEventBinary(ClusterEvent, true); - } - } - -private: - const FString MethodName; - uint32 ObjectId; - ObjectType* Object = nullptr; - FOnClusterEventBinaryListener ClusterEventListenerDelegate; -}; - -#define DCEW_STRINGIFY(x) #x -#define DCEW_TOSTRING(x) DCEW_STRINGIFY(x) - -#define DECLARE_DISPLAY_CLUSTER_EVENT(OwningType, MethodIdentifier) \ - ClusterEventWrapperEvent<decltype(&OwningType::MethodIdentifier), &OwningType::MethodIdentifier> \ - MethodIdentifier##Event \ - { \ - TEXT(DCEW_TOSTRING(OwningType) DCEW_TOSTRING(MethodIdentifier)) \ - } diff --git a/Source/RWTHVRCluster/Public/RWTHVRCluster.h b/Source/RWTHVRCluster/Public/RWTHVRCluster.h deleted file mode 100644 index 1c719c718aa503615557da6e7f713256a8232859..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/Public/RWTHVRCluster.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "Modules/ModuleManager.h" -#include "ClusterConsole/ClusterConsole.h" - -class FRWTHVRClusterModule : public IModuleInterface -{ -public: - virtual void StartupModule() override; - virtual void ShutdownModule() override; - -private: - FClusterConsole ClusterConsole; -}; diff --git a/Source/RWTHVRCluster/RWTHVRCluster.Build.cs b/Source/RWTHVRCluster/RWTHVRCluster.Build.cs deleted file mode 100644 index 6979cc65cea0cc0f7fca763bb7d7afa9c13f0577..0000000000000000000000000000000000000000 --- a/Source/RWTHVRCluster/RWTHVRCluster.Build.cs +++ /dev/null @@ -1,69 +0,0 @@ -using UnrealBuildTool; - -public class RWTHVRCluster : ModuleRules -{ - public RWTHVRCluster(ReadOnlyTargetRules Target) : base(Target) - { - PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; - - PublicIncludePaths.AddRange( - new string[] { } - ); - - PrivateIncludePaths.AddRange( - new string[] { } - ); - - PublicDependencyModuleNames.AddRange( - new string[] - { - "Core", - "CoreUObject", - "Engine", - "DeveloperSettings", - "EnhancedInput", - "UMG", - "Slate", - "SlateCore", - "RWTHVRToolkit", - "LiveLink" - } - ); - - if (IsPluginEnabledForTarget("nDisplay", base.Target)) - { - PublicDependencyModuleNames.AddRange( - new string[] - { - "DisplayCluster" - } - ); - } - - if (IsPluginEnabledForTarget("DTrackPlugin", base.Target)) - { - PublicDependencyModuleNames.AddRange( - new string[] - { - "DTrackPlugin", - "DTrackInput" - } - ); - } - - PrivateDependencyModuleNames.AddRange( - new string[] { } - ); - - DynamicallyLoadedModuleNames.AddRange( - new string[] { } - ); - } - - private static bool IsPluginEnabledForTarget(string PluginName, ReadOnlyTargetRules Target) - { - var PL = Plugins.GetPlugin(PluginName); - return PL != null && Target.ProjectFile != null && Plugins.IsPluginEnabledForTarget(PL, - ProjectDescriptor.FromFile(Target.ProjectFile), Target.Platform, Target.Configuration, Target.Type); - } -} \ No newline at end of file diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp index 9ae825fc21b3fa370faec8bbaa1c7b063bb21b25..f99b7d65df959a5725996eebaab3ec8bc2fd89e9 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/IntenSelect/IntenSelectable.cpp @@ -4,6 +4,7 @@ #include "Interaction/Interactables/IntenSelect/IntenSelectableScoring.h" #include "Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h" #include "Kismet/KismetSystemLibrary.h" +#include "Logging/StructuredLog.h" #include "Misc/MessageDialog.h" #include "Pawn/IntenSelectComponent.h" #include "Utility/RWTHVRUtilities.h" @@ -46,9 +47,9 @@ void UIntenSelectable::BeginPlay() { if (ScoringBehaviours.Num() == 0) { - URWTHVRUtilities::ShowErrorAndQuit( - "Please assign the Scoring Behaviour manually when using more than one IntenSelectable Component!", - false, this); + UE_LOGFMT( + Toolkit, Error, + "Please assign the Scoring Behaviour manually when using more than one IntenSelectable Component!"); } } else diff --git a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp index 56d56cf05728cc0ce2140f47d0b39a19e0dc665c..9801f83893cb31dec6b04d71c4f26e3696c2234b 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp @@ -16,6 +16,10 @@ #include "Roles/LiveLinkTransformTypes.h" #include "Utility/RWTHVRUtilities.h" +#if PLATFORM_SUPPORTS_CLUSTER +#include "Components/DisplayClusterSceneComponentSyncParent.h" +#endif + ARWTHVRPawn::ARWTHVRPawn(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { BaseEyeHeight = 160.0f; @@ -36,14 +40,21 @@ ARWTHVRPawn::ARWTHVRPawn(const FObjectInitializer& ObjectInitializer) : Super(Ob LeftHand = CreateDefaultSubobject<UReplicatedMotionControllerComponent>(TEXT("Left Hand MCC")); LeftHand->SetupAttachment(RootComponent); +} +void ARWTHVRPawn::BeginPlay() +{ + Super::BeginPlay(); +#if PLATFORM_SUPPORTS_CLUSTER // Add an nDisplay Parent Sync Component. It syncs the parent's transform from master to clients. // This is required because for collision based movement, it can happen that the physics engine // for some reason acts different on the nodes, therefore leading to a potential desync when // e.g. colliding with an object while moving. - SyncComponent = - CreateDefaultSubobject<UDisplayClusterSceneComponentSyncParent>(TEXT("Parent Display Cluster Sync Component")); - SyncComponent->SetupAttachment(RootComponent); + + SyncComponent = Cast<USceneComponent>(AddComponentByClass(UDisplayClusterSceneComponentSyncParent::StaticClass(), + false, FTransform::Identity, false)); + AddInstanceComponent(SyncComponent); +#endif } void ARWTHVRPawn::Tick(float DeltaSeconds) diff --git a/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp b/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp index ed5bfea32b0297dc3efe72487784d202ac197ea9..1a57b331df01f70bf330c8e9c4826d309fa616a8 100644 --- a/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp +++ b/Source/RWTHVRToolkit/Private/Utility/RWTHVRUtilities.cpp @@ -1,15 +1,5 @@ #include "Utility/RWTHVRUtilities.h" -#if PLATFORM_SUPPORTS_NDISPLAY -#include "DisplayClusterConfigurationTypes.h" -#include "DisplayClusterRootActor.h" -#include "IDisplayCluster.h" -#include "Cluster/IDisplayClusterClusterManager.h" -#include "Components/DisplayClusterCameraComponent.h" -#include "Config/IDisplayClusterConfigManager.h" -#include "Game/IDisplayClusterGameManager.h" -#endif - #include "AudioDevice.h" #include "IHeadMountedDisplay.h" #include "IXRTrackingSystem.h" @@ -17,20 +7,15 @@ #include "Engine/LocalPlayer.h" #include "Kismet/GameplayStatics.h" +#if PLATFORM_SUPPORTS_CLUSTER +#include "Utility/RWTHVRClusterUtilities.h" +#endif + DEFINE_LOG_CATEGORY(Toolkit); bool URWTHVRUtilities::IsDesktopMode() { return !IsRoomMountedMode() && !IsHeadMountedMode(); } -bool URWTHVRUtilities::IsRoomMountedMode() -{ -#if PLATFORM_SUPPORTS_NDISPLAY - return IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster; -#else - return false; -#endif -} - bool URWTHVRUtilities::IsHeadMountedMode() { // In editor builds: checks for EdEngine->IsVRPreviewActive() @@ -38,62 +23,20 @@ bool URWTHVRUtilities::IsHeadMountedMode() return FAudioDevice::CanUseVRAudioDevice(); } -bool URWTHVRUtilities::IsCave() +bool URWTHVRUtilities::IsRoomMountedMode() { -#if PLATFORM_SUPPORTS_NDISPLAY - if (!IsRoomMountedMode()) - return false; - - const UDisplayClusterConfigurationData* ClusterConfig = IDisplayCluster::Get().GetConfigMgr()->GetConfig(); - return ClusterConfig->CustomParameters.Contains("Hardware_Platform") && - ClusterConfig->CustomParameters.Find("Hardware_Platform")->Equals("aixcave", ESearchCase::IgnoreCase); -#else - return false; +#if PLATFORM_SUPPORTS_CLUSTER + URWTHVRClusterUtilities::IsRoomMountedMode(); #endif -} - -bool URWTHVRUtilities::IsRolv() -{ -#if PLATFORM_SUPPORTS_NDISPLAY - if (!IsRoomMountedMode()) - return false; - - const UDisplayClusterConfigurationData* ClusterConfig = IDisplayCluster::Get().GetConfigMgr()->GetConfig(); - return ClusterConfig->CustomParameters.Contains("Hardware_Platform") && - ClusterConfig->CustomParameters.Find("Hardware_Platform")->Equals("ROLV", ESearchCase::IgnoreCase); -#else return false; -#endif } -/* Return true on the Primary in cluster mode and in a normal desktop session. Otherwise false */ bool URWTHVRUtilities::IsPrimaryNode() { -#if PLATFORM_SUPPORTS_NDISPLAY - if (!IDisplayCluster::IsAvailable()) - { - return true; - } - IDisplayClusterClusterManager* Manager = IDisplayCluster::Get().GetClusterMgr(); - if (Manager == nullptr) - { - return true; // if we are not in cluster mode, we are always the primary node - } - return Manager->IsPrimary() || !Manager->IsSecondary(); -#else - return true; -#endif -} - -bool URWTHVRUtilities::IsSecondaryNode() { return !IsPrimaryNode(); } - -FString URWTHVRUtilities::GetNodeName() -{ -#if PLATFORM_SUPPORTS_NDISPLAY - return IsRoomMountedMode() ? IDisplayCluster::Get().GetClusterMgr()->GetNodeId() : FString(TEXT("Localhost")); -#else - return FString(TEXT("Localhost")); +#if PLATFORM_SUPPORTS_CLUSTER + URWTHVRClusterUtilities::IsPrimaryNode(); #endif + return false; } float URWTHVRUtilities::GetEyeDistance() @@ -102,81 +45,7 @@ float URWTHVRUtilities::GetEyeDistance() { return GEngine->XRSystem->GetHMDDevice()->GetInterpupillaryDistance(); } - else - { -#if PLATFORM_SUPPORTS_NDISPLAY - const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor(); - return (RootActor) ? RootActor->GetDefaultCamera()->GetInterpupillaryDistance() : 0.0f; -#else - return 0.0f; -#endif - } -} - -EEyeStereoOffset URWTHVRUtilities::GetNodeEyeType() -{ -#if PLATFORM_SUPPORTS_NDISPLAY - const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor(); - return static_cast<EEyeStereoOffset>((RootActor) ? RootActor->GetDefaultCamera()->GetStereoOffset() - : EDisplayClusterEyeStereoOffset::None); -#else - return EDisplayClusterEyeStereoOffset::None; -#endif -} -void URWTHVRUtilities::ShowErrorAndQuit(const FString& Message, bool ShouldQuit, const UObject* WorldContext) -{ - UE_LOG(LogTemp, Error, TEXT("%s"), *Message) -#if WITH_EDITOR - FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message)); -#endif - if (ShouldQuit) - { - UKismetSystemLibrary::QuitGame(WorldContext, nullptr, EQuitPreference::Quit, false); - } -} - -USceneComponent* URWTHVRUtilities::GetClusterComponent(const FString& Name) -{ -#if PLATFORM_SUPPORTS_NDISPLAY - const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor(); - return (RootActor) ? RootActor->GetComponentByName<USceneComponent>(Name) : nullptr; -#else - return nullptr; -#endif -} - -USceneComponent* URWTHVRUtilities::GetNamedClusterComponent(const ENamedClusterComponent& Component) -{ - switch (Component) - { - case ENamedClusterComponent::NCC_CAVE_ORIGIN: - return GetClusterComponent("cave_origin"); - case ENamedClusterComponent::NCC_CAVE_CENTER: - return GetClusterComponent("cave_center"); - case ENamedClusterComponent::NCC_CAVE_LHT: - return GetClusterComponent("left_hand_target"); - case ENamedClusterComponent::NCC_CAVE_RHT: - return GetClusterComponent("right_hand_target"); - case ENamedClusterComponent::NCC_SHUTTERGLASSES: - return GetClusterComponent("shutter_glasses"); - case ENamedClusterComponent::NCC_ROLV_ORIGIN: - return GetClusterComponent("rolv_origin"); - case ENamedClusterComponent::NCC_FLYSTICK: - return GetClusterComponent("flystick"); - case ENamedClusterComponent::NCC_CALIBRATIO: - return GetClusterComponent("calibratio"); - case ENamedClusterComponent::NCC_TRACKING_ORIGIN: - USceneComponent* Result; - if ((Result = GetClusterComponent("cave_origin"))) - return Result; - if ((Result = GetClusterComponent("rolv_origin"))) - return Result; - if ((Result = GetClusterComponent("tdw_origin_floor"))) - return Result; - return nullptr; - default: - return nullptr; - } + return 0; } void URWTHVRUtilities::ShowErrorAndQuit(UWorld* WorldContext, const FString& Message) diff --git a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h index 490dffdf9445a9578e43cf15f6b062b73b70baf1..abe9255dd701b20595c5ee56caff2702f1d60a36 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h +++ b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h @@ -6,8 +6,6 @@ #include "LiveLinkRole.h" #include "Pawn/Navigation/CollisionHandlingMovement.h" -#include "Components/DisplayClusterSceneComponentSyncParent.h" - #include "RWTHVRPawn.generated.h" class UInputMappingContext; @@ -27,6 +25,8 @@ class RWTHVRTOOLKIT_API ARWTHVRPawn : public APawn public: ARWTHVRPawn(const FObjectInitializer& ObjectInitializer); + virtual void BeginPlay() override; + virtual void Tick(float DeltaSeconds) override; virtual void NotifyControllerChanged() override; @@ -54,8 +54,8 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera") UCameraComponent* HeadCameraComponent; - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera") - UDisplayClusterSceneComponentSyncParent* SyncComponent; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn") + USceneComponent* SyncComponent; // LiveLink functionality diff --git a/Source/RWTHVRToolkit/Public/Utility/RWTHVRUtilities.h b/Source/RWTHVRToolkit/Public/Utility/RWTHVRUtilities.h index 978b12b962c0e32bd655a74b80a55f77f6a6b0d3..c6b547336d00f2b88633806be95456597d2af12f 100644 --- a/Source/RWTHVRToolkit/Public/Utility/RWTHVRUtilities.h +++ b/Source/RWTHVRToolkit/Public/Utility/RWTHVRUtilities.h @@ -2,7 +2,6 @@ #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" -#include "UObject/ConstructorHelpers.h" #include "RWTHVRUtilities.generated.h" @@ -12,75 +11,25 @@ */ DECLARE_LOG_CATEGORY_EXTERN(Toolkit, Log, All); -UENUM(BlueprintType) -enum class ENamedClusterComponent : uint8 -{ - /* CAVE Specific */ - NCC_CAVE_ORIGIN UMETA(DisplayName = "CAVE Origin"), - NCC_CAVE_CENTER UMETA(DisplayName = "CAVE Center"), - NCC_CAVE_LHT UMETA(DisplayName = "CAVE Left Hand Target"), - NCC_CAVE_RHT UMETA(DisplayName = "CAVE Right Hand Target"), - - /* ROLV Specific */ - NCC_ROLV_ORIGIN UMETA(DisplayName = "ROLV Origin"), - - /* Non Specific */ - NCC_CALIBRATIO UMETA(DisplayName = "Calibratio Motion to Photon Measurement Device"), - NCC_SHUTTERGLASSES UMETA(DisplayName = "CAVE/ROLV/TDW Shutter Glasses"), - NCC_FLYSTICK UMETA(DisplayName = "CAVE/ROLV/TDW Flystick"), - NCC_TRACKING_ORIGIN UMETA(DisplayName = "CAVE/ROLV/TDW Origin") -}; - -UENUM() -enum class EEyeStereoOffset -{ - None, - Left, - Right -}; - UCLASS() class RWTHVRTOOLKIT_API URWTHVRUtilities : public UBlueprintFunctionLibrary { GENERATED_BODY() public: - UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") + UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform") static bool IsDesktopMode(); - UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") - static bool IsRoomMountedMode(); - UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") + UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform") static bool IsHeadMountedMode(); - UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") - static bool IsCave(); - UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") - static bool IsRolv(); - - UFUNCTION(BlueprintPure, Category = "DisplayCluster") + UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform") + static bool IsRoomMountedMode(); + UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform") static bool IsPrimaryNode(); - UFUNCTION(BlueprintPure, Category = "DisplayCluster") - static bool IsSecondaryNode(); - UFUNCTION(BlueprintPure, Category = "DisplayCluster") - static FString GetNodeName(); /* Distance in meters */ - UFUNCTION(BlueprintPure, Category = "DisplayCluster") + UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit") static float GetEyeDistance(); - UFUNCTION(BlueprintPure, Category = "DisplayCluster") - static EEyeStereoOffset GetNodeEyeType(); - - static void ShowErrorAndQuit(const FString& Message, bool ShouldQuit, const UObject* WorldContext); - - // Get Component of Display Cluster by it's name, which is specified in the nDisplay config - UE_DEPRECATED(5.4, "GetClusterComponent has been removed because it is obsolete.") - UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster", meta = (DeprecatedFunction)) - static USceneComponent* GetClusterComponent(const FString& Name); - - UE_DEPRECATED(5.4, "GetNamedClusterComponent has been removed because it is obsolete.") - UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster", meta = (DeprecatedFunction)) - static USceneComponent* GetNamedClusterComponent(const ENamedClusterComponent& Component); - UFUNCTION(BlueprintCallable) static void ShowErrorAndQuit(UWorld* WorldContext, const FString& Message); }; diff --git a/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs b/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs index 930dc9129b0fbcf2ba9b275595cea42f42866238..a949553aaa90bd704c53e9ace2f749073a5441bf 100644 --- a/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs +++ b/Source/RWTHVRToolkit/RWTHVRToolkit.Build.cs @@ -49,15 +49,23 @@ public class RWTHVRToolkit : ModuleRules DynamicallyLoadedModuleNames.AddRange( new string[]{} ); - - if(Target.Platform == UnrealTargetPlatform.Win64 || Target.Platform == UnrealTargetPlatform.Linux) + + if (IsPluginEnabledForTarget("RWTHVRCluster", base.Target)) { - PublicDependencyModuleNames.Add("DisplayCluster"); - PublicDefinitions.Add("PLATFORM_SUPPORTS_NDISPLAY=1"); + PrivateDependencyModuleNames.Add("RWTHVRCluster"); + PrivateDependencyModuleNames.Add("DisplayCluster"); + PublicDefinitions.Add("PLATFORM_SUPPORTS_CLUSTER=1"); } else - { - PublicDefinitions.Add("PLATFORM_SUPPORTS_NDISPLAY=0"); + { + PublicDefinitions.Add("PLATFORM_SUPPORTS_CLUSTER=0"); } } + + private static bool IsPluginEnabledForTarget(string PluginName, ReadOnlyTargetRules Target) + { + var PL = Plugins.GetPlugin(PluginName); + return PL != null && Target.ProjectFile != null && Plugins.IsPluginEnabledForTarget(PL, + ProjectDescriptor.FromFile(Target.ProjectFile), Target.Platform, Target.Configuration, Target.Type); + } }