// Fill out your copyright notice in the Description page of Project Settings. // what's up? #include "VAReceiverActor.h" #include "VAPlugin.h" #include "VAUtils.h" #include "VADefines.h" #include "SoundSource/VAAbstractSourceComponent.h" #include "ImageSourceModel/VAReflectionWall.h" #include "Directivity/VADirectivityManager.h" #include "HRIR/VAHRIRManager.h" #include "Cluster/DisplayClusterClusterEvent.h" #include "Engine/World.h" // World #include "GameFramework/PlayerController.h" // Viewport #include "IDisplayCluster.h" // For Events #include "Pawn/VirtualRealityPawn.h" // VR Pawn #include "Kismet/GameplayStatics.h" // Get Actors of class #include "Utility/VirtualRealityUtilities.h" // ****************************************************************** // // ******* Initialization Functions ********************************* // // ****************************************************************** // AVAReceiverActor::AVAReceiverActor() { PrimaryActorTick.bCanEverTick = true; DirManager = MakeShared<FVADirectivityManager>(); HRIRManager = MakeShared<FVAHRIRManager>(); AuralizationModeController = CreateDefaultSubobject<UVAAuralizationModeController>(TEXT("AuralizationModeController")); } void AVAReceiverActor::BeginPlay() { Super::BeginPlay(); FVAPlugin::SetReceiverActor(this); // Cluster Stuff for Events // RunOnAllNodesEvent.Attach(this); // CurrentReceiverActor = this; if(bReconnecToVAServer && UVirtualRealityUtilities::IsMaster() && FVAPlugin::IsConnected()) { //this might be needed if different server version should be started between levels FVAPlugin::DisconnectServer(); } //try to start (remote) VAServer automatically bool bStartedVAServer = false; if (bAutomaticRemoteVAStart) { FVAPlugin::VAServerLauncher.StartVAServerLauncher(); //if possible bStartedVAServer = FVAPlugin::VAServerLauncher.RemoteStartVAServer(GetIPAddress(), RemoteVAStarterPort, WhichVAServerVersionToStart); if(bStartedVAServer){ FVAPlugin::SetUseVA(true); } } // Ask if used or not FVAPlugin::AskForSettings(GetIPAddress(), GetPort(), bAskForDebugMode, !bStartedVAServer); if (UVirtualRealityUtilities::IsMaster()) { if (FVAPlugin::GetUseVA()) { RunOnAllNodes("useVA = true"); } else { RunOnAllNodes("useVA = false"); return; } } bWallsInitialized = false; TimeSinceUpdate = 0.0f; TotalTime = 0.0f; if (!FVAPlugin::GetUseVA()) { return; } if (UVirtualRealityUtilities::IsMaster()) { FVAPlugin::SetScale(WorldScale); if (!FVAPlugin::IsConnected()) { FVAPlugin::ConnectServer(GetIPAddress(), GetPort()); } else { FVAPlugin::ResetServer(); } if (AuralizationModeController) { AuralizationModeController->Initialize(); } // Initialize the dirManager DirManager->ResetManager(); if (bReadInitialMappingFile) { DirManager->ReadConfigFile(DirMappingFileName); } // Initialize the HRIRManager HRIRManager->ResetManager(); // Initialize Receiver Actor ReceiverID = FVAPlugin::CreateNewSoundReceiver(this); if (FVAHRIRManager::GetDefaultHRIR().IsValid() && VA::IsValidID( FVAHRIRManager::GetDefaultHRIR()->GetID() )) { CurrentHRIR = FVAHRIRManager::GetDefaultHRIR(); } } // Initialize Walls for Sound Reflection if (!bWallsInitialized) { InitializeWalls(); } // Handle all sound Sources TArray<AActor*> ActorsA; UGameplayStatics::GetAllActorsOfClass(this->GetWorld(), AActor::StaticClass(), ActorsA); for (AActor* Actor : ActorsA) { TArray<UVAAbstractSourceComponent*> VASourceComponents; Actor->GetComponents(VASourceComponents); for (UVAAbstractSourceComponent* SourceComponent : VASourceComponents) { SourceComponent->Initialize(); } } if (UVirtualRealityUtilities::IsMaster()) { if (FVAPlugin::GetDebugMode()) { RunOnAllNodes("debugMode = true"); } else { RunOnAllNodes("debugMode = false"); } } bInitialized = true; } void AVAReceiverActor::EndPlay(const EEndPlayReason::Type EndPlayReason) { RunOnAllNodesEvent.Detach(); if(!FVAPlugin::GetWasStarted()) { return; } FVAPlugin::ResetServer(); DirManager->ResetManager(); HRIRManager->ResetManager(); Super::EndPlay(EndPlayReason); } void AVAReceiverActor::InitializeWalls() { TArray<AActor*> WallsA; UGameplayStatics::GetAllActorsOfClass(this->GetWorld(), AVAReflectionWall::StaticClass(), WallsA); for (AActor* EntryWalls : WallsA) { ReflectionWalls.Add(static_cast<AVAReflectionWall*>(EntryWalls)); } bWallsInitialized = true; } void AVAReceiverActor::SetUpdateRate(const int Rate) { UpdateRate = Rate; } // ****************************************************************** // // ******* Tick Function ******************************************** // // ****************************************************************** // void AVAReceiverActor::Tick(const float DeltaTime) { Super::Tick(DeltaTime); if (!FVAPlugin::GetUseVA() || !UVirtualRealityUtilities::IsMaster()) { return; } if (!bInitialized) { FVAUtils::OpenMessageBox("[AVAReceiverActor::Tick()]: Receiver Actor is not initialized", true); } TimeSinceUpdate += DeltaTime; TotalTime += DeltaTime; if (TimeSinceUpdate > (1.0f / float(UpdateRate))) { UpdateVirtualWorldPose(); UpdateRealWorldPose(); TimeSinceUpdate = 0.0f; } } // ****************************************************************** // // ******* Position updates ***************************************** // // ****************************************************************** // bool AVAReceiverActor::SetManualReceiverData(FVector VirtualPos, FRotator VirtualRot, FVector RealWorldPos /*= FVector(0, 0, 0)*/, FRotator RealWorldRot /*= FRotator(0, 0, 0)*/) { if (TrackingSource != ETrackingSource::ManualData) { FVAUtils::LogStuff("[AVAReceiverActor::SetManualReceiverData()]: SetManualReceiverData() called, but TrackingSource != ManualData", true); return false; } const FVector HeadCenterPosition = VirtualPos + VirtualRot.RotateVector(ViewpointToHeadcenterOffset); bool bResult = true; //Update VirtualWorldPose bResult &= FVAPlugin::SetSoundReceiverPosition(ReceiverID, HeadCenterPosition); bResult &= FVAPlugin::SetSoundReceiverRotation(ReceiverID, VirtualRot); //Update RealWorldPose bResult &= FVAPlugin::SetSoundReceiverRealWorldPose(ReceiverID, RealWorldPos, RealWorldRot); return bResult; } bool AVAReceiverActor::UpdateVirtualWorldPose() { if(TrackingSource == ETrackingSource::VirtualRealityPawn) { // Auralization Pose is coppled to the Virtual Reality Pawn, e.g, HMD, CAVE FVector ViewPos; FRotator ViewRot; GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(ViewPos, ViewRot); bool bResult = true; bResult &= FVAPlugin::SetSoundReceiverPosition(ReceiverID, ViewPos + ViewRot.RotateVector(ViewpointToHeadcenterOffset)); //Offset from ViewPoint (between eyes) to head center, rotate according to view rotation bResult &= FVAPlugin::SetSoundReceiverRotation(ReceiverID, ViewRot); return bResult; } return false; } bool AVAReceiverActor::UpdateRealWorldPose() { if (TrackingSource==ETrackingSource::VirtualRealityPawn) { if (!UVirtualRealityUtilities::IsMaster() || !FVAPlugin::GetUseVA()) { return false; } if (GetWorld() == nullptr) { return false; } APlayerController* PlayerController = GetWorld()->GetFirstPlayerController(); if (PlayerController == nullptr) { return false; } AVirtualRealityPawn* VirtualRealityPawn = Cast<AVirtualRealityPawn>(PlayerController->AcknowledgedPawn); if (VirtualRealityPawn == nullptr) { return false; } USceneComponent* Head = VirtualRealityPawn->Head; if (!Head) { return false; } // calculate positions const FQuat InverseOriginRot = VirtualRealityPawn->GetActorQuat().Inverse(); //Inverse Quaternion of Actor in Virtual World const FVector HeadCenter = Head->GetComponentLocation() + Head->GetComponentRotation().RotateVector(ViewpointToHeadcenterOffset); //Location of Head Center in Virtual World const FVector Pos = InverseOriginRot.RotateVector( HeadCenter - VirtualRealityPawn->GetActorLocation()); //Get position by subtraction virtual origin const FQuat Quat = InverseOriginRot * Head->GetComponentQuat(); return FVAPlugin::SetSoundReceiverRealWorldPose(ReceiverID, Pos, Quat.Rotator()); } return false; } // ****************************************************************** // // ******* Directivity / HRIR Handling ****************************** // // ****************************************************************** // TSharedPtr<FVADirectivity> AVAReceiverActor::GetDirectivityByMapping(const FString Phoneme) const { return DirManager->GetDirectivityByPhoneme(Phoneme); } TSharedPtr<FVADirectivity> AVAReceiverActor::GetDirectivityByFileName(const FString FileName) { return DirManager->GetDirectivityByFileName(FileName); } bool AVAReceiverActor::ReadDirMappingFile(const FString FileName) { if (DirManager->GetFileName() == FileName) { FVAUtils::LogStuff("[AVAReceiverActor::ReadDirMappingFile()]: file already loaded", false); return false; } DirMappingFileName = FileName; DirManager->ResetManager(); return DirManager->ReadConfigFile(DirMappingFileName); } bool AVAReceiverActor::SetHRIRByFileName(const FString FileName) { TSharedPtr<FVAHRIR> NewHRIR = HRIRManager->GetHRIRByFileName(FileName); if (!NewHRIR.IsValid()) { return false; } if(CurrentHRIR.IsValid() && NewHRIR->GetID() == CurrentHRIR->GetID()) { return true; } if (FVAPlugin::SetSoundReceiverHRIR(ReceiverID, NewHRIR->GetID())) { CurrentHRIR = NewHRIR; return true; } return false; } // ****************************************************************** // // ******* Getter Functions ***************************************** // // ****************************************************************** // bool AVAReceiverActor::IsInitialized() const { return bInitialized; } float AVAReceiverActor::GetScale() const { return WorldScale; } FString AVAReceiverActor::GetIPAddress() const { switch (AddressSetting) { case EConnectionSetting::Automatic: #if PLATFORM_WINDOWS return FString("127.0.0.1"); #else return FString("10.0.1.240"); #endif break; case EConnectionSetting::Cave: return FString("10.0.1.240"); break; case EConnectionSetting::Localhost: return FString("127.0.0.1"); break; case EConnectionSetting::Manual: return ServerIPAddress; break; default: break; } FVAUtils::LogStuff("[AVAReceiverActor::GetIPAddress()]: Unreachable Error", true); return FString("127.0.0.1"); } int AVAReceiverActor::GetPort() const { switch (AddressSetting) { case EConnectionSetting::Automatic: case EConnectionSetting::Cave: case EConnectionSetting::Localhost: return 12340; break; case EConnectionSetting::Manual: return ServerPort; break; default: break; } FVAUtils::LogStuff("[AVAReceiverActor::GetPort()]: Unreachable Error", true); return -1; } UVAAuralizationModeController* AVAReceiverActor::GetAuralizationModeController() const { return AuralizationModeController; } int AVAReceiverActor::GetReceiverID() const { return ReceiverID; } int AVAReceiverActor::GetUpdateRate() const { return UpdateRate; } TArray<AVAReflectionWall*> AVAReceiverActor::GetReflectionWalls() { if (!bWallsInitialized) { InitializeWalls(); } return ReflectionWalls; } // ****************************************************************** // // ******* Cluster Stuff ******************************************** // // ****************************************************************** // void AVAReceiverActor::SetDebugMode(const bool bDebugMode) { if (bDebugMode) { RunOnAllNodes("debugMode = true"); } else { RunOnAllNodes("debugMode = false"); } } void AVAReceiverActor::RunOnAllNodes(FString Command) { FVAUtils::LogStuff("[AVAReceiverActor::RunOnAllNodes()]: Cluster Command " + Command + " received", false); if (Command == "useVA = true") { FVAPlugin::SetUseVA(true); } else if (Command == "useVA = false") { FVAPlugin::SetUseVA(false); } else if (Command == "debugMode = true") { FVAPlugin::SetDebugMode(true); } else if (Command == "debugMode = false") { FVAPlugin::SetDebugMode(false); } else { FVAUtils::LogStuff("[AVAReceiverActor::RunOnAllNodes()]: Cluster Command " + Command + " could not be evaluated.", true); } } // ****************************************************************** // // ******* Blueprint Settings *************************************** // // ****************************************************************** // #if WITH_EDITOR bool AVAReceiverActor::CanEditChange(const FProperty* InProperty) const { // Check manual Address if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, ServerIPAddress) || InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, ServerPort)) { return AddressSetting == EConnectionSetting::Manual; } if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(AVAReceiverActor, DirMappingFileName)) { return bReadInitialMappingFile; } return true; } #endif