Android build settings + metaxr

This commit is contained in:
2025-05-14 14:00:02 +03:00
parent 6a2bb7475e
commit d5aa21f55c
594 changed files with 200530 additions and 2 deletions

View File

@@ -0,0 +1,56 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class OculusXREditor : ModuleRules
{
public OculusXREditor(ReadOnlyTargetRules Target) : base(Target)
{
bUseUnity = true;
PrivateDependencyModuleNames.AddRange(
new string[] {
"Projects",
"InputCore",
"UnrealEd",
"LevelEditor",
"PropertyEditor",
"CoreUObject",
"Engine",
"EngineSettings",
"AndroidRuntimeSettings",
"Slate",
"SlateCore",
"EditorStyle",
"Core",
"OculusXRHMD",
"OculusXRMovement",
"OculusXRPassthrough",
"OVRPluginXR",
"OculusXRProjectSetupTool",
"HTTP",
"DesktopPlatform",
"LauncherServices",
"GameProjectGeneration",
"SharedSettingsWidgets",
"RHI",
"SourceControl",
}
);
PrivateIncludePaths.AddRange(
new string[] {
// Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source
"OculusXREditor/Private",
"OculusXRHMD/Private",
"OculusXRProjectSetupTool/Private"
});
PrivateIncludePathModuleNames.AddRange(
new string[] {
"Settings",
"OculusXRProjectSetupTool"
});
}
}

View File

@@ -0,0 +1,328 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXRBuildAnalytics.h"
#include "GameProjectGenerationModule.h"
#include "OculusXRHMDModule.h"
#include "OculusXRHMDRuntimeSettings.h"
#include "OculusXRTelemetryPrivacySettings.h"
#include "Runtime/Core/Public/HAL/FileManager.h"
FOculusBuildAnalytics* FOculusBuildAnalytics::instance = 0;
FOculusBuildAnalytics* FOculusBuildAnalytics::GetInstance()
{
if (IOculusXRHMDModule::IsAvailable())
{
if (instance == nullptr)
{
instance = new FOculusBuildAnalytics();
}
}
return instance;
}
bool FOculusBuildAnalytics::IsOculusXRHMDAvailable()
{
return IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::Get().PreInit();
}
void FOculusBuildAnalytics::Shutdown()
{
}
FOculusBuildAnalytics::FOculusBuildAnalytics()
{
bool TelemetryEnabled = false;
if (const auto EditorPrivacySettings = GetDefault<UOculusXRTelemetryPrivacySettings>())
{
TelemetryEnabled = EditorPrivacySettings->bIsEnabled;
}
if (TelemetryEnabled)
{
RegisterLauncherCallback();
}
}
void FOculusBuildAnalytics::OnTelemetryToggled(bool Enabled)
{
if (Enabled)
{
RegisterLauncherCallback();
}
else
{
if (LauncherCallbackHandle.IsValid())
{
ILauncherServicesModule& ProjectLauncherServicesModule = FModuleManager::LoadModuleChecked<ILauncherServicesModule>("LauncherServices");
ProjectLauncherServicesModule.OnCreateLauncherDelegate.Remove(LauncherCallbackHandle);
}
}
}
void FOculusBuildAnalytics::RegisterLauncherCallback()
{
ILauncherServicesModule& ProjectLauncherServicesModule = FModuleManager::LoadModuleChecked<ILauncherServicesModule>("LauncherServices");
LauncherCallbackHandle = ProjectLauncherServicesModule.OnCreateLauncherDelegate.AddRaw(this, &FOculusBuildAnalytics::OnLauncherCreated);
}
void FOculusBuildAnalytics::OnLauncherCreated(ILauncherRef Launcher)
{
// Add callback for when launcher worker is started
Launcher->FLauncherWorkerStartedDelegate.AddRaw(this, &FOculusBuildAnalytics::OnLauncherWorkerStarted);
}
void FOculusBuildAnalytics::OnLauncherWorkerStarted(ILauncherWorkerPtr LauncherWorker, ILauncherProfileRef Profile)
{
bool isUsingIterativeCotf = GetMutableDefault<UOculusXRHMDRuntimeSettings>()->bIterativeCookOnTheFly;
FOculusXRHMDModule::GetPluginWrapper().SetDeveloperMode(true);
FOculusXRHMDModule::GetPluginWrapper().SendEvent2(
"build_start_is_iterative_cotf", isUsingIterativeCotf ? "1" : "0", "ovrbuild");
TArray<FString> Platforms = Profile.Get().GetCookedPlatforms();
if (Platforms.Num() == 1)
{
if (Platforms[0].Equals("Android_ASTC") || Platforms[0].Contains("Windows"))
{
CurrentBuildStage = UNDEFINED_STAGE;
AndroidPackageTime = 0;
UATLaunched = false;
BuildCompleted = false;
CurrentBuildPlatform = Platforms[0];
TotalBuildTime = 0;
BuildStepCount = 0;
OutputDirectory = Profile.Get().GetPackageDirectory();
// Assign callbacks for stages
LauncherWorker.Get()->OnStageCompleted().AddRaw(this, &FOculusBuildAnalytics::OnStageCompleted);
LauncherWorker.Get()->OnOutputReceived().AddRaw(this, &FOculusBuildAnalytics::OnBuildOutputReceived);
LauncherWorker.Get()->OnStageStarted().AddRaw(this, &FOculusBuildAnalytics::OnStageStarted);
LauncherWorker.Get()->OnCompleted().AddRaw(this, &FOculusBuildAnalytics::OnCompleted);
// Get information on what oculus platform we are building for and also the OS platform
FString OculusPlatform;
if (CurrentBuildPlatform.Equals("Android_ASTC"))
{
UEnum* OculusMobileDevices = StaticEnum<EOculusMobileDevice::Type>();
UAndroidRuntimeSettings* Settings = GetMutableDefault<UAndroidRuntimeSettings>();
TArray<TEnumAsByte<EOculusMobileDevice::Type>> TargetOculusDevices = Settings->PackageForOculusMobile;
TArray<FString> Devices;
if (TargetOculusDevices.Contains(EOculusMobileDevice::Quest2))
{
Devices.Add("quest2");
}
OculusPlatform = FString::Join(Devices, TEXT("_"));
}
else if (CurrentBuildPlatform.Contains("Windows"))
{
CurrentBuildPlatform = "Windows";
OculusPlatform = "rift";
}
// Count user asset files
UserAssetCount = 0;
TArray<FString> FileNames;
IFileManager::Get().FindFilesRecursive(FileNames, *FPaths::ProjectContentDir(), TEXT("*.*"), true, false, false);
UserAssetCount = FileNames.Num();
// Count user script files
FGameProjectGenerationModule& GameProjectModule = FModuleManager::LoadModuleChecked<FGameProjectGenerationModule>(TEXT("GameProjectGeneration"));
SourceFileCount = 0;
SourceFileDirectorySize = 0;
GameProjectModule.Get().GetProjectSourceDirectoryInfo(SourceFileCount, SourceFileDirectorySize);
// Generate build GUID
FGuid guid = FGuid::NewGuid();
FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("build_guid", TCHAR_TO_ANSI(*guid.ToString()));
// Send build start event with corresponding metadata
FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("asset_count", TCHAR_TO_ANSI(*FString::FromInt(UserAssetCount)));
FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("script_count", TCHAR_TO_ANSI(*FString::FromInt(SourceFileCount)));
FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("target_platform", TCHAR_TO_ANSI(*CurrentBuildPlatform));
FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("target_oculus_platform", TCHAR_TO_ANSI(*OculusPlatform));
TArray<ILauncherTaskPtr> TaskList;
LauncherWorker->GetTasks(TaskList);
BuildStepCount = TaskList.Num();
}
}
}
void FOculusBuildAnalytics::OnCompleted(bool Succeeded, double TotalTime, int32 ErrorCode)
{
if (!BuildCompleted && Succeeded)
{
SendBuildCompleteEvent(TotalTime);
}
}
void FOculusBuildAnalytics::OnStageCompleted(const FString& StageName, double Time)
{
if (CurrentBuildStage != UNDEFINED_STAGE)
{
FString TaskName;
switch (CurrentBuildStage)
{
case COOK_IN_EDITOR_STAGE:
TaskName = "build_step_editor_cook";
break;
case LAUNCH_UAT_STAGE:
TaskName = "build_step_launch_uat";
break;
case COMPILE_STAGE:
TaskName = "build_step_compile";
break;
case COOK_STAGE:
TaskName = "build_step_cook";
break;
case DEPLOY_STAGE:
TaskName = "build_step_deploy";
break;
case PACKAGE_STAGE:
TaskName = "build_step_package";
break;
case RUN_STAGE:
return;
default:
TaskName = "build_step_undefined";
break;
}
if (AndroidPackageTime > 0)
{
Time -= AndroidPackageTime;
}
TotalBuildTime += Time;
FOculusXRHMDModule::GetPluginWrapper().SendEvent2(TCHAR_TO_ANSI(*TaskName), TCHAR_TO_ANSI(*FString::SanitizeFloat(Time)), "ovrbuild");
}
}
void FOculusBuildAnalytics::OnStageStarted(const FString& StageName)
{
if (StageName.Equals("Cooking in the editor"))
{
CurrentBuildStage = COOK_IN_EDITOR_STAGE;
}
else if (StageName.Equals("Build Task") && CurrentBuildStage == LAUNCH_UAT_STAGE)
{
CurrentBuildStage = COMPILE_STAGE;
}
else if (StageName.Equals("Build Task"))
{
CurrentBuildStage = LAUNCH_UAT_STAGE;
}
else if (StageName.Equals("Cook Task"))
{
CurrentBuildStage = COOK_STAGE;
}
else if (StageName.Equals("Package Task"))
{
CurrentBuildStage = PACKAGE_STAGE;
}
else if (StageName.Equals("Deploy Task"))
{
CurrentBuildStage = DEPLOY_STAGE;
}
else if (StageName.Equals("Run Task"))
{
CurrentBuildStage = RUN_STAGE;
SendBuildCompleteEvent(TotalBuildTime);
BuildCompleted = true;
}
else
{
CurrentBuildStage = UNDEFINED_STAGE;
}
}
void FOculusBuildAnalytics::OnBuildOutputReceived(const FString& Message)
{
if (CurrentBuildPlatform.Equals("Android_ASTC") && (CurrentBuildStage == DEPLOY_STAGE || CurrentBuildStage == PACKAGE_STAGE))
{
if (Message.Contains("BUILD SUCCESSFUL"))
{
FString Text, Time;
Message.Split("in", &Text, &Time);
if (!Time.IsEmpty())
{
FString SMinutes, SSeconds;
if (Time.Contains("m"))
{
Time.Split("m", &SMinutes, &SSeconds);
}
else
{
SSeconds = Time;
}
int Minutes = FCString::Atoi(*SMinutes);
int Seconds = FCString::Atoi(*SSeconds);
AndroidPackageTime = Minutes * 60 + Seconds;
FOculusXRHMDModule::GetPluginWrapper().SendEvent2("build_step_gradle_build", TCHAR_TO_ANSI(*FString::SanitizeFloat(AndroidPackageTime)), "ovrbuild");
}
}
}
}
void FOculusBuildAnalytics::SendBuildCompleteEvent(float TotalTime)
{
if (CurrentBuildPlatform.Equals("Android_ASTC"))
{
int64 APKTotalSize = 0;
TArray<FString> FoundAPKs;
OutputDirectory = FPaths::ProjectDir() + "Binaries/Android";
OutputDirectory = FPaths::ConvertRelativePathToFull(OutputDirectory);
IFileManager::Get().FindFiles(FoundAPKs, *FPaths::Combine(OutputDirectory, TEXT("*.apk")), true, false);
FDateTime LatestTime = FDateTime(0);
FString LatestAPK;
for (int i = 0; i < FoundAPKs.Num(); i++)
{
FDateTime APKCreationTime = IFileManager::Get().GetTimeStamp(*FPaths::Combine(OutputDirectory, FoundAPKs[i]));
if (APKCreationTime > LatestTime)
{
LatestTime = APKCreationTime;
LatestAPK = FoundAPKs[i];
}
}
TArray<FString> FoundOBBs;
LatestTime = FDateTime(0);
FString LatestOBB;
IFileManager::Get().FindFiles(FoundOBBs, *FPaths::Combine(OutputDirectory, TEXT("*.obb")), true, false);
for (int i = 0; i < FoundOBBs.Num(); i++)
{
FDateTime OBBCreationTime = IFileManager::Get().GetTimeStamp(*FPaths::Combine(OutputDirectory, FoundOBBs[i]));
if (OBBCreationTime > LatestTime)
{
LatestTime = OBBCreationTime;
LatestOBB = FoundOBBs[i];
}
}
if (!LatestAPK.IsEmpty())
{
APKTotalSize += IFileManager::Get().FileSize(*FPaths::Combine(OutputDirectory, LatestAPK));
}
if (!LatestOBB.IsEmpty())
{
APKTotalSize += IFileManager::Get().FileSize(*FPaths::Combine(OutputDirectory, LatestOBB));
}
if (APKTotalSize > 0)
{
FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("build_output_size", TCHAR_TO_ANSI(*FString::FromInt(APKTotalSize)));
}
}
FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("build_step_count", TCHAR_TO_ANSI(*FString::FromInt(BuildStepCount)));
FOculusXRHMDModule::GetPluginWrapper().SendEvent2("build_complete", TCHAR_TO_ANSI(*FString::SanitizeFloat(TotalTime)), "ovrbuild");
}

View File

@@ -0,0 +1,62 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ILauncherServicesModule.h"
#include "ILauncher.h"
#include "Modules/ModuleManager.h"
#include "UObject/Class.h"
#include "AndroidRuntimeSettings.h"
#include "OculusXRPluginWrapper.h"
enum EBuildStage
{
UNDEFINED_STAGE,
COOK_IN_EDITOR_STAGE,
COOK_STAGE,
LAUNCH_UAT_STAGE,
COMPILE_STAGE,
PACKAGE_STAGE,
DEPLOY_STAGE,
RUN_STAGE,
};
class FOculusBuildAnalytics
{
public:
static FOculusBuildAnalytics* GetInstance();
static void Shutdown();
static bool IsOculusXRHMDAvailable();
void RegisterLauncherCallback();
void OnTelemetryToggled(bool Enabled);
void OnLauncherCreated(ILauncherRef Launcher);
void OnLauncherWorkerStarted(ILauncherWorkerPtr LauncherWorker, ILauncherProfileRef Profile);
void OnStageCompleted(const FString& StageName, double Time);
void OnStageStarted(const FString& StageName);
void OnBuildOutputReceived(const FString& Message);
void OnCompleted(bool Succeeded, double TotalTime, int32 ErrorCode);
void SendBuildCompleteEvent(float TotalTime);
private:
FOculusBuildAnalytics();
static FOculusBuildAnalytics* instance;
FDelegateHandle LauncherCallbackHandle;
float TotalBuildTime;
float AndroidPackageTime;
bool BuildCompleted;
bool UATLaunched;
int UserAssetCount;
int BuildStepCount;
int32 SourceFileCount;
int64 SourceFileDirectorySize;
EBuildStage CurrentBuildStage;
FString CurrentBuildPlatform;
FString OutputDirectory;
};

View File

@@ -0,0 +1,624 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXREditorModule.h"
#include "AssetToolsModule.h"
#include "OculusXRToolStyle.h"
#include "OculusXRToolCommands.h"
#include "OculusXRPlatformToolWidget.h"
#include "OculusXRAssetDirectory.h"
#include "OculusXRHMDRuntimeSettings.h"
#include "IOculusXRProjectSetupModule.h"
#include "OculusXRHMDTypes.h"
#include "LevelEditor.h"
#include "Modules/ModuleManager.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/Input/SButton.h"
#include "PropertyEditorModule.h"
#include "DetailLayoutBuilder.h"
#include "DetailCategoryBuilder.h"
#include "DetailWidgetRow.h"
#include "IDetailPropertyRow.h"
#include "GeneralProjectSettings.h"
#include "IAssetTools.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "ISettingsModule.h"
#include "OculusXRPassthroughColorLutAsset.h"
#include "OculusXRHMDModule.h"
#include "OculusXRPrivacyNotification.h"
#include "OculusXRSettingsToggle.h"
#include "OculusXRTelemetryPrivacySettings.h"
#include "OculusXRTelemetry.h"
#include "OculusXRTelemetryEditorEvents.h"
#include "OculusXRBuildAnalytics.h"
#include "OculusXRPTLayerComponentDetailsCustomization.h"
#include "OculusXRPassthroughLayerComponent.h"
#include "SExternalImageReference.h"
#include "AndroidRuntimeSettings.h"
#include "SourceControlHelpers.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Interfaces/IProjectManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Editor/EditorPerformanceSettings.h"
#include "HAL/FileManager.h"
#define LOCTEXT_NAMESPACE "OculusXREditor"
const FName FOculusXREditorModule::OculusPlatToolTabName = FName("OculusXRPlaformTool");
void FOculusXREditorModule::PostLoadCallback()
{
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
}
void FOculusXREditorModule::StartupModule()
{
bModuleValid = true;
RegisterSettings();
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyModule.RegisterCustomClassLayout(UOculusXRPassthroughLayerComponent::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FOculusXRPTLayerComponentDetailsCustomization::MakeInstance));
FOculusAssetDirectory::LoadForCook();
if (!IsRunningCommandlet())
{
FOculusToolStyle::Initialize();
FOculusToolStyle::ReloadTextures();
FOculusToolCommands::Register();
PluginCommands = MakeShareable(new FUICommandList);
PluginCommands->MapAction(
FOculusToolCommands::Get().OpenProjectSetupTool,
FExecuteAction::CreateRaw(this, &FOculusXREditorModule::PluginOpenSetupToolWindow),
FCanExecuteAction());
PluginCommands->MapAction(
FOculusToolCommands::Get().OpenPlatWindow,
FExecuteAction::CreateRaw(this, &FOculusXREditorModule::PluginOpenPlatWindow),
FCanExecuteAction());
PluginCommands->MapAction(
FOculusToolCommands::Get().ToggleDeploySo,
FExecuteAction::CreateLambda([=]() {
UOculusXRHMDRuntimeSettings* settings = GetMutableDefault<UOculusXRHMDRuntimeSettings>();
settings->bDeploySoToDevice = !settings->bDeploySoToDevice;
settings->Modify(true);
settings->UpdateSinglePropertyInConfigFile(settings->GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bDeploySoToDevice)), settings->GetDefaultConfigFilename());
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([=]() {
return GetMutableDefault<UOculusXRHMDRuntimeSettings>()->bDeploySoToDevice;
}));
PluginCommands->MapAction(
FOculusToolCommands::Get().ToggleIterativeCookOnTheFly,
FExecuteAction::CreateLambda([=]() {
UOculusXRHMDRuntimeSettings* settings = GetMutableDefault<UOculusXRHMDRuntimeSettings>();
settings->bIterativeCookOnTheFly = !settings->bIterativeCookOnTheFly;
settings->Modify(true);
settings->UpdateSinglePropertyInConfigFile(settings->GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bIterativeCookOnTheFly)), settings->GetDefaultConfigFilename());
}),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([=]() {
return GetMutableDefault<UOculusXRHMDRuntimeSettings>()->bIterativeCookOnTheFly;
}));
PluginCommands->MapAction(
FOculusToolCommands::Get().ToggleMetaXRSim,
FExecuteAction::CreateRaw(this, &FOculusXREditorModule::ToggleOpenXRRuntime),
FCanExecuteAction(),
FIsActionChecked::CreateLambda([=]() {
return FOculusXRHMDModule::IsSimulatorActivated();
}));
int32 numRooms = FOculusToolCommands::Get().RoomCommands.Num();
for (int ii = 0; ii < numRooms; ++ii)
{
PluginCommands->MapAction(
FOculusToolCommands::Get().RoomCommands[ii],
FExecuteAction::CreateLambda([this, ii]() {
FOculusXREditorModule::LaunchRoom(ii);
}));
}
PluginCommands->MapAction(
FOculusToolCommands::Get().StopServer,
FExecuteAction::CreateRaw(this, &FOculusXREditorModule::StopSESServer),
FCanExecuteAction());
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
// Adds an option to launch the tool to Window->Developer Tools.
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
MenuExtender->AddMenuExtension("Miscellaneous", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FOculusXREditorModule::AddMenuExtension));
LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
// We add the Oculus menu on the toolbar
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
ToolbarExtender->AddToolBarExtension("Play", EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FOculusXREditorModule::AddToolbarExtension));
LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(OculusPlatToolTabName, FOnSpawnTab::CreateRaw(this, &FOculusXREditorModule::OnSpawnPlatToolTab)).SetDisplayName(LOCTEXT("FOculusPlatfToolTabTitle", "Meta XR Platform Tool")).SetMenuType(ETabSpawnerMenuType::Hidden);
// Register asset types
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_OculusXRPassthroughColorLut));
OculusXRTelemetry::PropagateTelemetryConsent();
// If needed, open a notification here.
OculusXRTelemetry::MaybeSpawnTelemetryConsent();
FOculusBuildAnalytics::GetInstance();
const OculusXRTelemetry::TScopedMarker<OculusXRTelemetry::Events::FEditorStart> StartEvent;
bool bProjectCreatedFromMRTemplate = false;
FProjectStatus ProjectStatus;
if (IProjectManager::Get().QueryStatusForCurrentProject(ProjectStatus))
{
bProjectCreatedFromMRTemplate = ProjectStatus.Category == "MetaMRTemplate";
}
const auto& Annotated = StartEvent.AddAnnotation("created_from_mr_template", bProjectCreatedFromMRTemplate ? "true" : "false");
// OVRPlugin may not be initialized, we need to check if it is initialized before sending the event.
if (FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
{
FOculusXRHMDModule::GetPluginWrapper().SendEvent2("editor_start", bProjectCreatedFromMRTemplate ? "created_from_mr_template" : "", "integration");
}
UEditorPerformanceSettings* EditorPerformanceSettings = GetMutableDefault<UEditorPerformanceSettings>();
if (EditorPerformanceSettings->bOverrideMaxViewportRenderingResolution)
{
UE_LOG(LogTemp, Warning, TEXT("Existing value for UEditorPerformanceSettings::MaxViewportRenderingResolution will be overriden."));
}
UE_LOG(LogTemp, Log, TEXT("MetaXR ignores max viewport resolution in editor to support full HMD resolutions."));
EditorPerformanceSettings->bOverrideMaxViewportRenderingResolution = true;
EditorPerformanceSettings->MaxViewportRenderingResolution = 0;
FPropertyChangedEvent DisabledMaxResolutionEvent(EditorPerformanceSettings->GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UEditorPerformanceSettings, MaxViewportRenderingResolution)), EPropertyChangeType::ValueSet);
EditorPerformanceSettings->PostEditChangeProperty(DisabledMaxResolutionEvent);
}
}
void FOculusXREditorModule::ShutdownModule()
{
if (!bModuleValid)
{
return;
}
if (!IsRunningCommandlet())
{
FOculusToolStyle::Shutdown();
FOculusToolCommands::Unregister();
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(OculusPlatToolTabName);
FOculusBuildAnalytics::Shutdown();
}
FOculusAssetDirectory::ReleaseAll();
if (UObjectInitialized())
{
UnregisterSettings();
}
}
TSharedRef<SDockTab> FOculusXREditorModule::OnSpawnPlatToolTab(const FSpawnTabArgs& SpawnTabArgs)
{
/* clang-format off */
auto myTab = SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
SNew(SOculusPlatformToolWidget)
];
/* clang-format on */
return myTab;
}
void FOculusXREditorModule::RegisterSettings()
{
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
SettingsModule->RegisterSettings("Project", "Plugins", "OculusXR",
LOCTEXT("RuntimeSettingsName", "Meta XR"),
LOCTEXT("RuntimeSettingsDescription", "Configure the Meta XR plugin"),
GetMutableDefault<UOculusXRHMDRuntimeSettings>());
FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyModule.RegisterCustomClassLayout(UOculusXRHMDRuntimeSettings::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FOculusXRHMDSettingsDetailsCustomization::MakeInstance));
SettingsModule->RegisterSettings("Editor", "Privacy", "OculusXR",
LOCTEXT("PrivacyTelemetrySettingsName", "MetaXR Usage Data"),
LOCTEXT("PrivacyTelemetrySettingsDescription", "Configure the way MetaXR usage information is handled."),
GetMutableDefault<UOculusXRTelemetryPrivacySettings>());
PropertyModule.RegisterCustomClassLayout(UOculusXRTelemetryPrivacySettings::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FOculusXRSettingsToggle::MakeInstance));
}
}
void FOculusXREditorModule::UnregisterSettings()
{
if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
SettingsModule->UnregisterSettings("Project", "Plugins", "OculusXR");
SettingsModule->UnregisterSettings("Editor", "Privacy", "OculusXR");
}
}
FReply FOculusXREditorModule::PluginClickFn(bool text)
{
PluginOpenSetupToolWindow();
return FReply::Handled();
}
void FOculusXREditorModule::PluginOpenSetupToolWindow()
{
IOculusXRProjectSetupToolModule::Get().ShowProjectSetupTool("Meta Menu");
}
void FOculusXREditorModule::PluginOpenPlatWindow()
{
FGlobalTabmanager::Get()->TryInvokeTab(OculusPlatToolTabName);
}
void FOculusXREditorModule::ToggleOpenXRRuntime()
{
FOculusXRHMDModule::ToggleOpenXRRuntime();
}
void FOculusXREditorModule::LaunchRoom(int32 index)
{
FOculusXRHMDModule::LaunchEnvironment(index);
}
void FOculusXREditorModule::StopSESServer()
{
FOculusXRHMDModule::StopServer();
}
void FOculusXREditorModule::AddMenuExtension(FMenuBuilder& Builder)
{
bool v = false;
GConfig->GetBool(TEXT("/Script/OculusXREditor.OculusXREditorSettings"), TEXT("bAddMenuOption"), v, GEditorIni);
if (v)
{
Builder.AddMenuEntry(FOculusToolCommands::Get().OpenProjectSetupTool);
}
}
void FOculusXREditorModule::AddToolbarExtension(FToolBarBuilder& Builder)
{
Builder.SetLabelVisibility(EVisibility::All);
Builder.AddComboButton(
FUIAction(),
FOnGetContent::CreateRaw(this, &FOculusXREditorModule::CreateToolbarEntryMenu, PluginCommands),
LOCTEXT("OculusToolsToolBarCombo", "Meta XR Tools"),
LOCTEXT("OculusToolsToolBarComboTooltip", "Meta XR tools"),
TAttribute<FSlateIcon>::CreateLambda([]() {
return FSlateIcon(FOculusToolStyle::GetStyleSetName(), "OculusTool.MenuButton");
}),
false);
Builder.AddComboButton(
FUIAction(),
FOnGetContent::CreateRaw(this, &FOculusXREditorModule::CreateXrSimToolbarEntryMenu, PluginCommands),
LOCTEXT("MetaXRSimulatorCombo", "Meta XR Simulator"),
LOCTEXT("MetaXRSimulatorComboTooltip", "Meta XR Simulator"),
TAttribute<FSlateIcon>::CreateLambda([]() {
return FSlateIcon(FOculusToolStyle::GetStyleSetName(), "OculusTool.MenuButton");
}),
false);
}
// Add the entries to the OculusXR Tools toolbar menu button
TSharedRef<SWidget> FOculusXREditorModule::CreateToolbarEntryMenu(TSharedPtr<class FUICommandList> Commands)
{
FMenuBuilder MenuBuilder(true, Commands);
MenuBuilder.BeginSection("OculusXRBuilds", LOCTEXT("OculusXRBuilds", "Builds"));
MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().ToggleDeploySo);
MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().ToggleIterativeCookOnTheFly);
MenuBuilder.EndSection();
MenuBuilder.BeginSection("OculusXRTools", LOCTEXT("OculusXRTools", "Tools"));
MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().OpenProjectSetupTool);
MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().OpenPlatWindow);
MenuBuilder.EndSection();
return MenuBuilder.MakeWidget();
}
TSharedRef<SWidget> FOculusXREditorModule::CreateXrSimToolbarEntryMenu(TSharedPtr<class FUICommandList> Commands)
{
FMenuBuilder MenuBuilder(true, Commands);
MenuBuilder.BeginSection("MetaXRSimulator", LOCTEXT("MetaXRSimulator", "Toggle"));
MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().ToggleMetaXRSim);
MenuBuilder.EndSection();
MenuBuilder.BeginSection("SES", LOCTEXT("SES", "SES"));
MenuBuilder.AddSubMenu(
LOCTEXT("Synthetic Environment Server", "Synthetic Environment Server"),
LOCTEXT("Synthetic Environment Server", "Synthetic Environment Server"),
FNewMenuDelegate::CreateRaw(this, &FOculusXREditorModule::CreateSESSubMenus));
MenuBuilder.EndSection();
return MenuBuilder.MakeWidget();
}
void FOculusXREditorModule::CreateSESSubMenus(FMenuBuilder& MenuBuilder)
{
MenuBuilder.BeginSection("Synthetic Environment Server", LOCTEXT("Synthetic Environment Server", "Synthetic Environment Server"));
for (auto room : FOculusToolCommands::Get().RoomCommands)
{
MenuBuilder.AddMenuEntry(room);
}
MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().StopServer);
MenuBuilder.EndSection();
}
FOculusXRHMDSettingsDetailsCustomization::FOculusXRHMDSettingsDetailsCustomization()
: LaunchImageLandscape(FPlatformIconInfo(TEXT("res/drawable/splashscreen_landscape.png"), LOCTEXT("SystemSplashImage", "System Splash Image"), FText::GetEmpty(), 640, 360, FPlatformIconInfo::Required))
, EngineAndroidPath(FPaths::EngineDir() + TEXT("Build/Android/Java"))
, GameAndroidPath(FPaths::ProjectDir() + TEXT("Build/Android"))
, VRSplashPath(FPaths::ProjectDir() + TEXT("Build/Android/assets/vr_splash.png"))
{
}
TSharedRef<IDetailCustomization> FOculusXRHMDSettingsDetailsCustomization::MakeInstance()
{
return MakeShareable(new FOculusXRHMDSettingsDetailsCustomization);
}
FReply FOculusXRHMDSettingsDetailsCustomization::PluginClickPerfFn(bool text)
{
IOculusXRProjectSetupToolModule::Get().ShowProjectSetupTool("Settings");
return FReply::Handled();
}
FReply FOculusXRHMDSettingsDetailsCustomization::PluginClickPlatFn(bool text)
{
FGlobalTabmanager::Get()->TryInvokeTab(FOculusXREditorModule::OculusPlatToolTabName);
return FReply::Handled();
}
FReply FOculusXRHMDSettingsDetailsCustomization::DisableEngineSplash(bool text)
{
UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault<UOculusXRHMDRuntimeSettings>();
Settings->bAutoEnabled = false;
Settings->SplashDescs.Empty();
Settings->TryUpdateDefaultConfigFile();
return FReply::Handled();
}
FReply FOculusXRHMDSettingsDetailsCustomization::AddSplashImage(bool text)
{
const FString AutomaticImagePath = EngineAndroidPath / LaunchImageLandscape.IconPath;
FText FailReason;
if (!SourceControlHelpers::CopyFileUnderSourceControl(VRSplashPath, AutomaticImagePath, LOCTEXT("ImageDescription", "image"), FailReason))
{
FNotificationInfo Info(FailReason);
Info.ExpireDuration = 3.0f;
FSlateNotificationManager::Get().AddNotification(Info);
return FReply::Unhandled();
}
return FReply::Handled();
}
void FOculusXRHMDSettingsDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailLayout)
{
static const FName WarningColorStyle("Colors.AccentYellow");
SavedLayoutBuilder = &DetailLayout;
// Labeled "General OculusXR" instead of "General" to enable searchability. The button "Launch Oculus Utilities Window" doesn't show up if you search for "Oculus"
IDetailCategoryBuilder& CategoryBuilder = DetailLayout.EditCategory("General Meta XR", FText::GetEmpty(), ECategoryPriority::Important);
/* clang-format off */
CategoryBuilder.AddCustomRow(LOCTEXT("General", "General"))
.WholeRowContent()
[
SNew(SVerticalBox)
+ SVerticalBox::Slot().AutoHeight().Padding(2)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().AutoWidth()
[
SNew(SButton)
.Text(LOCTEXT("LaunchTool", "Launch Meta XR Project Setup Tool"))
.OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::PluginClickPerfFn, true)
]
+ SHorizontalBox::Slot().FillWidth(8)
]
+ SVerticalBox::Slot().AutoHeight().Padding(2)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().AutoWidth()
[
SNew(SButton)
.Text(LOCTEXT("LaunchPlatTool", "Launch Meta XR Platform Window"))
.OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::PluginClickPlatFn, true)
]
+ SHorizontalBox::Slot().FillWidth(8)
]
];
IDetailCategoryBuilder& CTXPTCategoryBuilder = DetailLayout.EditCategory("System SplashScreen", FText::GetEmpty(), ECategoryPriority::Important);
CTXPTCategoryBuilder.AddCustomRow(LOCTEXT("CTXPTWarning", "Contextual Passthrough Warning"))
.Visibility(TAttribute<EVisibility>(this, &FOculusXRHMDSettingsDetailsCustomization::GetContextualPassthroughWarningVisibility))
[
SNew(SVerticalBox)
+ SVerticalBox::Slot().FillHeight(1.f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().FillWidth(1.f).VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(STextBlock)
.Font(IDetailLayoutBuilder::GetDetailFont())
.AutoWrapText(true)
.Justification(ETextJustify::Center)
.Text(LOCTEXT("CTXPT_EngineSplashWarning", "Engine Splash Screen is enabled, this will result in an inconsistent experience."))
.ColorAndOpacity(FAppStyle::Get().GetSlateColor(WarningColorStyle))
]
+ SHorizontalBox::Slot().FillWidth(1.f).HAlign(EHorizontalAlignment::HAlign_Left)
[
SNew(SButton)
.VAlign(EVerticalAlignment::VAlign_Center)
.Text(LOCTEXT("DisableEngineSplashScreen", "Disable Engine Splash Screen"))
.OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::DisableEngineSplash, true)
]
]
];
// Duplicate "Show Launch Image" and "Launch Landscape" properties from Android Settings
CTXPTCategoryBuilder.AddCustomRow(LOCTEXT("ShowSystemSplashImageRow", "Show System Splash Image Row"))
.NameContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(FMargin(0, 1, 0, 1))
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("ShowSystemSplashImage", "Show System Splash Image"))
.Font(DetailLayout.GetDetailFont())
.ToolTipText(LOCTEXT("ShowSystemSplashImageToolTip", "Same as \"Show Launch Image\" setting in the \"Platform > Android > Launch Images\" section. If set, the image will be presented by the Operating System at launch time"))
]
]
.ValueContent()
.MaxDesiredWidth(400.0f)
.MinDesiredWidth(100.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.VAlign(VAlign_Center)
[
SNew(SCheckBox)
.IsChecked(TAttribute<ECheckBoxState>(this, &FOculusXRHMDSettingsDetailsCustomization::GetShowLaunchImageCheckBoxState))
.OnCheckStateChanged(this, &FOculusXRHMDSettingsDetailsCustomization::OnShowLaunchImageCheckStateChanged)
]
];
const FString AutomaticImagePath = EngineAndroidPath / LaunchImageLandscape.IconPath;
const FString TargetImagePath = GameAndroidPath / LaunchImageLandscape.IconPath;
const FVector2D LaunchImageMaxSize(150.0f, 150.0f);
CTXPTCategoryBuilder.AddCustomRow(LaunchImageLandscape.IconName)
.IsEnabled(TAttribute<bool>(this, &FOculusXRHMDSettingsDetailsCustomization::IsLaunchImageEnabled))
.NameContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(FMargin(0, 1, 0, 1))
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LaunchImageLandscape.IconName)
.Font(DetailLayout.GetDetailFont())
.ToolTipText(LOCTEXT("SystemSplashImageToolTip", "Same as \"Launch Landscape\" setting in the \"Platform > Android > Launch Images\" section. This is the image that will be presented by the Operating System at launch time"))
]
]
.ValueContent()
.MaxDesiredWidth(400.0f)
.MinDesiredWidth(100.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
.VAlign(VAlign_Center)
[
SNew(SExternalImageReference, AutomaticImagePath, TargetImagePath)
.FileDescription(LaunchImageLandscape.IconDescription)
.MaxDisplaySize(LaunchImageMaxSize)
.OnPostExternalImageCopy(FOnPostExternalImageCopy::CreateSP(this, &FOculusXRHMDSettingsDetailsCustomization::OnLaunchImageChanged))
]
];
CTXPTCategoryBuilder.AddCustomRow(LOCTEXT("SystemSplashImageWarning", "System Splash Image warning"))
.Visibility(TAttribute<EVisibility>(this, &FOculusXRHMDSettingsDetailsCustomization::GetSystemSplashImageWarningVisibility))
[
SNew(SVerticalBox)
+ SVerticalBox::Slot().FillHeight(1.f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot().FillWidth(1.f).VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(STextBlock)
.Font(IDetailLayoutBuilder::GetDetailFont())
.AutoWrapText(true)
.Justification(ETextJustify::Center)
.Text(LOCTEXT("SystemSplashWarningText", "Splash Image is currently missing from project. Click button to add it."))
.ColorAndOpacity(FAppStyle::Get().GetSlateColor(WarningColorStyle))
]
+ SHorizontalBox::Slot().FillWidth(1.f).HAlign(EHorizontalAlignment::HAlign_Left)
[
SNew(SButton)
.VAlign(EVerticalAlignment::VAlign_Center)
.Text(LOCTEXT("DisableEngineSplashScreen", "Add Splash Image file to project"))
.OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::AddSplashImage, true)
]
]
];
/* clang-format on */
}
EVisibility FOculusXRHMDSettingsDetailsCustomization::GetContextualPassthroughWarningVisibility() const
{
UOculusXRHMDRuntimeSettings* OculusSettings = GetMutableDefault<UOculusXRHMDRuntimeSettings>();
return OculusSettings->SystemSplashBackground == ESystemSplashBackgroundType::Contextual && (OculusSettings->bAutoEnabled || !OculusSettings->SplashDescs.IsEmpty()) ? EVisibility::Visible : EVisibility::Collapsed;
}
ECheckBoxState FOculusXRHMDSettingsDetailsCustomization::GetShowLaunchImageCheckBoxState() const
{
UAndroidRuntimeSettings* AndroidSettings = GetMutableDefault<UAndroidRuntimeSettings>();
return AndroidSettings->bShowLaunchImage ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
}
bool FOculusXRHMDSettingsDetailsCustomization::IsLaunchImageEnabled() const
{
UAndroidRuntimeSettings* AndroidSettings = GetMutableDefault<UAndroidRuntimeSettings>();
return AndroidSettings->bShowLaunchImage;
}
void FOculusXRHMDSettingsDetailsCustomization::OnShowLaunchImageCheckStateChanged(const ECheckBoxState NewState)
{
UAndroidRuntimeSettings* AndroidSettings = GetMutableDefault<UAndroidRuntimeSettings>();
AndroidSettings->bShowLaunchImage = NewState == ECheckBoxState::Checked;
AndroidSettings->TryUpdateDefaultConfigFile();
}
bool FOculusXRHMDSettingsDetailsCustomization::OnLaunchImageChanged(const FString& InChosenImage)
{
// This will refresh the launch image located in android settings as well
SavedLayoutBuilder->ForceRefreshDetails();
FText FailReason;
if (!SourceControlHelpers::CopyFileUnderSourceControl(VRSplashPath, InChosenImage, LOCTEXT("ImageDescription", "image"), FailReason))
{
FNotificationInfo Info(FailReason);
Info.ExpireDuration = 3.0f;
FSlateNotificationManager::Get().AddNotification(Info);
return false;
}
return true;
}
EVisibility FOculusXRHMDSettingsDetailsCustomization::GetSystemSplashImageWarningVisibility() const
{
IFileManager& FileManager = IFileManager::Get();
return !FileManager.FileExists(*VRSplashPath) ? EVisibility::Visible : EVisibility::Collapsed;
}
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_MODULE(FOculusXREditorModule, OculusXREditor);
//////////////////////////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,98 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "CoreMinimal.h"
#include "IOculusXREditorModule.h"
#include "Modules/ModuleInterface.h"
#include "IDetailCustomization.h"
#include "PlatformIconInfo.h"
#include "Input/Reply.h"
#include "Layout/Visibility.h"
class FToolBarBuilder;
class FMenuBuilder;
#define OCULUS_EDITOR_MODULE_NAME "OculusXREditor"
enum class ECheckBoxState : uint8;
class FOculusXREditorModule : public IOculusXREditorModule
{
public:
FOculusXREditorModule()
: bModuleValid(false){};
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
virtual void PostLoadCallback() override;
void RegisterSettings();
void UnregisterSettings();
void PluginOpenSetupToolWindow();
FReply PluginClickFn(bool text);
void PluginOpenPlatWindow();
void ToggleOpenXRRuntime();
void CreateSESSubMenus(FMenuBuilder& MenuBuilder);
void StopSESServer();
void LaunchRoom(int32 roomIndex);
public:
static const FName OculusPlatToolTabName;
private:
void AddToolbarExtension(FToolBarBuilder& Builder);
TSharedRef<SWidget> CreateToolbarEntryMenu(TSharedPtr<class FUICommandList> Commands);
TSharedRef<SWidget> CreateXrSimToolbarEntryMenu(TSharedPtr<class FUICommandList> Commands);
void AddMenuExtension(FMenuBuilder& Builder);
TSharedRef<class SDockTab> OnSpawnPlatToolTab(const class FSpawnTabArgs& SpawnTabArgs);
private:
TSharedPtr<class FUICommandList> PluginCommands;
bool bModuleValid;
};
class IDetailLayoutBuilder;
class FOculusXRHMDSettingsDetailsCustomization : public IDetailCustomization
{
private:
FOculusXRHMDSettingsDetailsCustomization();
FPlatformIconInfo LaunchImageLandscape;
const FString EngineAndroidPath;
const FString GameAndroidPath;
const FString VRSplashPath;
IDetailLayoutBuilder* SavedLayoutBuilder;
public:
/** Makes a new instance of this detail layout class for a specific detail view requesting it */
static TSharedRef<IDetailCustomization> MakeInstance();
// IDetailCustomization interface
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override;
// End of IDetailCustomization interface
EVisibility GetContextualPassthroughWarningVisibility() const;
ECheckBoxState GetShowLaunchImageCheckBoxState() const;
bool IsLaunchImageEnabled() const;
void OnShowLaunchImageCheckStateChanged(const ECheckBoxState NewState);
bool OnLaunchImageChanged(const FString& InChosenImage);
EVisibility GetSystemSplashImageWarningVisibility() const;
FReply PluginClickPerfFn(bool text);
FReply PluginClickPlatFn(bool text);
FReply DisableEngineSplash(bool text);
FReply AddSplashImage(bool text);
};

View File

@@ -0,0 +1,9 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXREditorSettings.h"
UOculusXREditorSettings::UOculusXREditorSettings()
: PerfToolTargetPlatform(EOculusXRPlatform::PC)
{
}

View File

@@ -0,0 +1,380 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXRMovementAssetsFactories.h"
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "OculusXRLiveLinkRetargetFaceAsset.h"
#include "OculusXRLiveLinkRetargetFaceVisemesAsset.h"
#include "OculusXRLiveLinkRetargetBodyAsset.h"
#define LOCTEXT_NAMESPACE "OculusXRMovementAssetsFactories"
UOculusXRMetahumanRetargetAssetFactory::UOculusXRMetahumanRetargetAssetFactory(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
SupportedClass = UBlueprint::StaticClass();
bCreateNew = true;
bEditAfterNew = true;
}
bool UOculusXRMetahumanRetargetAssetFactory::ConfigureProperties()
{
return true;
}
uint32 UOculusXRMetahumanRetargetAssetFactory::GetMenuCategories() const
{
IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
return AssetTools.RegisterAdvancedAssetCategory("LiveLink", LOCTEXT("AssetCategoryName", "Live Link"));
}
UObject* UOculusXRMetahumanRetargetAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext)
{
UBlueprint* RetargetBlueprint = FKismetEditorUtilities::CreateBlueprint(ParentClass, InParent, Name, BlueprintType, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass(), CallingContext);
if (const TSubclassOf<UObject> GeneratedClass = RetargetBlueprint->GeneratedClass)
{
SetDefaults(GeneratedClass);
}
return RetargetBlueprint;
}
UOculusXRMetahumanFaceRetargetAssetFactory::UOculusXRMetahumanFaceRetargetAssetFactory(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
ParentClass = UOculusXRLiveLinkRetargetFaceAsset::StaticClass();
}
FText UOculusXRMetahumanFaceRetargetAssetFactory::GetDisplayName() const
{
return LOCTEXT("DisplayNameMetahumanFace", "Face retarget asset for OculusXRMovement and Metahuman");
}
void UOculusXRMetahumanFaceRetargetAssetFactory::SetDefaults(const TSubclassOf<UObject> GeneratedClass) const
{
if (UOculusXRLiveLinkRetargetFaceAsset* Retargeting = GeneratedClass->GetDefaultObject<UOculusXRLiveLinkRetargetFaceAsset>())
{
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::BrowLowererL, { "CTRL_expressions_BrowDownL", "CTRL_expressions_BrowLateralL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::BrowLowererR, { "CTRL_expressions_BrowDownR", "CTRL_expressions_BrowLateralR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekPuffL, { "CTRL_expressions_mouthCheekBlowL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekPuffR, { "CTRL_expressions_mouthCheekBlowR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekRaiserL, { "CTRL_expressions_eyeCheekRaiseL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekRaiserR, { "CTRL_expressions_eyeCheekRaiseR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekSuckL, { "CTRL_expressions_mouthCheekSuckL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekSuckR, { "CTRL_expressions_mouthCheekSuckR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::ChinRaiserB, { "CTRL_expressions_jawChinRaiseDL", "CTRL_expressions_jawChinRaiseDR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::ChinRaiserT, { "CTRL_expressions_jawChinRaiseUL", "CTRL_expressions_jawChinRaiseUR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::DimplerL, { "CTRL_expressions_mouthDimpleL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::DimplerR, { "CTRL_expressions_mouthDimpleR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesClosedL, { "CTRL_expressions_eyeBlinkL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesClosedR, { "CTRL_expressions_eyeBlinkR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookDownL, { "CTRL_expressions_eyeLookDownL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookDownR, { "CTRL_expressions_eyeLookDownR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookLeftL, { "CTRL_expressions_eyeLookLeftL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookLeftR, { "CTRL_expressions_eyeLookLeftR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookRightL, { "CTRL_expressions_eyeLookRightL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookRightR, { "CTRL_expressions_eyeLookRightR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookUpL, { "CTRL_expressions_eyeLookUpL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookUpR, { "CTRL_expressions_eyeLookUpR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::InnerBrowRaiserL, { "CTRL_expressions_browRaiseInL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::InnerBrowRaiserR, { "CTRL_expressions_browRaiseInR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawDrop, { "CTRL_expressions_jawOpen" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawSidewaysLeft, { "CTRL_expressions_jawLeft" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawSidewaysRight, { "CTRL_expressions_jawRight" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawThrust, { "CTRL_expressions_jawFwd", "CTRL_expressions_jawBack" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LidTightenerL, { "CTRL_expressions_eyeSquintInnerL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LidTightenerR, { "CTRL_expressions_eyeSquintInnerR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerDepressorL, { "CTRL_expressions_mouthCornerDepressL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerDepressorR, { "CTRL_expressions_mouthCornerDepressR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerPullerL, { "CTRL_expressions_mouthCornerPullL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerPullerR, { "CTRL_expressions_mouthCornerPullR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerLB, { "CTRL_expressions_mouthFunnelDL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerLT, { "CTRL_expressions_mouthFunnelUL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerRB, { "CTRL_expressions_mouthFunnelDR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerRT, { "CTRL_expressions_mouthFunnelUR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPressorL, { "CTRL_expressions_mouthLipsPressL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPressorR, { "CTRL_expressions_mouthLipsPressR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPuckerL, { "CTRL_expressions_mouthLipsPurseDL", "CTRL_expressions_mouthLipsPurseUL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPuckerR, { "CTRL_expressions_mouthLipsPurseDR", "CTRL_expressions_mouthLipsPurseUR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipStretcherL, { "CTRL_expressions_mouthStretchL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipStretcherR, { "CTRL_expressions_mouthStretchR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckLB, { "CTRL_expressions_mouthLowerLipBiteL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckLT, { "CTRL_expressions_mouthUpperLipBiteL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckRB, { "CTRL_expressions_mouthLowerLipBiteR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckRT, { "CTRL_expressions_mouthUpperLipBiteR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipTightenerL, { "CTRL_expressions_mouthLipsTightenDL", "CTRL_expressions_mouthLipsTightenUL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipTightenerR, { "CTRL_expressions_mouthLipsTightenDR", "CTRL_expressions_mouthLipsTightenUR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipsToward, { "CTRL_expressions_jawChinRaiseDL", "CTRL_expressions_jawChinRaiseDR", "CTRL_expressions_jawChinRaiseUL", "CTRL_expressions_jawChinRaiseUR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LowerLipDepressorL, { "CTRL_expressions_mouthLowerLipDepressL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LowerLipDepressorR, { "CTRL_expressions_mouthLowerLipDepressR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::MouthLeft, { "CTRL_expressions_mouthLeft" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::MouthRight, { "CTRL_expressions_mouthRight" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::NoseWrinklerL, { "CTRL_expressions_noseWrinkleL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::NoseWrinklerR, { "CTRL_expressions_noseWrinkleR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::OuterBrowRaiserL, { "CTRL_expressions_browRaiseOuterL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::OuterBrowRaiserR, { "CTRL_expressions_browRaiseOuterR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLidRaiserL, { "CTRL_expressions_eyeUpperLidUpL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLidRaiserR, { "CTRL_expressions_eyeUpperLidUpR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLipRaiserL, { "CTRL_expressions_mouthUpperLipRaiseL" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLipRaiserR, { "CTRL_expressions_mouthUpperLipRaiseR" });
}
}
UOculusXRFaceVisemesRetargetAssetFactory::UOculusXRFaceVisemesRetargetAssetFactory(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
ParentClass = UOculusXRLiveLinkRetargetFaceVisemesAsset::StaticClass();
}
FText UOculusXRFaceVisemesRetargetAssetFactory::GetDisplayName() const
{
return LOCTEXT("DisplayNameMetahumanFace", "Face retarget asset for OculusXRMovement and Viseme based assets");
}
void UOculusXRFaceVisemesRetargetAssetFactory::SetDefaults(const TSubclassOf<UObject> GeneratedClass) const
{
if (UOculusXRLiveLinkRetargetFaceVisemesAsset* Retargeting = GeneratedClass->GetDefaultObject<UOculusXRLiveLinkRetargetFaceVisemesAsset>())
{
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::SIL, { "viseme_sil" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::PP, { "viseme_PP" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::FF, { "viseme_FF" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::TH, { "viseme_TH" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::DD, { "viseme_DD" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::KK, { "viseme_kk" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::CH, { "viseme_CH" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::SS, { "viseme_SS" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::NN, { "viseme_nn" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::RR, { "viseme_RR" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::AA, { "viseme_aa" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::E, { "viseme_E" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::IH, { "viseme_I" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::OH, { "viseme_O" });
Retargeting->CurveRemapping.Emplace(EOculusXRFaceVisemesExpression::OU, { "viseme_U" });
}
}
UOculusXRMetahumanBodyRetargetAssetFactory::UOculusXRMetahumanBodyRetargetAssetFactory(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
ParentClass = UOculusXRLiveLinkRetargetBodyAsset::StaticClass();
}
FText UOculusXRMetahumanBodyRetargetAssetFactory::GetDisplayName() const
{
return LOCTEXT("DisplayNameMetahumanBody", "Body retarget asset for OculusXRMovement and Metahuman");
}
void UOculusXRMetahumanBodyRetargetAssetFactory::SetDefaults(const TSubclassOf<UObject> GeneratedClass) const
{
if (UOculusXRLiveLinkRetargetBodyAsset* Retargeting = GeneratedClass->GetDefaultObject<UOculusXRLiveLinkRetargetBodyAsset>())
{
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRoot, "root");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyHips, "pelvis");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodySpineLower, "spine_01");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodySpineMiddle, "spine_02");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodySpineUpper, "spine_04");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyChest, "spine_05");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyNeck, "neck_02");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyHead, "head");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftShoulder, "clavicle_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftScapula, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftArmUpper, "upperarm_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftArmLower, "lowerarm_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandWristTwist, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightShoulder, "clavicle_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightScapula, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightArmUpper, "upperarm_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightArmLower, "lowerarm_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandWristTwist, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandPalm, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandWrist, "hand_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbMetacarpal, "thumb_01_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbProximal, "thumb_02_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbDistal, "thumb_03_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexMetacarpal, "index_metacarpal_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexProximal, "index_01_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexIntermediate, "index_02_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexDistal, "index_03_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleMetacarpal, "middle_metacarpal_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleProximal, "middle_01_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleIntermediate, "middle_02_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleDistal, "middle_03_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingMetacarpal, "ring_metacarpal_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingProximal, "ring_01_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingIntermediate, "ring_02_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingDistal, "ring_03_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleMetacarpal, "pinky_metacarpal_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleProximal, "pinky_01_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleIntermediate, "pinky_02_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleDistal, "pinky_03_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandPalm, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandWrist, "hand_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbMetacarpal, "thumb_01_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbProximal, "thumb_02_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbDistal, "thumb_03_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexMetacarpal, "index_metacarpal_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexProximal, "index_01_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexIntermediate, "index_02_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexDistal, "index_03_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleMetacarpal, "middle_metacarpal_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleProximal, "middle_01_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleIntermediate, "middle_02_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleDistal, "middle_03_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingMetacarpal, "ring_metacarpal_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingProximal, "ring_01_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingIntermediate, "ring_02_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingDistal, "ring_03_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleMetacarpal, "pinky_metacarpal_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleProximal, "pinky_01_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleIntermediate, "pinky_02_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleDistal, "pinky_03_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleTip, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftUpperLeg, "thigh_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftLowerLeg, "calf_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootAnkleTwist, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootAnkle, "foot_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootSubtalar, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootTransverse, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootBall, "ball_l");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightUpperLeg, "thigh_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightLowerLeg, "calf_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootAnkleTwist, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootAnkle, "foot_r");
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootSubtalar, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootTransverse, NAME_None);
Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootBall, "ball_r");
{
FOculusXRBoneCorrection FromOculusToUnreal;
FromOculusToUnreal.RotationOffset.Roll = -90;
FromOculusToUnreal.RotationOffset.Yaw = -90;
Retargeting->GlobalCorrection = FromOculusToUnreal;
}
{
FOculusXRBoneCorrectionSet Root;
Root.Bones.Add(EOculusXRBoneID::BodyRoot);
Root.BoneCorrection.RotationOffset.Roll = 90;
Retargeting->LocalCorrections.Add(Root);
}
{
FOculusXRBoneCorrectionSet Hips;
Hips.Bones.Add(EOculusXRBoneID::BodyHips);
Hips.BoneCorrection.RotationOffset.Yaw = 5;
Retargeting->LocalCorrections.Add(Hips);
}
{
FOculusXRBoneCorrectionSet SpineLowerPart;
SpineLowerPart.Bones.Add(EOculusXRBoneID::BodySpineLower);
SpineLowerPart.Bones.Add(EOculusXRBoneID::BodySpineMiddle);
SpineLowerPart.BoneCorrection.RotationOffset.Yaw = 10;
Retargeting->LocalCorrections.Add(SpineLowerPart);
}
{
FOculusXRBoneCorrectionSet SpineUpperPart;
SpineUpperPart.Bones.Add(EOculusXRBoneID::BodySpineUpper);
SpineUpperPart.BoneCorrection.PositionOffset.Y = 3;
SpineUpperPart.BoneCorrection.RotationOffset.Yaw = -5;
Retargeting->LocalCorrections.Add(SpineUpperPart);
}
{
FOculusXRBoneCorrectionSet Chest;
Chest.Bones.Add(EOculusXRBoneID::BodyChest);
Chest.BoneCorrection.PositionOffset.Y = 3;
Chest.BoneCorrection.RotationOffset.Yaw = -5;
Retargeting->LocalCorrections.Add(Chest);
}
{
FOculusXRBoneCorrectionSet Head;
Head.Bones.Add(EOculusXRBoneID::BodyHead);
Head.Bones.Add(EOculusXRBoneID::BodyNeck);
Head.BoneCorrection.PositionOffset.Y = -3;
Head.BoneCorrection.RotationOffset.Yaw = 5;
Retargeting->LocalCorrections.Add(Head);
}
{
FOculusXRBoneCorrectionSet LeftShoulder;
LeftShoulder.Bones.Add(EOculusXRBoneID::BodyLeftShoulder);
LeftShoulder.BoneCorrection.RotationOffset.Pitch = -5;
LeftShoulder.BoneCorrection.RotationOffset.Yaw = 30;
LeftShoulder.BoneCorrection.PositionOffset.X = 5;
LeftShoulder.BoneCorrection.PositionOffset.Y = -6;
Retargeting->LocalCorrections.Add(LeftShoulder);
}
{
FOculusXRBoneCorrectionSet RightShoulder;
RightShoulder.Bones.Add(EOculusXRBoneID::BodyRightShoulder);
RightShoulder.BoneCorrection.RotationOffset.Pitch = -5;
RightShoulder.BoneCorrection.RotationOffset.Yaw = 30;
RightShoulder.BoneCorrection.PositionOffset.X = -6;
RightShoulder.BoneCorrection.PositionOffset.Y = 5;
Retargeting->LocalCorrections.Add(RightShoulder);
}
{
FOculusXRBoneCorrectionSet Hands;
for (uint8 BoneId = static_cast<uint8>(EOculusXRBoneID::BodyLeftHandPalm); BoneId <= static_cast<uint8>(EOculusXRBoneID::BodyRightHandLittleTip); ++BoneId)
{
Hands.Bones.Emplace(static_cast<EOculusXRBoneID>(BoneId));
}
Hands.BoneCorrection.RotationOffset.Roll = 180;
Retargeting->LocalCorrections.Add(Hands);
}
{
FOculusXRBoneCorrectionSet Legs;
Legs.Bones.Add(EOculusXRBoneID::BodyLeftUpperLeg);
Legs.Bones.Add(EOculusXRBoneID::BodyLeftLowerLeg);
Legs.Bones.Add(EOculusXRBoneID::BodyRightUpperLeg);
Legs.Bones.Add(EOculusXRBoneID::BodyRightLowerLeg);
Legs.BoneCorrection.RotationOffset.Yaw = 180;
Retargeting->LocalCorrections.Add(Legs);
}
{
FOculusXRBoneCorrectionSet FootAnkles;
FootAnkles.Bones.Add(EOculusXRBoneID::BodyLeftFootAnkle);
FootAnkles.Bones.Add(EOculusXRBoneID::BodyRightFootAnkle);
FootAnkles.BoneCorrection.RotationOffset.Roll = 180;
FootAnkles.BoneCorrection.RotationOffset.Pitch = 175;
FootAnkles.BoneCorrection.RotationOffset.Yaw = -80;
Retargeting->LocalCorrections.Add(FootAnkles);
}
{
FOculusXRBoneCorrectionSet FootBalls;
FootBalls.Bones.Add(EOculusXRBoneID::BodyLeftFootBall);
FootBalls.BoneCorrection.RotationOffset.Yaw = 200;
FootBalls.BoneCorrection.PositionOffset.Y = -5;
FootBalls.BoneCorrection.PositionOffset.Z = 1;
Retargeting->LocalCorrections.Add(FootBalls);
}
{
FOculusXRBoneCorrectionSet FootBalls;
FootBalls.Bones.Add(EOculusXRBoneID::BodyRightFootBall);
FootBalls.BoneCorrection.RotationOffset.Yaw = 200;
FootBalls.BoneCorrection.PositionOffset.Y = 5;
FootBalls.BoneCorrection.PositionOffset.Z = -1;
Retargeting->LocalCorrections.Add(FootBalls);
}
Retargeting->RetargetingMode = EOculusXRRetargetingMode::RotationsPlusHips;
Retargeting->ForwardMesh = EOculusXRAxis::Y;
}
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,62 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "CoreMinimal.h"
#include "Factories/BlueprintFactory.h"
#include "OculusXRMovementAssetsFactories.generated.h"
UCLASS(Abstract, hidecategories = Object, MinimalAPI)
class UOculusXRMetahumanRetargetAssetFactory : public UBlueprintFactory
{
GENERATED_BODY()
public:
UOculusXRMetahumanRetargetAssetFactory(const FObjectInitializer& ObjectInitializer);
virtual bool ConfigureProperties() override;
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext) override;
virtual uint32 GetMenuCategories() const override;
protected:
virtual void SetDefaults(const TSubclassOf<UObject> GeneratedClass) const PURE_VIRTUAL(UOculusXRMetahumanRetargetAssetFactory::SetDefaults, );
};
UCLASS(hidecategories = Object, MinimalAPI)
class UOculusXRMetahumanFaceRetargetAssetFactory : public UOculusXRMetahumanRetargetAssetFactory
{
GENERATED_BODY()
public:
UOculusXRMetahumanFaceRetargetAssetFactory(const FObjectInitializer& ObjectInitializer);
virtual FText GetDisplayName() const override;
protected:
virtual void SetDefaults(const TSubclassOf<UObject> GeneratedClass) const override;
};
UCLASS(hidecategories = Object, MinimalAPI)
class UOculusXRFaceVisemesRetargetAssetFactory : public UOculusXRMetahumanRetargetAssetFactory
{
GENERATED_BODY()
public:
UOculusXRFaceVisemesRetargetAssetFactory(const FObjectInitializer& ObjectInitializer);
virtual FText GetDisplayName() const override;
protected:
virtual void SetDefaults(const TSubclassOf<UObject> GeneratedClass) const override;
};
UCLASS(hidecategories = Object, MinimalAPI)
class UOculusXRMetahumanBodyRetargetAssetFactory : public UOculusXRMetahumanRetargetAssetFactory
{
GENERATED_BODY()
public:
UOculusXRMetahumanBodyRetargetAssetFactory(const FObjectInitializer& ObjectInitializer);
virtual FText GetDisplayName() const override;
protected:
virtual void SetDefaults(const TSubclassOf<UObject> GeneratedClass) const override;
};

View File

@@ -0,0 +1,93 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXRPTLayerComponentDetailsCustomization.h"
#include "OculusXRPassthroughLayerComponent.h"
#include "Components/StereoLayerComponent.h"
#include "DetailWidgetRow.h"
#include "PropertyRestriction.h"
#include "DetailLayoutBuilder.h"
#include "UObject/Field.h"
#include "Widgets/Text/STextBlock.h"
#define LOCTEXT_NAMESPACE "OculusXREditor"
//////////////////////////////////////////////////////////////////////////
// FOculusXRPTLayerComponentDetailsCustomization
TSharedRef<IDetailCustomization> FOculusXRPTLayerComponentDetailsCustomization::MakeInstance()
{
return MakeShareable(new FOculusXRPTLayerComponentDetailsCustomization);
}
void FOculusXRPTLayerComponentDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
TArray<FName> Categories;
DetailBuilder.GetCategoryNames(Categories);
for (FName CategoryName : Categories)
{
IDetailCategoryBuilder& CategoryBuilder = DetailBuilder.EditCategory(CategoryName, FText::GetEmpty(), ECategoryPriority::Important);
TArray<TSharedRef<IPropertyHandle>> DefaultProperties;
CategoryBuilder.GetDefaultProperties(DefaultProperties);
for (TSharedRef<IPropertyHandle> PropertyHandle : DefaultProperties)
{
if (PropertyHandle->GetProperty()->GetName() == FName("Shape"))
{
ShapePropertyHandle = PropertyHandle;
static const FName WarningColorStyle("Colors.AccentYellow");
/* clang-format off */
CategoryBuilder.AddCustomRow(LOCTEXT("OculusXRPTComponentShapeWarning", "Warning for UOculusXRPassthroughLayerComponent::Shape property"))
.Visibility(TAttribute<EVisibility>(this, &FOculusXRPTLayerComponentDetailsCustomization::GetShapeWarningVisibility))
[
SNew(SVerticalBox)
+ SVerticalBox::Slot().FillHeight(1.f).VAlign(EVerticalAlignment::VAlign_Center)
[
SNew(STextBlock)
.Font(IDetailLayoutBuilder::GetDetailFont())
.AutoWrapText(true)
.Justification(ETextJustify::Center)
.Text(TAttribute<FText>(this, &FOculusXRPTLayerComponentDetailsCustomization::GetShapeWarningText))
.ColorAndOpacity(FAppStyle::Get().GetSlateColor(WarningColorStyle))
]
];
/* clang-format on */
}
IDetailPropertyRow& Property = CategoryBuilder.AddProperty(PropertyHandle);
Property.Visibility(TAttribute<EVisibility>::CreateLambda([PropertyHandle]() -> EVisibility {
return PropertyHandle->IsEditConst() ? EVisibility::Hidden : EVisibility::Visible;
}));
}
}
}
EVisibility FOculusXRPTLayerComponentDetailsCustomization::GetShapeWarningVisibility() const
{
UObject* Shape = nullptr;
ShapePropertyHandle->GetValue(Shape);
if (!IsValid(Shape) || Shape->IsA<UOculusXRStereoLayerShapeUserDefined>())
return EVisibility::Collapsed;
else
return EVisibility::Visible;
}
FText FOculusXRPTLayerComponentDetailsCustomization::GetShapeWarningText() const
{
UObject* Shape = nullptr;
ShapePropertyHandle->GetValue(Shape);
if (!IsValid(Shape) || Shape->IsA<UOculusXRStereoLayerShapeUserDefined>())
return FText::GetEmpty();
else if (Shape->IsA<UOculusXRStereoLayerShapeReconstructed>())
return LOCTEXT("OculusXRPTComponentShapeWarningText_Reconstructed",
"If you wish to use the Reconstructed Passthrough Layer shape, the recommended method is to use the passthrough subsystem.\nFrom blueprint, call the \"Passthrough Subsytem->Initialize Persistent Passthrough\" node on startup instead of using this component.");
else
return FText::Format(LOCTEXT("OculusXRPTComponentShapeWarningText", "Please use a Shape class supporting passthrough with this component.\nIf you wish to continue using {0}, consider a Stereo Layer component instead"), FText::FromString(Shape->GetClass()->GetName()));
}
//////////////////////////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,25 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "PropertyHandle.h"
#include "IDetailCustomization.h"
class IDetailLayoutBuilder;
class FOculusXRPTLayerComponentDetailsCustomization : public IDetailCustomization
{
public:
/** Makes a new instance of this detail layout class for a specific detail view requesting it */
static TSharedRef<IDetailCustomization> MakeInstance();
// IDetailCustomization interface
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override;
// End of IDetailCustomization interface
EVisibility GetShapeWarningVisibility() const;
FText GetShapeWarningText() const;
private:
TSharedPtr<IPropertyHandle> ShapePropertyHandle;
};

View File

@@ -0,0 +1,59 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXRPassthroughColorLutAsset.h"
#include "AssetTypeCategories.h"
#include "UObject/ObjectMacros.h"
#include "UObject/Object.h"
#include "OculusXRPassthroughColorLut.h"
#define LOCTEXT_NAMESPACE "AssetTypeActions"
FText FAssetTypeActions_OculusXRPassthroughColorLut::GetName() const
{
return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PassthroughColorLUT", "PassthroughColorLUT");
}
FColor FAssetTypeActions_OculusXRPassthroughColorLut::GetTypeColor() const
{
return FColor(100, 100, 100);
}
const TArray<FText>& FAssetTypeActions_OculusXRPassthroughColorLut::GetSubMenus() const
{
static const TArray<FText> SubMenus{
LOCTEXT("AssetOculusXRPassthroughColorLutSubMenu", "OculusXR")
};
return SubMenus;
}
UClass* FAssetTypeActions_OculusXRPassthroughColorLut::GetSupportedClass() const
{
return UOculusXRPassthroughColorLut::StaticClass();
}
uint32 FAssetTypeActions_OculusXRPassthroughColorLut::GetCategories()
{
return EAssetTypeCategories::Misc;
}
UOculusXRPassthroughColorLutFactory::UOculusXRPassthroughColorLutFactory(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
SupportedClass = UOculusXRPassthroughColorLut::StaticClass();
bCreateNew = true;
bEditAfterNew = true;
}
UObject* UOculusXRPassthroughColorLutFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context,
FFeedbackContext* Warn)
{
return NewObject<UOculusXRPassthroughColorLut>(InParent, Name, Flags);
}
uint32 UOculusXRPassthroughColorLutFactory::GetMenuCategories() const
{
return EAssetTypeCategories::Misc;
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,33 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "CoreMinimal.h"
#include "Factories/Factory.h"
#include "AssetTypeActions_Base.h"
#include "OculusXRPassthroughColorLutAsset.generated.h"
class FAssetTypeActions_OculusXRPassthroughColorLut : public FAssetTypeActions_Base
{
public:
virtual FText GetName() const override;
virtual FColor GetTypeColor() const override;
virtual const TArray<FText>& GetSubMenus() const override;
virtual UClass* GetSupportedClass() const override;
virtual uint32 GetCategories() override;
};
UCLASS(hidecategories = Object, MinimalAPI)
class UOculusXRPassthroughColorLutFactory : public UFactory
{
GENERATED_BODY()
public:
UOculusXRPassthroughColorLutFactory(const FObjectInitializer& ObjectInitializer);
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context,
FFeedbackContext* Warn) override;
virtual uint32 GetMenuCategories() const override;
};

View File

@@ -0,0 +1,25 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXRPlatformToolSettings.h"
UOculusXRPlatformToolSettings::UOculusXRPlatformToolSettings()
: OculusTargetPlatform(EOculusXRPlatformTarget::Rift)
{
uint8 NumPlatforms = (uint8)EOculusXRPlatformTarget::Length;
OculusApplicationID.Init("", NumPlatforms);
OculusApplicationToken.Init("", NumPlatforms);
OculusReleaseChannel.Init("Alpha", NumPlatforms);
OculusReleaseNote.Init("", NumPlatforms);
OculusLaunchFilePath.Init("", NumPlatforms);
OculusSymbolDirPath.Init("", NumPlatforms);
OculusLanguagePacksPath.Init("", NumPlatforms);
OculusExpansionFilesPath.Init("", NumPlatforms);
OculusAssetConfigs.Init(FOculusXRAssetConfigArray(), NumPlatforms);
UploadDebugSymbols = true;
for (int i = 0; i < NumPlatforms; i++)
{
OculusAssetConfigs[i].ConfigArray = TArray<FOculusXRAssetConfig>();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,223 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "OculusXRPlatformToolSettings.h"
#include "Widgets/SWidget.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Input/SMultiLineEditableTextBox.h"
#include "Widgets/Input/SComboBox.h"
#include "Widgets/Input/STextComboBox.h"
#include "Widgets/Layout/SScrollBox.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/SCheckBox.h"
#include "Engine/PostProcessVolume.h"
#include "Framework/Text/SlateHyperlinkRun.h"
#include "HttpModule.h"
#include "HttpManager.h"
#include "Interfaces/IHttpResponse.h"
#include "Async/AsyncWork.h"
#include "HAL/Event.h"
#include "HAL/ThreadSafeBool.h"
#include "OculusXRPluginWrapper.h"
#include "Brushes/SlateDynamicImageBrush.h"
class SOculusPlatformToolWidget;
// Function Delegates
DECLARE_DELEGATE_OneParam(FEnableUploadButtonDel, bool);
DECLARE_DELEGATE_OneParam(FUpdateLogTextDel, FString);
DECLARE_DELEGATE_OneParam(FSetProcessDel, FProcHandle);
DECLARE_DELEGATE_RetVal_TwoParams(bool, FFieldValidatorDel, FString, FString&);
class SOculusPlatformToolWidget : public SCompoundWidget
{
public:
typedef void (SOculusPlatformToolWidget::*PTextComboBoxDel)(TSharedPtr<FString>, ESelectInfo::Type);
typedef void (SOculusPlatformToolWidget::*PTextComittedDel)(const FText&, ETextCommit::Type);
typedef FReply (SOculusPlatformToolWidget::*PButtonClickedDel)();
typedef bool (SOculusPlatformToolWidget::*PFieldValidatorDel)(FString, FString&);
typedef void (SOculusPlatformToolWidget::*PCheckBoxChangedDel)(ECheckBoxState);
SLATE_BEGIN_ARGS(SOculusPlatformToolWidget)
{
}
SLATE_END_ARGS();
SOculusPlatformToolWidget();
void Construct(const FArguments& InArgs);
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
static FString LogText;
private:
TSharedPtr<SMultiLineEditableTextBox> ToolConsoleLog;
TSharedPtr<SVerticalBox> GeneralSettingsBox;
TSharedPtr<SHorizontalBox> ButtonToolbar;
TSharedPtr<SVerticalBox> OptionalSettings;
TSharedPtr<SVerticalBox> ExpansionFilesSettings;
TSharedPtr<FSlateDynamicImageBrush> ODHIconDynamicImageBrush;
UEnum* PlatformEnum;
UEnum* GamepadEmulationEnum;
UEnum* AssetTypeEnum;
UOculusXRPlatformToolSettings* PlatformSettings;
TArray<TSharedPtr<FString>> OculusPlatforms;
TArray<TSharedPtr<FString>> RiftGamepadEmulation;
TArray<TSharedPtr<FString>> AssetType;
bool Options2DCollapsed;
bool OptionsRedistPackagesCollapsed;
bool ActiveUploadButton;
bool RequestUploadButtonActive;
FProcHandle PlatformProcess;
FThreadSafeBool LogTextUpdated;
FEnableUploadButtonDel EnableUploadButtonDel;
FUpdateLogTextDel UpdateLogTextDel;
FSetProcessDel SetProcessDel;
// Callbacks
FReply OnStartPlatformUpload();
FReply OnSelectRiftBuildDirectory();
FReply OnClearRiftBuildDirectory();
FReply OnSelectLaunchFilePath();
FReply OnClearLaunchFilePath();
FReply OnSelectSymbolDirPath();
FReply OnClearSymbolDirPath();
FReply OnSelect2DLaunchPath();
FReply OnClear2DLaunchPath();
FReply OnCancelUpload();
FReply OnSelectLanguagePacksPath();
FReply OnClearLanguagePacksPath();
FReply OnSelectExpansionFilesPath();
FReply OnClearExpansionFilesPath();
FString GenerateSymbolPath();
void OnPlatformSettingChanged(TSharedPtr<FString> ItemSelected, ESelectInfo::Type SelectInfo);
void OnApplicationIDChanged(const FText& InText, ETextCommit::Type InCommitType);
void OnApplicationTokenChanged(const FText& InText, ETextCommit::Type InCommitType);
void OnReleaseChannelChanged(const FText& InText, ETextCommit::Type InCommitType);
void OnReleaseNoteChanged(const FText& InText, ETextCommit::Type InCommitType);
void OnRiftBuildVersionChanged(const FText& InText, ETextCommit::Type InCommitType);
void OnRiftLaunchParamsChanged(const FText& InText, ETextCommit::Type InCommitType);
void OnRiftFirewallChanged(ECheckBoxState CheckState);
void OnRedistPackageStateChanged(ECheckBoxState CheckState, FOculusXRRedistPackage* Package);
void OnRiftGamepadEmulationChanged(TSharedPtr<FString> ItemSelected, ESelectInfo::Type SelectInfo);
void On2DLaunchParamsChanged(const FText& InText, ETextCommit::Type InCommitType);
void On2DOptionsExpanded(bool bExpanded);
void OnRedistPackagesExpanded(bool bExpanded);
void OnAssetConfigRequiredChanged(ECheckBoxState CheckState, int i);
void OnAssetConfigTypeChanged(TSharedPtr<FString> ItemSelected, ESelectInfo::Type SelectInfo, int i);
void OnAssetConfigSKUChanged(const FText& InText, ETextCommit::Type InCommitType, int i);
void OnUploadDebugSymbolsChanged(ECheckBoxState CheckState);
void OnDebugSymbolsOnlyChanged(ECheckBoxState CheckState);
void OnBuildIDChanged(const FText& InText, ETextCommit::Type InCommitType);
// UI Constructors
void BuildGeneralSettingsBox(TSharedPtr<SVerticalBox> box);
void BuildTextComboBoxField(TSharedPtr<SVerticalBox> box, FText name, TArray<TSharedPtr<FString>>* options, TSharedPtr<FString> current, PTextComboBoxDel deleg, int32 indentAmount = 0);
void BuildTextField(TSharedPtr<SVerticalBox> box, FText name, FText text, FText tooltip, PTextComittedDel deleg, bool isPassword = false, int32 indentAmount = 0);
void BuildFileDirectoryField(TSharedPtr<SVerticalBox> box, FText name, FText path, FText tooltip, PButtonClickedDel deleg, PButtonClickedDel clearDeleg, int32 indentAmount = 0);
void BuildCheckBoxField(TSharedPtr<SVerticalBox> box, FText name, bool check, FText tooltip, PCheckBoxChangedDel deleg, int32 indentAmount = 0);
void BuildButtonToolbar(TSharedPtr<SHorizontalBox> box);
void BuildRiftOptionalFields(TSharedPtr<SVerticalBox> area);
void BuildRedistPackagesBox(TSharedPtr<SVerticalBox> box);
void BuildExpansionFileBox(TSharedPtr<SVerticalBox> box);
void BuildAssetConfigBox(TSharedPtr<SVerticalBox> box, FOculusXRAssetConfig config, int index);
// Text Field Validators
void ValidateTextField(PFieldValidatorDel del, FString text, FString name, bool& success);
bool GenericFieldValidator(FString text, FString& error);
bool IDFieldValidator(FString text, FString& error);
bool DirectoryFieldValidator(FString text, FString& error);
bool FileFieldValidator(FString text, FString& error);
bool LaunchParamValidator(FString text, FString& error);
bool ConstructArguments(FString& args);
bool ConstructDebugSymbolArguments(FString& args);
void EnableUploadButton(bool enabled);
void LoadConfigSettings();
void UpdateLogText(FString text);
void SetPlatformProcess(FProcHandle proc);
void LoadRedistPackages();
};
class FPlatformDownloadTask : public FNonAbandonableTask
{
friend class FAsyncTask<FPlatformDownloadTask>;
private:
FUpdateLogTextDel UpdateLogText;
FString ToolConsoleLog;
FEvent* downloadCompleteEvent;
FEvent* SaveCompleteEvent;
TArray<uint8> httpData;
public:
FPlatformDownloadTask(FUpdateLogTextDel textDel, FEvent* saveEvent);
void OnDownloadRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded);
void OnRequestDownloadProgress64(FHttpRequestPtr HttpRequest, uint64 BytesSend, uint64 InBytesReceived);
void OnRequestDownloadProgress(FHttpRequestPtr HttpRequest, int32 BytesSend, int32 InBytesReceived);
protected:
void DoWork();
void UpdateProgressLog(int progress);
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FPlatformDownloadTask, STATGROUP_ThreadPoolAsyncTasks);
}
};
class FPlatformUploadTask : public FNonAbandonableTask
{
friend class FAsyncTask<FPlatformUploadTask>;
public:
FPlatformUploadTask(FString args, FEnableUploadButtonDel del, FUpdateLogTextDel textDel, FSetProcessDel procDel);
private:
void* ReadPipe;
void* WritePipe;
FSetProcessDel SetProcess;
FUpdateLogTextDel UpdateLogText;
FEnableUploadButtonDel EnableUploadButton;
FString LaunchArgs;
protected:
void DoWork();
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FPlatformUploadTask, STATGROUP_ThreadPoolAsyncTasks);
}
};
class FPlatformLoadRedistPackagesTask : public FNonAbandonableTask
{
friend class FAsyncTask<FPlatformLoadRedistPackagesTask>;
public:
FPlatformLoadRedistPackagesTask(FUpdateLogTextDel textDel);
private:
void* ReadPipe;
void* WritePipe;
FUpdateLogTextDel UpdateLogText;
protected:
void DoWork();
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FPlatformLoadRedistPackagesTask, STATGROUP_ThreadPoolAsyncTasks);
}
};

View File

@@ -0,0 +1,316 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXRPrivacyNotification.h"
#include <regex>
#include "ISettingsModule.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "OculusXRHMDModule.h"
#include "OculusXRTelemetry.h"
#include "OculusXRToolStyle.h"
#include "Interfaces/IMainFrameModule.h"
#include "Widgets/Notifications/INotificationWidget.h"
#include "Widgets/Text/SRichTextBlock.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/Images/SImage.h"
#include "Framework/Application/SlateApplication.h"
#include "OculusXRTelemetryPrivacySettings.h"
#define LOCTEXT_NAMESPACE "OculusXRTelemetryPrivacySettings"
namespace OculusXRTelemetry
{
namespace
{
constexpr int CONSENT_TITLE_MAX_LENGTH = 256;
constexpr int CONSENT_TEXT_MAX_LENGTH = 2048;
constexpr int CONSENT_NOTIFICATION_MAX_LENGTH = 1024;
void OnBrowserLinkClicked(const FSlateHyperlinkRun::FMetadata& Metadata)
{
const FString* Url = Metadata.Find(TEXT("href"));
if (Url)
{
FPlatformProcess::LaunchURL(**Url, nullptr, nullptr);
}
}
void UpdateNotificationShown()
{
FOculusXRHMDModule::GetPluginWrapper().SetNotificationShown(UNREAL_TOOL_ID);
}
std::string MarkdownToRTF(const std::string& markdown)
{
const std::regex boldText(R"(\*\*(.*?)\*\*)");
const std::string boldReplacement = "<NormalText.Important>$1</>";
std::string rtf = "";
rtf = std::regex_replace(markdown, boldText, boldReplacement);
const std::regex linkRegex(R"(\[(.*?)\]\((.*?)\))");
const std::string linkReplacement = "<a id=\"browser\" style=\"Hyperlink\" href=\"$2\">$1</>";
rtf = std::regex_replace(rtf, linkRegex, linkReplacement);
return rtf;
}
} // namespace
class SOculusXRPrivacyNotification : public SCompoundWidget, public INotificationWidget
{
public:
SLATE_BEGIN_ARGS(SOculusXRPrivacyNotification) {}
SLATE_ARGUMENT(std::string, ConsentText);
/** Invoked when any button is clicked, needed for fading out notification */
SLATE_EVENT(FSimpleDelegate, OnClicked)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs)
{
OnClicked = InArgs._OnClicked;
// Container for the text and optional interactive widgets (buttons, check box, and hyperlink)
TSharedRef<SVerticalBox> InteractiveWidgetsBox = SNew(SVerticalBox);
InteractiveWidgetsBox->AddSlot()
.Padding(FMargin(0.0f, 10.0f, 0.0f, 2.0f))
.AutoHeight()
[SNew(SRichTextBlock)
.Text(FText::FromString(MarkdownToRTF(InArgs._ConsentText).data()))
.AutoWrapText(true)
+ SRichTextBlock::HyperlinkDecorator(TEXT("browser"), FSlateHyperlinkRun::FOnClick::CreateStatic(&OnBrowserLinkClicked))
+ SRichTextBlock::HyperlinkDecorator(TEXT("PrivacySettings"), FSlateHyperlinkRun::FOnClick::CreateRaw(this, &SOculusXRPrivacyNotification::OpenPrivacySettings))];
ChildSlot
[SNew(SBox)
[SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Top)
.HAlign(HAlign_Left)
[SNew(SOverlay)
+ SOverlay::Slot()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[SNew(SImage)
.Image(FOculusToolStyle::Get().GetBrush("OculusTool.MetaLogo"))
.DesiredSizeOverride(FVector2D(32, 32))]]
+ SHorizontalBox::Slot()
.Padding(10.f, 0.f, 5.f, 0.f)
[InteractiveWidgetsBox]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Top)
.HAlign(HAlign_Right)
[SNew(SButton)
.Cursor(EMouseCursor::Default)
.ButtonStyle(FAppStyle::Get(), "SimpleButton")
.ContentPadding(0.0f)
.OnClicked(this, &SOculusXRPrivacyNotification::CloseButtonClicked)
.Content()
[SNew(SImage)
.Image(FAppStyle::GetBrush("Icons.X"))
.ColorAndOpacity(FSlateColor::UseForeground())]]]];
}
private:
virtual TSharedRef<SWidget> AsWidget() override
{
return AsShared();
}
virtual void OnSetCompletionState(SNotificationItem::ECompletionState InState) override
{
if (InState == SNotificationItem::ECompletionState::CS_Success)
{
UpdateNotificationShown();
}
}
FReply CloseButtonClicked()
{
OnClicked.ExecuteIfBound();
return FReply::Handled();
}
void OpenPrivacySettings(const FSlateHyperlinkRun::FMetadata& /*Metadata*/) const
{
OnClicked.ExecuteIfBound();
FModuleManager::LoadModuleChecked<ISettingsModule>("Settings").ShowViewer(FName("Editor"), FName("Privacy"), FName("OculusXR"));
}
FSimpleDelegate OnClicked;
};
class SOculusTelemetryWindow : public SCompoundWidget
{
SLATE_BEGIN_ARGS(SOculusTelemetryWindow) {}
SLATE_ARGUMENT(std::string, ConsentText);
SLATE_END_ARGS()
/** Construct the slate layout for the widget */
void Construct(const FArguments& InArgs)
{
TSharedPtr<SVerticalBox> RootContainer = SNew(SVerticalBox);
const TSharedPtr<SHorizontalBox> ButtonsWidget = SNew(SHorizontalBox);
ButtonsWidget->AddSlot()
[SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.ContentPadding(5)
.OnClicked(this, &SOculusTelemetryWindow::OnNotShareClicked)
.Text(LOCTEXT("NotShare", "Only share essential data"))]];
ButtonsWidget->AddSlot()
[SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
[SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.ContentPadding(5)
.OnClicked(this, &SOculusTelemetryWindow::OnShareClicked)
.ButtonStyle(&FAppStyle::Get().GetWidgetStyle<FButtonStyle>("PrimaryButton"))
.Text(LOCTEXT("Share", "Share additional data"))]];
// Construct the text widget
const TSharedPtr<SVerticalBox> TextWidget = SNew(SVerticalBox);
TextWidget->AddSlot()
.AutoHeight()
[SNew(SRichTextBlock)
.AutoWrapText(true)
.Text(FText::FromString(MarkdownToRTF(InArgs._ConsentText).data()))
.DecoratorStyleSet(&FAppStyle::Get())
+ SRichTextBlock::HyperlinkDecorator(TEXT("browser"), FSlateHyperlinkRun::FOnClick::CreateStatic(&OnBrowserLinkClicked))];
RootContainer->AddSlot()
[SNew(SVerticalBox)
+ SVerticalBox::Slot()
.Padding(20, 20, 20, 20)
.VAlign(VAlign_Center)
[TextWidget.ToSharedRef()]];
RootContainer->AddSlot()
[SNew(SVerticalBox)
+ SVerticalBox::Slot()
.Padding(20, 20)
.VAlign(VAlign_Bottom)
[ButtonsWidget.ToSharedRef()]];
ChildSlot
[SNew(SBox)
.WidthOverride(960)
[RootContainer.ToSharedRef()]];
}
private:
FReply OnShareClicked()
{
FOculusXRHMDModule::GetPluginWrapper().SaveUnifiedConsent(UNREAL_TOOL_ID, ovrpBool_True);
if (UOculusXRTelemetryPrivacySettings* EditorPrivacySettings = GetMutableDefault<UOculusXRTelemetryPrivacySettings>())
{
EditorPrivacySettings->bIsEnabled = true;
}
PropagateTelemetryConsent();
FSlateApplication::Get().FindWidgetWindow(AsShared())->RequestDestroyWindow();
return FReply::Handled();
}
FReply OnNotShareClicked()
{
FOculusXRHMDModule::GetPluginWrapper().SaveUnifiedConsent(UNREAL_TOOL_ID, ovrpBool_False);
if (UOculusXRTelemetryPrivacySettings* EditorPrivacySettings = GetMutableDefault<UOculusXRTelemetryPrivacySettings>())
{
EditorPrivacySettings->bIsEnabled = false;
}
PropagateTelemetryConsent();
FSlateApplication::Get().FindWidgetWindow(AsShared())->RequestDestroyWindow();
return FReply::Handled();
}
};
void SpawnFullConsentWindow()
{
if (FSlateApplication::Get().IsRenderingOffScreen())
{
return;
}
char TelemetryWindowTitle[CONSENT_TITLE_MAX_LENGTH];
char ConsentText[CONSENT_TEXT_MAX_LENGTH];
if (FOculusXRHMDModule::GetPluginWrapper().GetConsentTitle(TelemetryWindowTitle) == ovrpFailure || FOculusXRHMDModule::GetPluginWrapper().GetConsentMarkdownText(ConsentText) == ovrpFailure)
{
return;
}
std::string Title(TelemetryWindowTitle);
std::string MarkdownText(ConsentText);
IMainFrameModule::Get().OnMainFrameCreationFinished().AddLambda([Title, MarkdownText](const TSharedPtr<SWindow>& RootWindow, bool /*bIsRunningStartupDialog*/) {
const TSharedRef<SWindow> Window = SNew(SWindow)
.Title(FText::FromString(Title.c_str()))
.SizingRule(ESizingRule::Autosized)
.SupportsMaximize(false)
.SupportsMinimize(false)[SNew(SOculusTelemetryWindow).ConsentText(MarkdownText)];
FSlateApplication::Get().AddModalWindow(Window, RootWindow);
});
}
void SpawnNotification()
{
char NotificationText[CONSENT_NOTIFICATION_MAX_LENGTH];
if (FOculusXRHMDModule::GetPluginWrapper().GetConsentNotificationMarkdownText("<a id=\"PrivacySettings\">Settings</>", NotificationText) == ovrpFailure)
{
return;
}
TPromise<TSharedPtr<SNotificationItem>> BtnNotificationPromise;
const auto OnClicked = [NotificationFuture = BtnNotificationPromise.GetFuture().Share()]() {
const TSharedPtr<SNotificationItem> Notification = NotificationFuture.Get();
Notification->SetCompletionState(SNotificationItem::CS_Success);
Notification->Fadeout();
};
FNotificationInfo Info(SNew(SOculusXRPrivacyNotification).OnClicked_Lambda(OnClicked).ConsentText(NotificationText));
Info.ExpireDuration = 60.0f;
const TSharedPtr<SNotificationItem> PrivacyNotification = FSlateNotificationManager::Get().AddNotification(Info);
if (PrivacyNotification.IsValid())
{
PrivacyNotification->SetCompletionState(SNotificationItem::CS_Pending);
BtnNotificationPromise.SetValue(PrivacyNotification);
}
}
void MaybeSpawnTelemetryConsent()
{
if (!FOculusXRHMDModule::Get().IsOVRPluginAvailable() || !FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
{
return;
}
if (!FModuleManager::Get().IsModuleLoaded("MainFrame"))
{
return;
}
const auto& PluginWrapper = FOculusXRHMDModule::GetPluginWrapper();
if (PluginWrapper.ShouldShowTelemetryConsentWindow(UNREAL_TOOL_ID))
{
SpawnFullConsentWindow();
}
if (PluginWrapper.ShouldShowTelemetryNotification(UNREAL_TOOL_ID))
{
SpawnNotification();
}
}
} // namespace OculusXRTelemetry
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,7 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
namespace OculusXRTelemetry
{
void MaybeSpawnTelemetryConsent();
} // namespace OculusXRTelemetry

View File

@@ -0,0 +1,215 @@

// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXRSettingsToggle.h"
#include "Containers/Array.h"
#include "Delegates/Delegate.h"
#include "DetailCategoryBuilder.h"
#include "DetailLayoutBuilder.h"
#include "DetailWidgetRow.h"
#include "Engine/ImportantToggleSettingInterface.h"
#include "Fonts/SlateFontInfo.h"
#include "HAL/PlatformProcess.h"
#include "IDetailPropertyRow.h"
#include "OculusXRHMDModule.h"
#include "OculusXRTelemetry.h"
#include "Layout/Children.h"
#include "Layout/Margin.h"
#include "Misc/Attribute.h"
#include "PropertyHandle.h"
#include "SlotBase.h"
#include "Styling/AppStyle.h"
#include "Styling/SlateColor.h"
#include "Styling/SlateTypes.h"
#include "Templates/Casts.h"
#include "Types/SlateEnums.h"
#include "UObject/NameTypes.h"
#include "UObject/Object.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Input/SCheckBox.h"
#include "Widgets/Input/SHyperlink.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Text/STextBlock.h"
#define LOCTEXT_NAMESPACE "OculusXRSettingsToggle"
class SImportantToggleButton : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SImportantToggleButton)
: _Text()
{
}
SLATE_STYLE_ARGUMENT(FCheckBoxStyle, CheckBoxStyle)
SLATE_ARGUMENT(FText, Text)
SLATE_ARGUMENT(FText, ToolTipText)
SLATE_ATTRIBUTE(bool, IsSet)
SLATE_EVENT(FSimpleDelegate, OnToggled)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs)
{
OnToggled = InArgs._OnToggled;
IsSetAttribute = InArgs._IsSet;
FSlateFontInfo LargeDetailsFont = IDetailLayoutBuilder::GetDetailFontBold();
LargeDetailsFont.Size += 4;
ChildSlot
[SNew(SCheckBox)
.Style(InArgs._CheckBoxStyle)
.IsChecked(this, &SImportantToggleButton::GetCheckedState)
.OnCheckStateChanged(this, &SImportantToggleButton::OnClick)
.ToolTipText(InArgs._ToolTipText)
.Padding(FMargin(16.0f, 12.0f))
.ForegroundColor(FSlateColor::UseForeground())
.IsFocusable(true)
[SNew(STextBlock)
.Text(InArgs._Text)
.Font(LargeDetailsFont)]];
}
private:
void OnClick(ECheckBoxState State)
{
OnToggled.ExecuteIfBound();
}
ECheckBoxState GetCheckedState() const
{
return IsSetAttribute.Get() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
}
TAttribute<bool> IsSetAttribute;
FSimpleDelegate OnToggled;
};
TSharedRef<IDetailCustomization> FOculusXRSettingsToggle::MakeInstance()
{
return MakeShareable(new FOculusXRSettingsToggle);
}
void FOculusXRSettingsToggle::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
if (!ToggleEnabled.IsSet() && FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized())
{
ToggleEnabled = FOculusXRHMDModule::GetPluginWrapper().IsConsentSettingsChangeEnabled(OculusXRTelemetry::UNREAL_TOOL_ID) == ovrpBool_True;
}
TArray<TWeakObjectPtr<UObject>> Objects;
DetailBuilder.GetObjectsBeingCustomized(Objects);
if (Objects.Num() == 1)
{
ToggleSettingObject = Objects[0];
IImportantToggleSettingInterface* ToggleSettingInterface = Cast<IImportantToggleSettingInterface>(ToggleSettingObject.Get());
if (ToggleSettingInterface != nullptr)
{
FName CategoryName;
FName PropertyName;
ToggleSettingInterface->GetToggleCategoryAndPropertyNames(CategoryName, PropertyName);
IDetailCategoryBuilder& Category = DetailBuilder.EditCategory(CategoryName);
TogglePropertyHandle = DetailBuilder.GetProperty(PropertyName);
FSlateFontInfo StateDescriptionFont = IDetailLayoutBuilder::GetDetailFont();
StateDescriptionFont.Size += 4;
// Customize collision section
Category.InitiallyCollapsed(false)
.AddProperty(TogglePropertyHandle)
.ShouldAutoExpand(true)
.CustomWidget()
[SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0.0f, 12.0f, 0.0f, 0.0f)
[SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[SNew(SImportantToggleButton)
.CheckBoxStyle(FAppStyle::Get(), "Property.ToggleButton.Start")
.Text(ToggleSettingInterface->GetFalseStateLabel())
.ToolTipText(ToggleSettingInterface->GetFalseStateTooltip())
.IsSet(this, &FOculusXRSettingsToggle::IsToggleValue, false)
.OnToggled(this, &FOculusXRSettingsToggle::OnToggledTo, false)
.IsEnabled(this, &FOculusXRSettingsToggle::IsEnabled)]
+ SHorizontalBox::Slot()
.AutoWidth()
[SNew(SImportantToggleButton)
.CheckBoxStyle(FAppStyle::Get(), "Property.ToggleButton.End")
.Text(ToggleSettingInterface->GetTrueStateLabel())
.ToolTipText(ToggleSettingInterface->GetTrueStateTooltip())
.IsSet(this, &FOculusXRSettingsToggle::IsToggleValue, true)
.OnToggled(this, &FOculusXRSettingsToggle::OnToggledTo, true)
.IsEnabled(this, &FOculusXRSettingsToggle::IsEnabled)]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Right)
.Padding(0.0f, 12.0f)
[SNew(SVerticalBox)
+ SVerticalBox::Slot()
.VAlign(VAlign_Center)
[SNew(SHyperlink)
.Text(ToggleSettingInterface->GetAdditionalInfoUrlLabel())
.OnNavigate(this, &FOculusXRSettingsToggle::OnNavigateHyperlink, ToggleSettingInterface->GetAdditionalInfoUrl())]]]
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0.0f, 12.0f)
[SNew(STextBlock)
.AutoWrapText(true)
.Text(this, &FOculusXRSettingsToggle::GetDescriptionText)
.Font(StateDescriptionFont)]];
}
}
}
bool FOculusXRSettingsToggle::IsToggleValue(bool bValue) const
{
bool bPropertyValue = false;
TogglePropertyHandle->GetValue(bPropertyValue);
return bPropertyValue == bValue;
}
bool FOculusXRSettingsToggle::IsEnabled() const
{
return ToggleEnabled.IsSet() && ToggleEnabled.GetValue();
}
void FOculusXRSettingsToggle::OnToggledTo(bool bSetTo)
{
TogglePropertyHandle->SetValue(bSetTo);
}
void FOculusXRSettingsToggle::OnNavigateHyperlink(FString Url)
{
FPlatformProcess::LaunchURL(*Url, nullptr, nullptr);
}
FText FOculusXRSettingsToggle::GetDescriptionText() const
{
IImportantToggleSettingInterface* ToogleSettingInterface = Cast<IImportantToggleSettingInterface>(ToggleSettingObject.Get());
if (ToogleSettingInterface != nullptr)
{
bool bPropertyValue = false;
TogglePropertyHandle->GetValue(bPropertyValue);
if (bPropertyValue)
{
return ToogleSettingInterface->GetTrueStateDescription();
}
else
{
return ToogleSettingInterface->GetFalseStateDescription();
}
}
return FText::GetEmpty();
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,30 @@

// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "IDetailCustomization.h"
#include "UObject/WeakObjectPtr.h"
class IPropertyHandle;
class OCULUSXREDITOR_API FOculusXRSettingsToggle : public IDetailCustomization
{
public:
static TSharedRef<IDetailCustomization> MakeInstance();
// IDetailCustomization interface
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
// End of IDetailCustomization interface
private:
bool IsToggleValue(bool bValue) const;
bool IsEnabled() const;
void OnToggledTo(bool bSetTo);
void OnNavigateHyperlink(FString Url);
FText GetDescriptionText() const;
TSharedPtr<IPropertyHandle> TogglePropertyHandle;
TWeakObjectPtr<UObject> ToggleSettingObject;
TOptional<bool> ToggleEnabled;
};

View File

@@ -0,0 +1,10 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "OculusXRTelemetry.h"
namespace OculusXRTelemetry::Events
{
using FEditorStart = TMarker<191956532>;
} // namespace OculusXRTelemetry::Events

View File

@@ -0,0 +1,67 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXRToolCommands.h"
#include "OculusXRProjectSetupToolModule.h"
#include "OculusXRSyntheticEnvironmentServer.h"
#include "Framework/Docking/TabManager.h"
#include "Misc/EngineVersionComparison.h"
#define LOCTEXT_NAMESPACE "FOculusXREditorModule"
#if UE_VERSION_OLDER_THAN(5, 5, 0)
#define AS_LOCALIZABLE_ADVANCED(Namespace, Key, TextLiteral) \
FInternationalization::ForUseOnlyByLocMacroAndGraphNodeTextLiterals_CreateText(TextLiteral, Namespace, Key)
#else
#define AS_LOCALIZABLE_ADVANCED(Namespace, Key, TextLiteral) \
FText::AsLocalizable_Advanced(Namespace, Key, TextLiteral)
#endif
void FOculusToolCommands::RegisterCommands()
{
UI_COMMAND(OpenProjectSetupTool, "Meta XR Project Setup Tool", "Show Meta XR Project Setup Tool", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(ToggleDeploySo, "Deploy compiled .so directly to device", "Faster deploy when we only have code changes by deploying compiled .so directly to device", EUserInterfaceActionType::ToggleButton, FInputChord());
UI_COMMAND(ToggleIterativeCookOnTheFly, "Enable Iterative Cook on the Fly", "Faster deploy for asset changes by keeping previously cooked contents on the device (Uses Cook on the Fly)", EUserInterfaceActionType::ToggleButton, FInputChord());
UI_COMMAND(OpenPlatWindow, "Meta XR Platform Window", "Show Meta XR Platform Window", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(ToggleMetaXRSim, "Meta XR Simulator", "Activate/Deactivate Meta XR Simulator", EUserInterfaceActionType::ToggleButton, FInputChord());
#if PLATFORM_WINDOWS
static const FString launch("Launch ");
static const FString dot(".");
const auto& rooms = FMetaXRSES::GetSynthEnvRooms();
for (const auto& room : rooms)
{
TSharedPtr<FUICommandInfo> command;
const FString DotCommandName = dot + room.GuiName;
const FString InDescription = launch + room.GuiName;
const FString InCommandNameUnderscoreTooltip = room.GuiName + TEXT("_ToolTip");
const FString InSubNamespace = TEXT(LOCTEXT_NAMESPACE);
const FString UICommandsStr = TEXT("UICommands");
const FString Namespace = UICommandsStr + dot + InSubNamespace;
FUICommandInfo::MakeCommandInfo(
this->AsShared(),
command,
FName(InCommandNameUnderscoreTooltip),
AS_LOCALIZABLE_ADVANCED(*Namespace, *InDescription, *InDescription),
AS_LOCALIZABLE_ADVANCED(*Namespace, InCommandNameUnderscoreTooltip.GetCharArray().GetData(), *InDescription),
FSlateIcon(),
EUserInterfaceActionType::Button,
FInputChord(),
FInputChord());
RoomCommands.Add(command);
}
#endif
UI_COMMAND(StopServer, "Stop Server", "Stop Server", EUserInterfaceActionType::Button, FInputChord());
}
void FOculusToolCommands::ShowOculusTool()
{
IOculusXRProjectSetupToolModule::Get().ShowProjectSetupTool("Console");
}
#undef LOCTEXT_NAMESPACE

View File

@@ -0,0 +1,44 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Framework/Commands/Commands.h"
#include "OculusXRToolStyle.h"
#include "OculusXREditorModule.h"
#include "HAL/IConsoleManager.h"
class FOculusToolCommands : public TCommands<FOculusToolCommands>
{
public:
FOculusToolCommands()
: TCommands<FOculusToolCommands>(
TEXT("OculusTool"), NSLOCTEXT("Contexts", "OculusXREditor", "OculusXREditor Plugin"), NAME_None,
FOculusToolStyle::GetStyleSetName())
, ShowOculusToolCommand(
TEXT("vr.oculus.ShowToolWindow"),
*NSLOCTEXT("OculusRift", "CCommandText_ShowToolWindow",
"Show the Oculus Editor Tool window (editor only).")
.ToString(),
FConsoleCommandDelegate::CreateRaw(this, &FOculusToolCommands::ShowOculusTool))
{
}
// TCommands<> interface
virtual void RegisterCommands() override;
TSharedPtr<FUICommandInfo> OpenProjectSetupTool;
TSharedPtr<FUICommandInfo> ToggleDeploySo;
TSharedPtr<FUICommandInfo> ToggleIterativeCookOnTheFly;
TSharedPtr<FUICommandInfo> OpenPlatWindow;
TSharedPtr<FUICommandInfo> ToggleMetaXRSim;
TSharedPtr<FUICommandInfo> StopServer;
TArray<TSharedPtr<FUICommandInfo>> RoomCommands;
private:
void ShowOculusTool();
FAutoConsoleCommand ShowOculusToolCommand;
};

View File

@@ -0,0 +1,75 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXRToolStyle.h"
#include "Styling/SlateStyleRegistry.h"
#include "Framework/Application/SlateApplication.h"
#include "Slate/SlateGameResources.h"
#include "Interfaces/IPluginManager.h"
TSharedPtr<FSlateStyleSet> FOculusToolStyle::StyleInstance = nullptr;
void FOculusToolStyle::Initialize()
{
if (!StyleInstance.IsValid())
{
StyleInstance = Create();
FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance);
}
}
void FOculusToolStyle::Shutdown()
{
FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance);
ensure(StyleInstance.IsUnique());
StyleInstance.Reset();
}
FName FOculusToolStyle::GetStyleSetName()
{
static FName StyleSetName(TEXT("OculusToolStyle"));
return StyleSetName;
}
#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define BOX_BRUSH(RelativePath, ...) FSlateBoxBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define BORDER_BRUSH(RelativePath, ...) FSlateBorderBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)
#define TTF_FONT(RelativePath, ...) FSlateFontInfo(Style->RootToContentDir(RelativePath, TEXT(".ttf")), __VA_ARGS__)
#define OTF_FONT(RelativePath, ...) FSlateFontInfo(Style->RootToContentDir(RelativePath, TEXT(".otf")), __VA_ARGS__)
const FVector2D Icon16x16(16.0f, 16.0f);
const FVector2D Icon20x20(20.0f, 20.0f);
const FVector2D Icon40x40(40.0f, 40.0f);
TSharedRef<FSlateStyleSet> FOculusToolStyle::Create()
{
TSharedRef<FSlateStyleSet> Style = MakeShareable(new FSlateStyleSet("OculusToolStyle"));
Style->SetContentRoot(IPluginManager::Get().FindPlugin("OculusXR")->GetBaseDir() / TEXT("Resources"));
Style->Set("OculusTool.MenuButton", new IMAGE_BRUSH(TEXT("ButtonIcon_80x"), Icon40x40));
Style->Set("OculusTool.OpenPluginWindow", new IMAGE_BRUSH(TEXT("ButtonIcon_80x"), Icon40x40));
Style->Set("OculusTool.MetaLogo",
new FSlateVectorImageBrush(Style->RootToContentDir("MetaLogo", TEXT(".svg")),
FVector2D(32.0f, 32.0f)));
return Style;
}
#undef IMAGE_BRUSH
#undef BOX_BRUSH
#undef BORDER_BRUSH
#undef TTF_FONT
#undef OTF_FONT
void FOculusToolStyle::ReloadTextures()
{
if (FSlateApplication::IsInitialized())
{
FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
}
}
const ISlateStyle& FOculusToolStyle::Get()
{
return *StyleInstance;
}

View File

@@ -0,0 +1,30 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Styling/SlateStyle.h"
/** */
class FOculusToolStyle
{
public:
static void Initialize();
static void Shutdown();
/** reloads textures used by slate renderer */
static void ReloadTextures();
/** @return The Slate style set for the Shooter game */
static const ISlateStyle& Get();
static FName GetStyleSetName();
private:
static TSharedRef<class FSlateStyleSet> Create();
private:
static TSharedPtr<class FSlateStyleSet> StyleInstance;
};

View File

@@ -0,0 +1,19 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleInterface.h"
class FToolBarBuilder;
class FMenuBuilder;
#define OCULUS_EDITOR_MODULE_NAME "OculusXREditor"
//////////////////////////////////////////////////////////////////////////
// IOculusXREditorModule
class IOculusXREditorModule : public IModuleInterface
{
};

View File

@@ -0,0 +1,37 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "OculusXREditorSettings.generated.h"
UENUM()
enum class EOculusXRPlatform : uint8
{
PC UMETA(DisplayName = "PC"),
Mobile UMETA(DisplayName = "Mobile"),
Length UMETA(DisplayName = "Invalid")
};
/**
*
*/
UCLASS(config = Editor)
class OCULUSXREDITOR_API UOculusXREditorSettings : public UObject
{
GENERATED_BODY()
public:
UOculusXREditorSettings();
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TMap<FName, bool> PerfToolIgnoreList;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
EOculusXRPlatform PerfToolTargetPlatform;
UPROPERTY(globalconfig, EditAnywhere, Category = MetaXR)
bool bAddMenuOption;
};

View File

@@ -0,0 +1,272 @@
// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "OculusXRPlatformToolSettings.generated.h"
UENUM()
enum class EOculusXRPlatformTarget : uint8
{
Rift UMETA(DisplayName = "Rift"),
Quest UMETA(DisplayName = "Quest"),
Length UMETA(DisplayName = "Invalid")
};
UENUM()
enum class EOculusXRGamepadEmulation : uint8
{
Off UMETA(DisplayName = "Off"),
Twinstick UMETA(DisplayName = "Twinstick"),
RightDPad UMETA(DisplayName = "Right D Pad"),
LeftDPad UMETA(DisplayName = "Left D Pad"),
Length UMETA(DisplayName = "Invalid")
};
UENUM()
enum class EOculusXRAssetType : uint8
{
Default UMETA(DisplayName = "Default"),
Store UMETA(DisplayName = "Store"),
Language_Pack UMETA(DisplayName = "Language Pack"),
Length UMETA(DisplayName = "Invlaid"),
};
USTRUCT()
struct FOculusXRRedistPackage
{
GENERATED_USTRUCT_BODY()
UPROPERTY(config, EditAnywhere, Category = MetaXR)
bool Included = false;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString Name;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString Id;
};
USTRUCT()
struct FOculusXRAssetConfig
{
GENERATED_USTRUCT_BODY()
UPROPERTY(config, EditAnywhere, Category = MetaXR)
EOculusXRAssetType AssetType = EOculusXRAssetType::Default;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
bool Required = false;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString Name;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString Sku;
};
USTRUCT()
struct FOculusXRAssetConfigArray
{
GENERATED_USTRUCT_BODY()
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FOculusXRAssetConfig> ConfigArray;
};
/**
*
*/
UCLASS(config = Editor)
class OCULUSXREDITOR_API UOculusXRPlatformToolSettings : public UObject
{
GENERATED_BODY()
public:
UOculusXRPlatformToolSettings();
uint8 GetTargetPlatform()
{
return (uint8)OculusTargetPlatform;
}
void SetTargetPlatform(uint8 i)
{
OculusTargetPlatform = (EOculusXRPlatformTarget)i;
}
FString GetApplicationID()
{
return (uint8)OculusTargetPlatform < OculusApplicationID.Num() ? OculusApplicationID[(uint8)OculusTargetPlatform] : "";
}
void SetApplicationID(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusApplicationID[(uint8)OculusTargetPlatform] = s;
}
}
FString GetApplicationToken()
{
return (uint8)OculusTargetPlatform < OculusApplicationToken.Num() ? OculusApplicationToken[(uint8)OculusTargetPlatform] : "";
}
void SetApplicationToken(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusApplicationToken[(uint8)OculusTargetPlatform] = s;
}
}
FString GetReleaseChannel()
{
return (uint8)OculusTargetPlatform < OculusReleaseChannel.Num() ? OculusReleaseChannel[(uint8)OculusTargetPlatform] : "Alpha";
}
void SetReleaseChannel(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusReleaseChannel[(uint8)OculusTargetPlatform] = s;
}
}
FString GetReleaseNote()
{
return (uint8)OculusTargetPlatform < OculusReleaseNote.Num() ? OculusReleaseNote[(uint8)OculusTargetPlatform] : "";
}
void SetReleaseNote(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusReleaseNote[(uint8)OculusTargetPlatform] = s;
}
}
FString GetLaunchFilePath()
{
return (uint8)OculusTargetPlatform < OculusLaunchFilePath.Num() ? OculusLaunchFilePath[(uint8)OculusTargetPlatform] : "";
}
void SetLaunchFilePath(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusLaunchFilePath[(uint8)OculusTargetPlatform] = s;
}
}
EOculusXRGamepadEmulation GetRiftGamepadEmulation()
{
return OculusRiftGamepadEmulation;
}
void SetRiftGamepadEmulation(uint8 i)
{
OculusRiftGamepadEmulation = (EOculusXRGamepadEmulation)i;
}
FString GetLanguagePacksPath()
{
return (uint8)OculusTargetPlatform < OculusLanguagePacksPath.Num() ? OculusLanguagePacksPath[(uint8)OculusTargetPlatform] : "";
}
void SetLanguagePacksPath(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusLanguagePacksPath[(uint8)OculusTargetPlatform] = s;
}
}
FString GetExpansionFilesPath()
{
return (uint8)OculusTargetPlatform < OculusExpansionFilesPath.Num() ? OculusExpansionFilesPath[(uint8)OculusTargetPlatform] : "";
}
void SetExpansionFilesPath(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusExpansionFilesPath[(uint8)OculusTargetPlatform] = s;
}
}
FString GetSymbolDirPath()
{
return (uint8)OculusTargetPlatform < OculusSymbolDirPath.Num() ? OculusSymbolDirPath[(uint8)OculusTargetPlatform] : "";
}
void SetSymbolDirPath(FString s)
{
if (OculusTargetPlatform < EOculusXRPlatformTarget::Length)
{
OculusSymbolDirPath[(uint8)OculusTargetPlatform] = s;
}
}
TArray<FOculusXRAssetConfig>* GetAssetConfigs()
{
return (uint8)OculusTargetPlatform < OculusAssetConfigs.Num() ? &OculusAssetConfigs[(uint8)OculusTargetPlatform].ConfigArray : nullptr;
}
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString OculusRiftBuildDirectory;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString OculusRiftBuildVersion;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString OculusRiftLaunchParams;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
bool OculusRiftFireWallException;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString OculusRift2DLaunchPath;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString OculusRift2DLaunchParams;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FOculusXRRedistPackage> OculusRedistPackages;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
bool UploadDebugSymbols;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
bool DebugSymbolsOnly;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
FString BuildID;
private:
UPROPERTY(config, EditAnywhere, Category = MetaXR)
EOculusXRPlatformTarget OculusTargetPlatform;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusApplicationID;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusApplicationToken;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusReleaseChannel;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusReleaseNote;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusLaunchFilePath;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
EOculusXRGamepadEmulation OculusRiftGamepadEmulation;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusLanguagePacksPath;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusExpansionFilesPath;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FString> OculusSymbolDirPath;
UPROPERTY(config, EditAnywhere, Category = MetaXR)
TArray<FOculusXRAssetConfigArray> OculusAssetConfigs;
};