diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 56f8c5fef548fe0f3371728d32ac0b307c2bd58c..5ad065fd25545a384ba13b8c6b09d08bf2e10c06 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -40,8 +40,7 @@ include:
 # Use the UNREAL_VERSION variable to adjust to your preferred Unreal version.
 
 variables:
-    UNREAL_VERSION: "5.3"
-    CUSTOM_NDISPLAY_CONFIG: "aixcave_5_3_dev.ndisplay"
+    UNREAL_VERSION: "5.4"
 
 stages:
   - analyze
@@ -82,7 +81,7 @@ Generate_Project:
         RUN_SETUP: "false"
         GEN_DEPENDENCIES: "(
             [master@UnrealDTrackPlugin]='https://github.com/VRGroupRWTH/UnrealDTrackPlugin.git'
-            [dev/5.3@RWTHVRToolkit]='https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/rwth-vr-toolkit.git'
+            [dev/5.4@RWTHVRToolkit]='https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/rwth-vr-toolkit.git'
             )"
 
 Generate_Project_Without_Toolkit:
diff --git a/Content/Config/aixcave.uasset b/Content/Config/aixcave.uasset
index 65937f62a73760ab23516ebb89cda72c808f22aa..17efe4c089ee96e659eb8457edc1c6a0efdba582 100644
Binary files a/Content/Config/aixcave.uasset and b/Content/Config/aixcave.uasset differ
diff --git a/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp b/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp
index 6553ad4ea869f745d92ff95b04b258c0851dcb61..4805e433258ea8a8fd01cda88e03bf125e00a2a0 100644
--- a/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp
+++ b/Source/RWTHVRCluster/Private/CAVEOverlay/CAVEOverlayController.cpp
@@ -149,6 +149,10 @@ void ACAVEOverlayController::BeginPlay()
 	if (GetNetMode() != NM_Standalone)
 		return;
 
+	// If we're not in room-mounted mode, return as well
+	if (!URWTHVRClusterUtilities::IsRoomMountedMode())
+		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;
 
@@ -157,7 +161,7 @@ void ACAVEOverlayController::BeginPlay()
 	// Not sure which place would be best...
 	const bool bValidPC = PC && PC->GetLocalPlayer();
 
-	if (!bValidPC || !URWTHVRClusterUtilities::IsRoomMountedMode())
+	if (!bValidPC)
 		return;
 
 	// Input config
@@ -223,11 +227,33 @@ void ACAVEOverlayController::BeginPlay()
 		return;
 	}
 
+	PC->OnPossessedPawnChanged.AddUniqueDynamic(this, &ACAVEOverlayController::UpdatePossessedPawn);
+
+	// I think this breaks in multiplayer mode
+	InitFromPawn(PC->GetPawn());
+
+	// Create dynamic material for tape
+	TapeMaterialDynamic = Tape->CreateDynamicMaterialInstance(0);
+
+	UE_LOGFMT(LogCAVEOverlay, Display, "CaveOverlay Initialization was successfull.");
+}
+
+void ACAVEOverlayController::UpdatePossessedPawn(APawn* OldPawn, APawn* NewPawn) { InitFromPawn(NewPawn); }
+
+
+void ACAVEOverlayController::InitFromPawn(const APawn* CurrentPawn)
+{
+	// Clear previous properties. We could reuse the SMCs and MIDs, clearing them might be dangerous.
+	// Too much in a hurry here to make this better.
+	MotionControllers.Empty();
+	SignsStaticMeshComponents.Empty();
+	SignsMIDs.Empty();
+
 	// Get the pawn so we can have access to head and hand positions
-	if (const auto* VRPawn = Cast<APawn>(PC->GetPawnOrSpectator()))
+	if (CurrentPawn)
 	{
-		PawnCamera = VRPawn->GetComponentByClass<UCameraComponent>();
-		auto FoundMotionControllers = VRPawn->K2_GetComponentsByClass(UMotionControllerComponent::StaticClass());
+		PawnCamera = CurrentPawn->GetComponentByClass<UCameraComponent>();
+		auto FoundMotionControllers = CurrentPawn->K2_GetComponentsByClass(UMotionControllerComponent::StaticClass());
 
 		for (const auto FoundMotionController : FoundMotionControllers)
 		{
@@ -261,13 +287,9 @@ void ACAVEOverlayController::BeginPlay()
 	}
 	else
 	{
+		bInitialized = false;
 		UE_LOGFMT(LogCAVEOverlay, Error, "No VirtualRealityPawn found which we could attach to!");
 	}
-
-	// Create dynamic material for tape
-	TapeMaterialDynamic = Tape->CreateDynamicMaterialInstance(0);
-
-	UE_LOGFMT(LogCAVEOverlay, Display, "CaveOverlay Initialization was successfull.");
 }
 
 void ACAVEOverlayController::EndPlay(const EEndPlayReason::Type EndPlayReason)
@@ -386,6 +408,12 @@ void ACAVEOverlayController::Tick(float DeltaTime)
 	// Hand Logic
 	for (int i = 0; i < MotionControllers.Num(); i++)
 	{
+		if (MotionControllers[i] == nullptr)
+		{
+			UE_LOGFMT(LogCAVEOverlay, Error, "Motion Controller was nullptr, disabling overlay!");
+			bInitialized = false;
+			return;
+		}
 		const FVector HandPosition = MotionControllers[i]->GetRelativeLocation();
 
 		// Set the position rotation, opacity, visibility of the hand warning signs.
diff --git a/Source/RWTHVRCluster/Private/RWTHVRCluster.cpp b/Source/RWTHVRCluster/Private/RWTHVRCluster.cpp
index 5632551f90a26458579d02705077b14faad5305c..34ed238cc69d225fefbc50c360b487d084ef2beb 100644
--- a/Source/RWTHVRCluster/Private/RWTHVRCluster.cpp
+++ b/Source/RWTHVRCluster/Private/RWTHVRCluster.cpp
@@ -1,11 +1,31 @@
 #include "RWTHVRCluster.h"
 
+
+#include "GameDelegates.h"
+#include "Logging/StructuredLog.h"
+
 #define LOCTEXT_NAMESPACE "FRWTHVRClusterModule"
 
-void FRWTHVRClusterModule::StartupModule() { ClusterConsole.Register(); }
+void FRWTHVRClusterModule::StartupModule()
+{
+	ClusterConsole.Register();
+
+	FGameDelegates::Get().GetModifyCookDelegate().AddRaw(this, &FRWTHVRClusterModule::GetPackagesToAlwaysCook);
+}
 
 void FRWTHVRClusterModule::ShutdownModule() { ClusterConsole.Unregister(); }
 
+void FRWTHVRClusterModule::GetPackagesToAlwaysCook(TConstArrayView<const ITargetPlatform*> InTargetPlatforms,
+												   TArray<FName>& InOutPackagesToCook,
+												   TArray<FName>& InOutPackagesToNeverCook)
+{
+	InOutPackagesToCook.Add("/RWTHVRCluster/Config/aixcave");
+	InOutPackagesToCook.Add("/RWTHVRCluster/Config/aixcave_two_player");
+
+	UE_LOGFMT(LogTemp, Display,
+			  "GetPackagesToAlwaysCook delegate called, adding aixcave configs to always cook list...");
+}
+
 #undef LOCTEXT_NAMESPACE
 
 IMPLEMENT_MODULE(FRWTHVRClusterModule, RWTHVRCluster)
diff --git a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h b/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h
index 0e8c09fc6d0648cf98c0e917e2a4a10260feb805..c46cabc14e6a18987eb7610adce29255c4979a3e 100644
--- a/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h
+++ b/Source/RWTHVRCluster/Public/CAVEOverlay/CAVEOverlayController.h
@@ -78,6 +78,12 @@ private:
 	const float WallWarningDistance = 40; // cm, distance on which the tape turns red, measured from wall
 	float DoorCurrentOpeningWidthAbsolute = 0;
 
+	// Function that initializes things from the currently possessed pawn
+	void InitFromPawn(const APawn* CurrentPawn);
+
+	UFUNCTION()
+	void UpdatePossessedPawn(APawn* OldPawn, APawn* NewPawn);
+
 	// Helper function to create a mesh component in the constructor
 	UStaticMeshComponent* CreateMeshComponent(const FName& Name, USceneComponent* Parent);
 
diff --git a/Source/RWTHVRCluster/Public/RWTHVRCluster.h b/Source/RWTHVRCluster/Public/RWTHVRCluster.h
index 71a7693ca67b6ff50ff31fd10125e3803102b9b8..24323555721580d90e40a39e82a2a735a10d83c8 100644
--- a/Source/RWTHVRCluster/Public/RWTHVRCluster.h
+++ b/Source/RWTHVRCluster/Public/RWTHVRCluster.h
@@ -10,6 +10,9 @@ public:
 	virtual void StartupModule() override;
 	virtual void ShutdownModule() override;
 
+	void GetPackagesToAlwaysCook(TConstArrayView<const ITargetPlatform*> InTargetPlatforms,
+								 TArray<FName>& InOutPackagesToCook, TArray<FName>& InOutPackagesToNeverCook);
+
 private:
 	FClusterConsole ClusterConsole;
 };