diff --git a/CAVELaunchButton.uplugin b/CAVELaunchButton.uplugin
index a8c0f1c2f6bb2caa6d929ac143e0890159238fb2..dd743ef17ea2c4ae8d05421200e8535ee7bd8a9e 100644
--- a/CAVELaunchButton.uplugin
+++ b/CAVELaunchButton.uplugin
@@ -10,7 +10,7 @@
 	"DocsURL": "",
 	"MarketplaceURL": "",
 	"SupportURL": "",
-	"CanContainContent": false,
+	"CanContainContent": true,
 	"IsBetaVersion": false,
 	"EnabledByDefault" : true,
 	"Modules": [
diff --git a/Source/CAVELaunchButton/CAVELaunchButton.Build.cs b/Source/CAVELaunchButton/CAVELaunchButton.Build.cs
index d2803e8ec6889ee9f755c11917f09c9781945497..af52f7f3da00c1bb275a5a69f6c4b2a853ca2bec 100644
--- a/Source/CAVELaunchButton/CAVELaunchButton.Build.cs
+++ b/Source/CAVELaunchButton/CAVELaunchButton.Build.cs
@@ -42,6 +42,8 @@ public class CAVELaunchButton : ModuleRules
 				"Engine",
 				"Slate",
 				"SlateCore",
+				"Sockets",
+				"Networking"
 				// ... add private dependencies that you statically link with here ...	
 			}
 			);
diff --git a/Source/CAVELaunchButton/Private/CAVELaunchButton.cpp b/Source/CAVELaunchButton/Private/CAVELaunchButton.cpp
index 38a97e3b7192b80583b7a6db42ca34b9ed0edced..038ffc109bc307f309f9dfaa98a416fb976ee82c 100644
--- a/Source/CAVELaunchButton/Private/CAVELaunchButton.cpp
+++ b/Source/CAVELaunchButton/Private/CAVELaunchButton.cpp
@@ -1,6 +1,8 @@
 // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
 #include "CAVELaunchButton.h"
 
+#include <string>
+
 #include "CAVELaunchButtonStyle.h"
 #include "CAVELaunchButtonSettings.h"
 #include "CAVELaunchButtonCommands.h"
@@ -8,6 +10,7 @@
 #include "Framework/MultiBox/MultiBoxBuilder.h"
 #include "IPluginManager.h"
 #include "Misc/EngineVersion.h"
+#include "Networking.h"
 
 #include "LevelEditor.h"
 
@@ -58,10 +61,25 @@ if (RootWindow.IsValid()) RootWindow->Minimize();
 	const UCAVELaunchButtonSettings* Settings = GetDefault<UCAVELaunchButtonSettings>();
 
 	if (Settings->StartROLVInsteadOfCAVE) {
-		UE_LOG(LogTemp, Log, TEXT("This would launch ROLV!"));
+		
+    FString EditorExecutable = "UE4Editor.exe";
+    FString Parameters = "\"" + FPaths::GetProjectFilePath() + "\" -game -dc_cluster -nosplash -fixedseed -dx11 -dc_dev_side_by_side dc_cfg=\"" + Settings->RolvConfig.FilePath + "\" -notexturestreaming -fullscreen dc_node=node_main -log ABSLOG=" + FPaths::ProjectDir() + "\\ROLV_Launch.log";
+
+    FProcHandle VRPN;
+    ProjectorDisplayType modeFromBefore;
+    if (Settings->StartVRPN) VRPN = FPlatformProcess::CreateProc(*Settings->VRPNPath.FilePath, *FString("-f \"" + Settings->VRPNConfigPath.FilePath + "\" -millisleep 0"), false, false, false, NULL, 0, NULL, NULL);
+    if (Settings->StartDTrack) SendToDTrack(Settings->DTrackIP, Settings->DTrackPort, "dtrack2 tracking start\0");
+    if (Settings->SwitchBeamer) modeFromBefore = SwitchBeamerToState(Settings->BeamerIP, Settings->BeamerPort, Settings->BeamerType);
+
+    FProcHandle instance = FPlatformProcess::CreateProc(*EditorExecutable, *(Parameters + " " + Settings->AdditionalParameters), true, false, false, NULL, 0, NULL, NULL);
+    FPlatformProcess::WaitForProc(instance);
+
+    if (Settings->StartVRPN) FPlatformProcess::TerminateProc(VRPN);  FPlatformProcess::CloseProc(VRPN);
+    if (Settings->StartDTrack) SendToDTrack(Settings->DTrackIP, Settings->DTrackPort, "dtrack2 tracking stop\0");
+    if (Settings->SwitchBeamer && modeFromBefore != DisplayType_Error) SwitchBeamerToState(Settings->BeamerIP, Settings->BeamerPort, modeFromBefore);
 	} else {
 		FString Config = IPluginManager::Get().FindPlugin("CAVELaunchButton")->GetBaseDir() + "/LaunchConfig/minicave.cfg";
-		FString EditorExecutable = "UE4Editor.exe"; //FPaths::ConvertRelativePathToFull(FPaths::EngineDir()) + "/Binaries/Win64/UE4Editor.exe";
+		FString EditorExecutable = "UE4Editor.exe";
 		FString Parameters = "\"" + FPaths::GetProjectFilePath() + "\" -game -windowed -fixedseed -notexturestreaming -opengl4 dc_cfg=\"" + Config + "\" -dc_cluster -dc_dev_mono";
 
 		const int num_nodes = 5;
@@ -88,6 +106,90 @@ if (RootWindow.IsValid()) RootWindow->Minimize();
 	if (RootWindow.IsValid()) RootWindow->Maximize();
 }
 
+FSocket* openSocket(FString address, int port, FString socketName) {
+  FIPv4Address parsedAddress;
+  if (!FIPv4Address::Parse(address, parsedAddress)) {
+    UE_LOG(LogTemp, Error, TEXT("Could not parse Address %s"), *address);
+    return NULL;
+  }
+
+  FIPv4Endpoint endpoint(parsedAddress, port);
+  FSocket* socket = FTcpSocketBuilder(*socketName);
+  if (!socket->Connect(endpoint.ToInternetAddr().Get()))
+  {
+    UE_LOG(LogTemp, Error, TEXT("Error connecting to server %s:%d via %s"), *address, port, *socketName);
+    socket->Close();
+    return NULL;
+  }
+  return socket;
+}
+
+int32 sendSocket(FSocket* socket, FString message) {
+  socket->Wait(ESocketWaitConditions::WaitForWrite, FTimespan::FromSeconds(5));
+  std::string buffer = std::string(TCHAR_TO_UTF8(*message));
+  int32 sent = 0;
+  if (!socket->Send((const uint8 *)buffer.c_str(), buffer.length(), sent))
+  {
+    UE_LOG(LogTemp, Error, TEXT("Error sending via %s. Sent %d bytes"), *socket->GetDescription() , sent);
+    socket->Close();
+  }
+  return sent;
+}
+
+template<int32 bufferSize> FString receiveSocket(FSocket* socket) {
+  socket->Wait(ESocketWaitConditions::WaitForRead, FTimespan::FromSeconds(5));
+  char receivebuffer[bufferSize];
+  int bytesReceived = 0;
+  if (!socket->Recv((uint8*)&receivebuffer, bufferSize, bytesReceived)) {
+    UE_LOG(LogTemp, Error, TEXT("No valid response from %s. Response: '%s'"), *socket->GetDescription(), *FString(std::string(receivebuffer, bytesReceived).c_str()));
+    socket->Close();
+  }
+  if (bytesReceived <= 0) return FString("");
+  return FString(std::string(receivebuffer, bytesReceived).c_str());
+}
+
+void FCAVELaunchButtonModule::SendToDTrack(FString address, int port, FString message) {
+  FSocket* socket = openSocket(address, port, "DTrackSocket");
+  if (!socket) return;
+  if (sendSocket(socket, message) <= 0) return;
+  FString response = receiveSocket<100>(socket);
+  if (response.Compare("dtrack2 ok") != 0) {
+    UE_LOG(LogTemp, Error, TEXT("DTrack Command Failed. Response: '%s'"), *response);
+  }
+  socket->Shutdown(ESocketShutdownMode::ReadWrite);
+  socket->Close();
+}
+
+//Returns old state
+ProjectorDisplayType FCAVELaunchButtonModule::SwitchBeamerToState(FString address, int port, ProjectorDisplayType state) {
+  ProjectorDisplayType modeBefore = ProjectorDisplayType::DisplayType_Error;
+  FSocket* socket = openSocket(address, port, "BeamerSocket");
+  if (!socket) return modeBefore;
+
+  //Get mode from before
+  if (sendSocket(socket, ":TDSM ?\r") <= 0) return modeBefore;
+  FString response = receiveSocket<100>(socket); //%001 TDSM 000000
+  
+  if (!response.IsEmpty()) {
+    int32 position = 0;
+    response.FindLastChar(' ', position);
+    modeBefore = (ProjectorDisplayType)FCString::Atoi(*response.RightChop(position));
+  }
+
+  if (response.IsEmpty() || sendSocket(socket, ":TDSM " + FString::FromInt(state) + "\r") <= 0) {
+    socket->Shutdown(ESocketShutdownMode::ReadWrite);
+    socket->Close();
+    return modeBefore;
+  }
+  response = receiveSocket<100>(socket);
+  if (response.EndsWith(")")) {
+    UE_LOG(LogTemp, Error, TEXT("Beamer Type Change Failed. Response: '%s'"), *response);
+  }
+  socket->Shutdown(ESocketShutdownMode::ReadWrite);
+  socket->Close();
+  return modeBefore;
+}
+
 void FCAVELaunchButtonModule::AddToolbarExtension(FToolBarBuilder& Builder)
 {
 	Builder.AddToolBarButton(FCAVELaunchButtonCommands::Get().PluginAction);
diff --git a/Source/CAVELaunchButton/Public/CAVELaunchButton.h b/Source/CAVELaunchButton/Public/CAVELaunchButton.h
index b0f7a5554557aaa53b34cd2bc998de70ccc417be..a35e554ecc2d0977e1f0fed30c3a5e89832a56f1 100644
--- a/Source/CAVELaunchButton/Public/CAVELaunchButton.h
+++ b/Source/CAVELaunchButton/Public/CAVELaunchButton.h
@@ -4,6 +4,7 @@
 
 #include "CoreMinimal.h"
 #include "Modules/ModuleManager.h"
+#include "CAVELaunchButtonSettings.h"
 
 class FToolBarBuilder;
 class FMenuBuilder;
@@ -19,10 +20,13 @@ public:
 	
 	/** This function will be bound to Command. */
 	void PluginButtonClicked();
-	
-private:
 
-	void AddToolbarExtension(FToolBarBuilder& Builder);
+  void SendToDTrack(FString address, int port, FString message);
+  ProjectorDisplayType SwitchBeamerToState(FString address, int port, ProjectorDisplayType state);
+
+private:
+  
+  void AddToolbarExtension(FToolBarBuilder& Builder);
 	
 private:
 	TSharedPtr<class FUICommandList> PluginCommands;
diff --git a/Source/CAVELaunchButton/Public/CAVELaunchButtonSettings.h b/Source/CAVELaunchButton/Public/CAVELaunchButtonSettings.h
index 632c66375cc9e99249ada8ef9599b9d25422c55c..7525296d8806938f891d692ed5a56d15ce21f81a 100644
--- a/Source/CAVELaunchButton/Public/CAVELaunchButtonSettings.h
+++ b/Source/CAVELaunchButton/Public/CAVELaunchButtonSettings.h
@@ -3,18 +3,54 @@
 #include "Engine/DeveloperSettings.h"
 #include "CAVELaunchButtonSettings.generated.h"
 
+UENUM(BlueprintType)
+enum ProjectorDisplayType
+{
+  DisplayType_Off = 0,
+  DisplayType_Frame_Sequential = 1,
+  DisplayType_Side_By_Side = 2,
+  DisplayType_DualHead = 3,
+  DisplayType_Error = 4 UMETA(Hidden)
+};
+
 UCLASS(config=Engine, defaultconfig, meta=(DisplayName="nDisplay Launch Button"))
 class UCAVELaunchButtonSettings : public UDeveloperSettings
 {
     GENERATED_BODY()
 public:
     
-    UPROPERTY(EditAnywhere, config, Category = LaunchParametersWindows)
+  UPROPERTY(EditAnywhere, config, Category = LaunchParametersWindows)
 	FString AdditionalParameters = "";
 
 	UPROPERTY(EditAnywhere, config, Category = LaunchParametersWindows)
 	FString AdditionalParametersMaster = "";
 
-	UPROPERTY(EditAnywhere, config, Category = Platform, meta = (ConfigRestartRequired = true))
+	UPROPERTY(EditAnywhere, config, Category = ROLV, meta = (ConfigRestartRequired = true))
 	bool StartROLVInsteadOfCAVE = false;
+
+  UPROPERTY(EditAnywhere, config, Category = ROLV)
+  FFilePath RolvConfig;
+
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|Beamer")
+  bool SwitchBeamer = true;
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|Beamer", meta = (EditCondition = "SwitchBeamer"))
+  TEnumAsByte<ProjectorDisplayType> BeamerType;
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|Beamer", meta = (EditCondition = "SwitchBeamer"))
+  FString BeamerIP;
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|Beamer", meta = (EditCondition = "SwitchBeamer"))
+  int BeamerPort = 1025;
+
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|VRPN")
+  bool StartVRPN = true;
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|VRPN", meta = (EditCondition = "StartVRPN"))
+  FFilePath VRPNPath;
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|VRPN", meta = (EditCondition = "StartVRPN"))
+  FFilePath VRPNConfigPath;
+
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|DTRACK")
+  bool StartDTrack = true;
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|DTRACK", meta= (EditCondition = "StartDTrack"))
+  FString DTrackIP;
+  UPROPERTY(EditAnywhere, config, Category = "ROLV|DTRACK", meta = (EditCondition = "StartDTrack"))
+  int DTrackPort = 50105;
 };