VRTowerDef/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.cpp

326 lines
9.8 KiB
C++

// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXRBuildAnalytics.h"
#include "GameProjectGenerationModule.h"
#include "OculusXRHMDModule.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 (!GConfig->GetBool(TEXT("/Script/OculusXREditor.OculusXREditorSettings"), TEXT("bEnableOculusBuildTelemetry"), TelemetryEnabled, GEditorIni))
{
GConfig->SetBool(TEXT("/Script/OculusXREditor.OculusXREditorSettings"), TEXT("bEnableOculusBuildTelemetry"), TelemetryEnabled, GEditorIni);
GConfig->Flush(0);
}
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)
{
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;
FOculusXRHMDModule::GetPluginWrapper().SetDeveloperMode(true);
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");
}