diff --git a/Content/Pawn/BP_RWTHVRPawn_Default.uasset b/Content/Pawn/BP_RWTHVRPawn_Default.uasset
index cb05e67f79561281c52e04b21e9bd67726871dbb..145ddf5f938d0a3612c7a609aafa75a30d82063f 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 3616819e69aa1ac0f21047b036be9244b1597c76..cba6c2e1875f45603f51e234dbb9b066017654f9 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/RWTHVRGameModeBase.cpp b/Source/RWTHVRToolkit/Private/Core/RWTHVRGameModeBase.cpp
index 4d9b4b6e4dcdb1447e2d9ff98fbfc5400f000589..a30a7ab130e1b84263f54aee3840c91705ef1b42 100644
--- a/Source/RWTHVRToolkit/Private/Core/RWTHVRGameModeBase.cpp
+++ b/Source/RWTHVRToolkit/Private/Core/RWTHVRGameModeBase.cpp
@@ -7,9 +7,15 @@
 #include "GameFramework/SpectatorPawn.h"
 #include "Kismet/GameplayStatics.h"
 #include "Logging/StructuredLog.h"
+#include "Pawn/ClusterRepresentationActor.h"
 #include "Utility/RWTHVRUtilities.h"
 
 
+ARWTHVRGameModeBase::ARWTHVRGameModeBase(const FObjectInitializer& ObjectInitializer)
+{
+	PlayerStateClass = ARWTHVRPlayerState::StaticClass();
+}
+
 FString ARWTHVRGameModeBase::InitNewPlayer(APlayerController* NewPlayerController, const FUniqueNetIdRepl& UniqueId,
 										   const FString& Options, const FString& Portal)
 {
@@ -17,6 +23,7 @@ FString ARWTHVRGameModeBase::InitNewPlayer(APlayerController* NewPlayerControlle
 	// but I don't really want to introduce a hard dependency here.
 	const FString NodeNameKey = "node";
 	const FString PrimaryNodeIdKey = "PrimaryNodeId";
+	const FString ClusterIdKey = "ClusterId";
 
 	// Check if we're using our custom PlayerState so that we can save the player type there.
 	// If not, just ingore all related args.
@@ -24,6 +31,7 @@ FString ARWTHVRGameModeBase::InitNewPlayer(APlayerController* NewPlayerControlle
 
 	if (State != nullptr)
 	{
+		int32 ClusterId = -1;
 		if (UGameplayStatics::HasOption(Options, PrimaryNodeIdKey))
 		{
 			const FString PrimaryNodeId = UGameplayStatics::ParseOption(Options, PrimaryNodeIdKey);
@@ -34,10 +42,51 @@ FString ARWTHVRGameModeBase::InitNewPlayer(APlayerController* NewPlayerControlle
 				? UGameplayStatics::ParseOption(Options, NodeNameKey)
 				: PrimaryNodeId;
 
+			ClusterId = UGameplayStatics::HasOption(Options, ClusterIdKey)
+				? TextKeyUtil::HashString(*UGameplayStatics::ParseOption(Options, ClusterIdKey))
+				: -1;
+
 			const EPlayerType Type =
 				NodeName == PrimaryNodeId ? EPlayerType::nDisplayPrimary : EPlayerType::nDisplaySecondary;
 			State->RequestSetPlayerType(Type);
 		}
+		else if (GetNetMode() == NM_Standalone && URWTHVRUtilities::IsRoomMountedMode())
+		{
+			ClusterId = 0;
+		}
+
+		// If we're in none-standalone netmode, this is only executed on the server, as the GM only exists there.
+		// On standalone, this is executed on every node.
+
+		State->SetCorrespondingClusterId(ClusterId);
+
+		auto* ClusterRepresentation = ConnectedClusters.Find(ClusterId);
+		if (!ClusterRepresentation)
+		{
+			// No actor there yet, spawn it
+			FActorSpawnParameters SpawnParameters;
+			SpawnParameters.Name = FName(*FString::Printf(TEXT("ClusterRepresentation_%d"), ClusterId));
+			ClusterRepresentation = GetWorld()->SpawnActor<AClusterRepresentationActor>(SpawnParameters);
+			ClusterRepresentation->ClusterId = ClusterId;
+			UE_LOGFMT(Toolkit, Display,
+					  "ARWTHVRGameModeBase: Spawned ClusterRepresentationActor {Name} for Cluster {Id}",
+					  ClusterRepresentation->GetName(), ClusterId);
+		}
+
+		UE_LOGFMT(Toolkit, Display, "ARWTHVRGameModeBase: Using ClusterRepresentationActor {Name} for Cluster {Id}",
+				  ClusterRepresentation->GetName(), ClusterId);
+
+		// Double check for sanity
+		check(ClusterId == ClusterRepresentation->ClusterId);
+
+		State->SetCorrespondingClusterActor(ClusterRepresentation);
+		State->SetCorrespondingClusterId(ClusterId);
+
+		if (State->GetPlayerType() == EPlayerType::nDisplayPrimary)
+		{
+			// We're the owner of the actor!
+			ClusterRepresentation->SetOwner(NewPlayerController);
+		}
 	}
 
 	return Super::InitNewPlayer(NewPlayerController, UniqueId, Options, Portal);
@@ -88,6 +137,5 @@ void ARWTHVRGameModeBase::PostLogin(APlayerController* NewPlayer)
 		NewPlayer->Possess(ResultPawn);
 	}
 
-
 	Super::PostLogin(NewPlayer);
 }
diff --git a/Source/RWTHVRToolkit/Private/Core/RWTHVRPlayerState.cpp b/Source/RWTHVRToolkit/Private/Core/RWTHVRPlayerState.cpp
index 0ad60f0c44a7853df65507cd23b9943c6cd8530b..4ae4795c85058331aeea4a2ff08df643b3cccd05 100644
--- a/Source/RWTHVRToolkit/Private/Core/RWTHVRPlayerState.cpp
+++ b/Source/RWTHVRToolkit/Private/Core/RWTHVRPlayerState.cpp
@@ -3,8 +3,10 @@
 
 #include "Core/RWTHVRPlayerState.h"
 
+#include "Logging/StructuredLog.h"
 #include "Net/UnrealNetwork.h"
 #include "Net/Core/PushModel/PushModel.h"
+#include "Utility/RWTHVRUtilities.h"
 
 // Boilerplate, copies properties to new state
 void ARWTHVRPlayerState::CopyProperties(class APlayerState* PlayerState)
@@ -17,6 +19,8 @@ void ARWTHVRPlayerState::CopyProperties(class APlayerState* PlayerState)
 		if (IsValid(RWTHVRPlayerState))
 		{
 			RWTHVRPlayerState->SetPlayerType(GetPlayerType());
+			RWTHVRPlayerState->SetCorrespondingClusterId(CorrespondingClusterId);
+			RWTHVRPlayerState->SetCorrespondingClusterActor(CorrespondingClusterActor);
 		}
 	}
 }
@@ -32,6 +36,8 @@ void ARWTHVRPlayerState::OverrideWith(class APlayerState* PlayerState)
 		if (IsValid(RWTHVRPlayerState))
 		{
 			SetPlayerType(RWTHVRPlayerState->GetPlayerType());
+			SetCorrespondingClusterId(RWTHVRPlayerState->CorrespondingClusterId);
+			SetCorrespondingClusterActor(RWTHVRPlayerState->CorrespondingClusterActor);
 		}
 	}
 }
@@ -45,6 +51,8 @@ void ARWTHVRPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& O
 	SharedParams.bIsPushBased = true;
 
 	DOREPLIFETIME_WITH_PARAMS_FAST(ARWTHVRPlayerState, PlayerType, SharedParams);
+	DOREPLIFETIME_WITH_PARAMS_FAST(ARWTHVRPlayerState, CorrespondingClusterId, SharedParams);
+	DOREPLIFETIME_WITH_PARAMS_FAST(ARWTHVRPlayerState, CorrespondingClusterActor, SharedParams);
 }
 
 void ARWTHVRPlayerState::ServerSetPlayerTypeRpc_Implementation(const EPlayerType NewPlayerType)
@@ -57,6 +65,28 @@ void ARWTHVRPlayerState::SetPlayerType(const EPlayerType NewPlayerType)
 	MARK_PROPERTY_DIRTY_FROM_NAME(ARWTHVRPlayerState, PlayerType, this);
 	PlayerType = NewPlayerType;
 }
+void ARWTHVRPlayerState::SetCorrespondingClusterId(int32 NewCorrespondingClusterId)
+{
+	if (!HasAuthority())
+	{
+		UE_LOGFMT(Toolkit, Warning, "ARWTHVRPlayerState: Cannot set cluster Id on non-authority!");
+		return;
+	}
+
+	MARK_PROPERTY_DIRTY_FROM_NAME(ARWTHVRPlayerState, CorrespondingClusterId, this);
+	CorrespondingClusterId = NewCorrespondingClusterId;
+}
+void ARWTHVRPlayerState::SetCorrespondingClusterActor(AClusterRepresentationActor* NewCorrespondingClusterActor)
+{
+	if (!HasAuthority())
+	{
+		UE_LOGFMT(Toolkit, Warning, "ARWTHVRPlayerState: Cannot set cluster actor ref on non-authority!");
+		return;
+	}
+
+	MARK_PROPERTY_DIRTY_FROM_NAME(ARWTHVRPlayerState, CorrespondingClusterActor, this);
+	CorrespondingClusterActor = NewCorrespondingClusterActor;
+}
 
 void ARWTHVRPlayerState::RequestSetPlayerType(const EPlayerType NewPlayerType)
 {
diff --git a/Source/RWTHVRToolkit/Private/Pawn/ClusterRepresentationActor.cpp b/Source/RWTHVRToolkit/Private/Pawn/ClusterRepresentationActor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f3ec515bdaffef8dfde867961f5f23fe7d4ff1c6
--- /dev/null
+++ b/Source/RWTHVRToolkit/Private/Pawn/ClusterRepresentationActor.cpp
@@ -0,0 +1,142 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "Pawn/ClusterRepresentationActor.h"
+
+#include "DisplayClusterRootActor.h"
+#include "IDisplayCluster.h"
+#include "Config/IDisplayClusterConfigManager.h"
+#include "Core/RWTHVRPlayerState.h"
+#include "Game/IDisplayClusterGameManager.h"
+#include "Kismet/GameplayStatics.h"
+#include "Logging/StructuredLog.h"
+#include "Utility/RWTHVRUtilities.h"
+
+// Sets default values
+AClusterRepresentationActor::AClusterRepresentationActor()
+{
+	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
+	PrimaryActorTick.bCanEverTick = false;
+	bReplicates = true;
+	SetActorEnableCollision(false);
+
+	SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("Origin")));
+}
+
+void AClusterRepresentationActor::BeginPlay()
+{
+	Super::BeginPlay();
+
+	// We need to identify the correct ClusterRepresentationActor to do the attachment.
+	// 1. Either we are the local net owner -> Primary Node Pawn
+	// This is hard to do as things might not be synchronized yet.
+	// In this case I think this is save to do because either:
+	// - We are in standalone mode, then attach it for all nodes
+	// - If we are a client, this actor has been spawned on the server only. Therefore I assume that if we
+	//   have replicated this actor to our client, we're good to go.
+
+	if (!URWTHVRUtilities::IsRoomMountedMode())
+		return;
+
+	// This should give us the first local player controller
+	const auto* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
+	
+	// Only run this for the local controller - redundant, but double check
+	if (!PlayerController || !PlayerController->IsLocalController())
+		return;
+
+	const auto* PlayerState = PlayerController->GetPlayerState<ARWTHVRPlayerState>();
+	if (!PlayerState)
+	{
+		UE_LOGFMT(
+			Toolkit, Error,
+			"AClusterRepresentationActor::BeginPlay: PlayerState is not valid or not of type ARWTHVRPlayerState.");
+		return;
+	}
+
+	// The local player this is executed on corresponds to this actor
+	if (PlayerState->GetCorrespondingClusterActor() == this)
+	{
+		check(PlayerState->GetCorrespondingClusterId() == ClusterId);
+		UE_LOGFMT(Toolkit, Display, "AClusterRepresentationActor::BeginPlay: Attaching DCRA to {Name} with Id: {Id}.",
+				  GetName(), ClusterId);
+
+		AttachDCRA();
+	}
+}
+
+bool AClusterRepresentationActor::AttachDCRA()
+{
+
+#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.
+
+	if (URWTHVRUtilities::IsRoomMountedMode())
+	{
+		UE_LOGFMT(Toolkit, Display, "{Name}: Trying to attach DCRA for ClusterId {Id}", GetName(), ClusterId);
+		auto DCRA = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
+
+		if (!IsValid(DCRA))
+		{
+			UE_LOGFMT(Toolkit, Display, "No Valid DCRA in BeginPlay. Spawning manually.");
+
+			DCRA = SpawnDCRA();
+			if (!IsValid(DCRA))
+			{
+				UE_LOGFMT(Toolkit, Error, "Failed to spawn correct DCRA, cannot attach it to ClusterRepresentation.");
+				return false;
+			}
+		}
+		else // if we just spawned the DCRA, it is not yet the primary one and this check makes no sense
+		{
+			if (!DCRA->IsPrimaryRootActor())
+			{
+				UE_LOGFMT(Toolkit, Error, "Found DCRA {Name} is not the primary DCRA of Cluster with Id {Id}!",
+						  DCRA->GetName(), ClusterId);
+				return false;
+			}
+		}
+
+		bool bAttached = DCRA->AttachToActor(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
+		UE_LOGFMT(Toolkit, Display, "Attaching {This} to DCRA {DCRA} returned {Res}", GetName(), DCRA->GetName(),
+				  bAttached);
+
+		DCRA->SetActorEnableCollision(false);
+	}
+#endif
+	return true;
+}
+
+ADisplayClusterRootActor* AClusterRepresentationActor::SpawnDCRA()
+{
+	UDisplayClusterConfigurationData* ConfigData = IDisplayCluster::Get().GetConfigMgr()->GetConfig();
+
+
+	// Function similar to the one from DisplayClusterGameManager.
+	ADisplayClusterRootActor* RootActor = nullptr;
+	// We need to use generated class as it's the only one available in packaged buidls
+	const FString AssetPath =
+		(ConfigData->Info.AssetPath.EndsWith(TEXT("_C")) ? ConfigData->Info.AssetPath
+														 : ConfigData->Info.AssetPath + TEXT("_C"));
+
+	if (UClass* ActorClass = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), nullptr, *AssetPath)))
+	{
+		// Spawn the actor
+		if (AActor* NewActor = GetWorld()->SpawnActor<AActor>(ActorClass))
+		{
+			RootActor = Cast<ADisplayClusterRootActor>(NewActor);
+
+			if (RootActor)
+			{
+				UE_LOG(Toolkit, Log, TEXT("Instantiated DCRA from asset '%s'"), *ConfigData->Info.AssetPath);
+
+				// Override actor settings in case the config file contains some updates
+				RootActor->OverrideFromConfig(ConfigData);
+			}
+		}
+	}
+	return RootActor;
+}
\ No newline at end of file
diff --git a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp
index d50578531749b295d79961ac45eab7ebfd097c7e..0d11d17ce60aff2dccac2c6472640409db3f7fb1 100644
--- a/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp
+++ b/Source/RWTHVRToolkit/Private/Pawn/RWTHVRPawn.cpp
@@ -8,8 +8,8 @@
 #include "ILiveLinkClient.h"
 #include "InputMappingContext.h"
 #include "Core/RWTHVRPlayerState.h"
-#include "Kismet/GameplayStatics.h"
 #include "Logging/StructuredLog.h"
+#include "Pawn/ClusterRepresentationActor.h"
 #include "Pawn/InputExtensionInterface.h"
 #include "Pawn/Navigation/CollisionHandlingMovement.h"
 #include "Pawn/ReplicatedCameraComponent.h"
@@ -61,7 +61,7 @@ void ARWTHVRPawn::Tick(float DeltaSeconds)
  * as connections now send their playertype over.
  */
 // This pawn's controller has changed! This is called on both server and owning client. If we are the owning client
-// and the master, request that the DCRA is attached to us.
+// and the master, request that the Cluster is attached to us.
 void ARWTHVRPawn::NotifyControllerChanged()
 {
 	Super::NotifyControllerChanged();
@@ -71,7 +71,7 @@ void ARWTHVRPawn::NotifyControllerChanged()
 	if (HasAuthority())
 	{
 		UE_LOG(Toolkit, Display,
-			   TEXT("ARWTHVRPawn: Player Controller has changed, trying to change DCRA attachment if possible..."));
+			   TEXT("ARWTHVRPawn: Player Controller has changed, trying to change Cluster attachment if possible..."));
 		if (const ARWTHVRPlayerState* State = GetPlayerState<ARWTHVRPlayerState>())
 		{
 			const EPlayerType Type = State->GetPlayerType();
@@ -80,8 +80,8 @@ void ARWTHVRPawn::NotifyControllerChanged()
 			// For all other player types this is a race condition
 			if (Type == EPlayerType::nDisplayPrimary || GetNetMode() == NM_Standalone)
 			{
-				UE_LOGFMT(Toolkit, Display, "ARWTHVRPawn: Attaching DCRA to Pawn {Pawn}.", GetName());
-				AttachDCRAtoPawn();
+				UE_LOGFMT(Toolkit, Display, "ARWTHVRPawn: Attaching Cluster to Pawn {Pawn}.", GetName());
+				AttachClustertoPawn();
 			}
 		}
 	}
@@ -259,31 +259,27 @@ void ARWTHVRPawn::MulticastAddDCSyncComponent_Implementation()
 #endif
 }
 
-// Executed on the server only: Finds and attaches the CaveSetup Actor, which contains the DCRA to the Pawn.
+// Executed on the server only: Attaches the ClusterRepresentation Actor, which contains the DCRA to the Pawn.
 // It is only executed on the server because attachments are synced to all clients, but not from client to server.
-void ARWTHVRPawn::AttachDCRAtoPawn()
+void ARWTHVRPawn::AttachClustertoPawn()
 {
-	if (!CaveSetupActorClass || !CaveSetupActorClass->IsValidLowLevelFast())
-	{
-		UE_LOGFMT(Toolkit, Warning, "No CaveSetup Actor class set in pawn!");
-		return;
-	}
-
-	// Find our CaveSetup actor
-	TArray<AActor*> FoundActors;
-	UGameplayStatics::GetAllActorsOfClass(GetWorld(), CaveSetupActorClass, FoundActors);
 
-	if (!FoundActors.IsEmpty())
+	if (const ARWTHVRPlayerState* State = GetPlayerState<ARWTHVRPlayerState>())
 	{
-		const auto CaveSetupActor = FoundActors[0];
-		FAttachmentTransformRules AttachmentRules = FAttachmentTransformRules::SnapToTargetNotIncludingScale;
-		CaveSetupActor->AttachToActor(this, AttachmentRules);
-		UE_LOGFMT(Toolkit, Display, "VirtualRealityPawn: Attaching CaveSetup to our pawn!");
+		if (!State->GetCorrespondingClusterActor())
+			UE_LOGFMT(Toolkit, Error,
+					  "ARWTHVRPawn::AttachClustertoPawn: GetCorrespondingClusterActor returned null! This won't work on "
+					  "the Cave.");
+
+		const FAttachmentTransformRules AttachmentRules = FAttachmentTransformRules::SnapToTargetNotIncludingScale;
+		bool bAttached = State->GetCorrespondingClusterActor()->AttachToComponent(GetRootComponent(), AttachmentRules);
+		//State->GetCorrespondingClusterActor()->OnAttached();
+		UE_LOGFMT(Toolkit, Display, "ARWTHVRPawn: Attaching corresponding cluster actor to our pawn returned: {Attached}", bAttached);
 	}
 	else
 	{
-		UE_LOGFMT(Toolkit, Warning,
-				  "No CaveSetup Actor found which can be attached to the Pawn! This won't work on the Cave.");
+		UE_LOGFMT(Toolkit, Error,
+				  "ARWTHVRPawn::AttachClustertoPawn: No ARWTHVRPlayerState set! This won't work on the Cave.");
 	}
 
 	// if (HasAuthority()) // Should always be the case here, but double check
diff --git a/Source/RWTHVRToolkit/Public/Core/RWTHVRGameModeBase.h b/Source/RWTHVRToolkit/Public/Core/RWTHVRGameModeBase.h
index 1469ac36caa9b571b765622766a01ed103b26252..d4b933507d4049967b25c29726320e2335eec11d 100644
--- a/Source/RWTHVRToolkit/Public/Core/RWTHVRGameModeBase.h
+++ b/Source/RWTHVRToolkit/Public/Core/RWTHVRGameModeBase.h
@@ -4,6 +4,7 @@
 
 #include "CoreMinimal.h"
 #include "GameFramework/GameModeBase.h"
+#include "Pawn/ClusterRepresentationActor.h"
 #include "RWTHVRGameModeBase.generated.h"
 
 /**
@@ -15,6 +16,9 @@ UCLASS()
 class RWTHVRTOOLKIT_API ARWTHVRGameModeBase : public AGameModeBase
 {
 	GENERATED_BODY()
+public:
+	
+	ARWTHVRGameModeBase(const FObjectInitializer& ObjectInitializer);
 
 protected:
 	/**
@@ -29,4 +33,7 @@ protected:
 	 * possess. If not, spawn a DefaultPawnClass Pawn and Possess it (Should be BP_VirtualRealityPawn to make sense).
 	 */
 	virtual void PostLogin(APlayerController* NewPlayer) override;
+
+private:
+	TMap<int32, AClusterRepresentationActor> ConnectedClusters;
 };
diff --git a/Source/RWTHVRToolkit/Public/Core/RWTHVRPlayerState.h b/Source/RWTHVRToolkit/Public/Core/RWTHVRPlayerState.h
index 4c709e204428e4cbcd20d782823676c5b8e12c7c..c5e8f46f8716d2f5d6119383affbc03a5e8030c9 100644
--- a/Source/RWTHVRToolkit/Public/Core/RWTHVRPlayerState.h
+++ b/Source/RWTHVRToolkit/Public/Core/RWTHVRPlayerState.h
@@ -7,6 +7,8 @@
 #include "GameFramework/PlayerState.h"
 #include "RWTHVRPlayerState.generated.h"
 
+
+class AClusterRepresentationActor;
 enum class EPlayerType : uint8;
 /**
  * Extension of the PlayerState that additionally holds information about what type the player is.
@@ -22,6 +24,15 @@ private:
 	UPROPERTY(Replicated, Category = PlayerState, BlueprintGetter = GetPlayerType, meta = (AllowPrivateAccess))
 	EPlayerType PlayerType = EPlayerType::Desktop;
 
+	/** Replicated cluster ID for this player. Is -1 in case player is not a cluster*/
+	UPROPERTY(Replicated, Category = PlayerState, BlueprintGetter = GetCorrespondingClusterId, meta = (AllowPrivateAccess))
+	int32 CorrespondingClusterId = -1;
+
+	/** Replicated cluster actor for this player. Is nullptr in case player is not a cluster*/
+	UPROPERTY(Replicated, Category = PlayerState, BlueprintGetter = GetCorrespondingClusterActor,
+			  meta = (AllowPrivateAccess))
+	AClusterRepresentationActor* CorrespondingClusterActor = nullptr;
+	
 	UFUNCTION(Reliable, Server)
 	void ServerSetPlayerTypeRpc(EPlayerType NewPlayerType);
 
@@ -31,6 +42,15 @@ public:
 	UFUNCTION(BlueprintGetter)
 	EPlayerType GetPlayerType() const { return PlayerType; }
 
+	UFUNCTION(BlueprintGetter)
+	int32 GetCorrespondingClusterId() const { return CorrespondingClusterId; }
+
+	UFUNCTION(BlueprintGetter)
+	AClusterRepresentationActor* GetCorrespondingClusterActor() const { return CorrespondingClusterActor; }
+	
+	void SetCorrespondingClusterId(int32 NewCorrespondingClusterId);
+	void SetCorrespondingClusterActor(AClusterRepresentationActor* NewCorrespondingClusterActor);
+
 	UFUNCTION(BlueprintCallable)
 	void RequestSetPlayerType(EPlayerType NewPlayerType);
 
diff --git a/Source/RWTHVRToolkit/Public/Pawn/ClusterRepresentationActor.h b/Source/RWTHVRToolkit/Public/Pawn/ClusterRepresentationActor.h
new file mode 100644
index 0000000000000000000000000000000000000000..1db7a420237e35cdb40cac9e35f9ea6fa7fdd5f4
--- /dev/null
+++ b/Source/RWTHVRToolkit/Public/Pawn/ClusterRepresentationActor.h
@@ -0,0 +1,29 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+
+#include "ClusterRepresentationActor.generated.h"
+
+
+class ADisplayClusterRootActor;
+UCLASS()
+class RWTHVRTOOLKIT_API AClusterRepresentationActor : public AActor
+{
+	GENERATED_BODY()
+
+public:
+	// Sets default values for this actor's properties
+	AClusterRepresentationActor();
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
+	int32 ClusterId = -1;
+
+	virtual void BeginPlay() override;
+	
+
+private:
+	bool AttachDCRA();
+	ADisplayClusterRootActor* SpawnDCRA();
+};
diff --git a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h
index 260cdc0408e5f2d1ef9d64c7f56ba4325a8ff123..cd81e497181dcfef757b067ccae8c862c022fa34 100644
--- a/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h
+++ b/Source/RWTHVRToolkit/Public/Pawn/RWTHVRPawn.h
@@ -79,10 +79,6 @@ public:
 	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Pawn|LiveLink")
 	bool bWorldTransform = false;
 
-	/* The class which to search for DCRA attachment. TODO: Make this better it's ugly */
-	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Pawn|LiveLink")
-	TSubclassOf<AActor> CaveSetupActorClass;
-
 protected:
 	virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
 	void AddInputMappingContext(const APlayerController* PC, const UInputMappingContext* Context) const;
@@ -107,8 +103,8 @@ protected:
 	UFUNCTION(Reliable, NetMulticast)
 	void MulticastAddDCSyncComponent();
 
-	/* Attaches the DCRA to the pawn */
-	void AttachDCRAtoPawn();
+	/* Attaches the Cluster representation to the pawn */
+	void AttachClustertoPawn();
 
 	/* Set device specific motion controller sources (None, L/R, Livelink) */
 	void SetupMotionControllerSources();