29 #include "ObjectTools.h"
31 #include "Subsystems/UnrealEditorSubsystem.h"
37 #include "Delegates/Delegate.h"
39 #include "Engine/LatentActionManager.h"
41 #include "Engine/LevelStreaming.h"
43 #include "Engine/TextureLightProfile.h"
45 #include "Engine/World.h"
47 #include "HAL/PlatformProcess.h"
49 #include "IImageWrapper.h"
51 #include "IImageWrapperModule.h"
53 #include "ImageUtils.h"
55 #include "Kismet/BlueprintFunctionLibrary.h"
57 #include "Kismet/GameplayStatics.h"
59 #include "Misc/Guid.h"
61 #include "Misc/MonitoredProcess.h"
63 #include "Stats/Stats.h"
65 #include "UObject/Object.h"
67 #include "UObject/ObjectMacros.h"
83 #include "RRCoreUtils.generated.h"
95 class UCameraComponent;
112 class RAPYUTASIMULATIONPLUGINS_API
URRCoreUtils :
public UBlueprintFunctionLibrary
126 template<
class T, std::
size_t N>
138 template<
bool bInBoolPreprocessor>
144 if constexpr (bInBoolPreprocessor)
156 return TEXT(
"FALSE");
174 FString outXMLString = InXMLString;
178 outXMLString.TrimStartAndEndInline();
182 outXMLString = outXMLString.Replace(TEXT(
"\r"),
EMPTY_STR);
192 FORCEINLINE
static FString
StdToFString(
const std::string& InStdString)
196 return FString(InStdString.c_str());
206 return std::string(TCHAR_TO_UTF8(*InUEString));
214 static constexpr
const TCHAR* CMD_SIM_QUIT = TEXT(
"quit");
216 static constexpr
const TCHAR* CMD_STATS_START = TEXT(
"stat startfile");
218 static constexpr
const TCHAR* CMD_STATS_STOP = TEXT(
"stat stopfile");
220 static constexpr
const TCHAR* CMD_MEMORY_REPORT = TEXT(
"memreport");
222 static constexpr
const TCHAR* CMD_MEMORY_REPORT_FULL = TEXT(
"memreport -full");
224 static constexpr
const TCHAR* CMD_GC_DUMP_POOL_STATS = TEXT(
"gc.DumpPoolStats");
226 static constexpr
const TCHAR* CMD_RHI_GPU_CAPTURE_OPTIONS_ENABLE = TEXT(
"r.RHISetGPUCaptureOptions 1");
228 static constexpr
const TCHAR* CMD_RENDER_DOC_CAPTURE_FRAME = TEXT(
"renderdoc.CaptureFrame");
230 static constexpr
const TCHAR* CMD_SHADOW_MAP_CACHING_TURN_OFF = TEXT(
"r.Shadow.CacheWholeSceneShadows 0");
232 static constexpr
const TCHAR* CMD_AO_USE_HISTORY_DISABLE = TEXT(
"r.AOUseHistory 0");
234 static constexpr
const TCHAR* CMD_OCCLUDED_PRIMITIVES_VISUALIZE = TEXT(
"r.VisualizeOccludedPrimitives 1");
236 static constexpr
const TCHAR* CMD_CUSTOM_DEPTH_STENCIL_ENABLE = TEXT(
"r.CustomDepth 3");
240 static constexpr
const TCHAR* CMD_FORWARD_SHADING_ENABLE = TEXT(
"r.ForwardShading 1");
242 static constexpr
const TCHAR* CMD_HIGHRES_SCREENSHOT_DELAY = TEXT(
"r.HighResScreenshotDelay");
244 static constexpr
const TCHAR* CMD_AUDIO_MIXER_DISABLE = TEXT(
"au.IsUsingAudioMixer 0");
254 static constexpr
const TCHAR* SimFileExts[] = {
342 const uint8 fileTypeIdx =
static_cast<uint8
>(InFileType);
346 return SimFileExts[fileTypeIdx];
350 static FString GetFileTypeFilter(
const ERRFileType InFileType);
380 FORCEINLINE
static bool IsFileType(
const FString& InFilePath,
const TArray<ERRFileType>& InFileTypes)
384 for (
const auto& fileType : InFileTypes)
406 #define CCMDLINE_ARG_FORMAT (TEXT("%s="))
408 template<
typename TCmdlet>
414 return IsRunningCommandlet() && GetRunningCommandletClass()->IsChildOf<TCmdlet>();
424 if (IsRunningCommandlet())
440 GetPlayerController<APlayerController>(0, InContextObject)->ConsoleCommand(InCommandText);
458 bool bResult =
false;
460 if constexpr (TIsSame<T, bool>::Value)
464 bResult = FParse::Bool(FCommandLine::Get(), *FString::Printf(
CCMDLINE_ARG_FORMAT, InArgName), OutArgValue);
472 bResult = FParse::Value(FCommandLine::Get(), *FString::Printf(
CCMDLINE_ARG_FORMAT, InArgName), OutArgValue);
478 if (!bResult && bIsLogged)
482 UE_LOG_WITH_INFO(LogTemp, Error, TEXT(
"Command line argument not found under the name [%s]"), InArgName);
496 const TCHAR* InArgName,
500 bool bIsLogged =
false)
504 bool bResult =
false;
506 if constexpr (TIsSame<T, bool>::Value)
510 bResult = FParse::Bool(*InParams, *FString::Printf(
CCMDLINE_ARG_FORMAT, InArgName), OutArgValue);
518 bResult = FParse::Value(*InParams, *FString::Printf(
CCMDLINE_ARG_FORMAT, InArgName), OutArgValue);
524 if (!bResult && bIsLogged)
528 UE_LOG_WITH_INFO(LogTemp, Error, TEXT(
"[%s] does not contain an argument named [%s]"), *InParams, InArgName);
540 static constexpr
const TCHAR* PIXEL_STREAMER_PLAYER_NAME = TEXT(
"pixelstreamer");
546 UWorld* editorWorld =
nullptr;
550 if (UUnrealEditorSubsystem* UnrealEditorSubsystem = GEditor->GetEditorSubsystem<UUnrealEditorSubsystem>())
556 editorWorld = UnrealEditorSubsystem->GetEditorWorld();
574 return GEditor && (GEditor->PlayWorld || GIsPlayInEditorWorld);
592 return Cast<T>(InContextObject->GetWorld()->GetAuthGameMode());
604 verify(IsInGameThread());
606 return Cast<T>(UGameplayStatics::GetGameInstance(InContextObject));
618 return Cast<T>(InContextObject->GetWorld()->GetGameState());
630 verify(IsInGameThread());
632 return Cast<T>(UGameplayStatics::GetPlayerControllerFromID(InContextObject, InSceneInstanceId));
644 if (UWorld* World = GEngine->GetWorldFromContextObject(InContextObject, EGetWorldErrorMode::LogAndReturnNull))
648 for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator)
652 T* playerController = Cast<T>(Iterator->Get());
654 if (playerController)
658 OutPlayerControllerList.Add(playerController);
676 return Cast<T>(UGameplayStatics::CreatePlayer(InContextObject, ControllerId,
true));
688 for (int32 i = 0; i < InNumOfPlayers; i++)
692 T* newPlayer = Cast<T>(UGameplayStatics::CreatePlayer(InContextObject, i,
true));
696 OutPlayerControllerList.Add(newPlayer);
702 static bool HasPlayerControllerListInitialized(
const UObject* InContextObject,
bool bIsLogged =
false);
708 static int32 GetMaxSplitscreenPlayers(
const UObject* InContextObject);
712 template<
typename TRRObject>
728 return InContextObject->GetDefaultConfigFilename();
738 return InContextObject->GetClass()->GetConfigName();
744 static bool IsSimProfiling();
768 static bool HasSimInitialized(
const UObject* InContextObject,
bool bIsLogged =
false);
786 static URRSceneInstance* GetSceneInstance(
const UObject* InContextObject, int8 InSceneInstanceId);
790 static ARRSceneDirector* GetSceneDirector(
const UObject* InContextObject, int8 InSceneInstanceId);
792 static FVector GetSceneInstanceLocation(int8 InSceneInstanceId);
796 static bool HasEnoughDiskSpace(
const FString& InPath, uint64 InRequiredMemorySizeInBytes);
800 static bool ShutDownSim(
const UObject* InContextObject, uint64 InSimCompletionTimeoutInSecs);
802 static void ExecuteSimQuitCommand(
const UObject* InContextObject);
810 return GetTypeHash(FGuid::NewGuid());
838 bool bSucceeded =
false;
840 ULevelStreamingDynamic* streamLevel =
842 ULevelStreamingDynamic::LoadLevelInstance(InContextObject->GetWorld(),
852 UE_LOG_WITH_INFO(LogTemp, Log, TEXT(
"%d Streaming level creation from path: %s"), bSucceeded, *InLevelInfo.
AssetPath);
880 const FString& InLevelName,
882 UObject* InTargetObject =
nullptr,
884 const FName& InExecuteFunctionName = NAME_None)
888 static int32 sLatentActionUUID = 0;
890 FLatentActionInfo latentActionInfo;
892 latentActionInfo.CallbackTarget = InTargetObject;
894 latentActionInfo.ExecutionFunction = InExecuteFunctionName;
896 latentActionInfo.UUID = ++sLatentActionUUID;
898 latentActionInfo.Linkage = 0;
900 UGameplayStatics::LoadStreamLevel(InContextObject, *InLevelName,
true,
true, latentActionInfo);
918 static void UnstreamLevel(
const UObject* InContextObject,
const FName& InLevelName)
922 UGameplayStatics::UnloadStreamLevel(InContextObject, InLevelName, FLatentActionInfo(),
true);
930 int8 InStartSceneInstanceId,
932 int8 InTargetSceneInstanceId)
936 if (InStartSceneInstanceId != InTargetSceneInstanceId)
940 const FVector startSceneInstanceLoc = GetSceneInstanceLocation(InStartSceneInstanceId);
942 const FVector targetSceneInstanceLoc = GetSceneInstanceLocation(InTargetSceneInstanceId);
944 InStreamingLevel->GetLoadedLevel()->ApplyWorldOffset(targetSceneInstanceLoc - startSceneInstanceLoc,
false);
958 static bool LoadFullFilePaths(
const FString& FolderPath,
960 TArray<FString>& OutFilePaths,
962 const TArray<ERRFileType>& InFileTypes,
964 const bool bInRecursive =
true);
972 FString dirFullPath = FPaths::IsRelative(DirPath) ? FPaths::ConvertRelativePathToFull(DirPath) : DirPath;
974 if (FPaths::DirectoryExists(dirFullPath))
986 bool res = FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*dirFullPath);
992 UE_LOG_WITH_INFO(LogTemp, Error, TEXT(
"Failed to create dir %s"), *dirFullPath)
1008 if (
false == InDirPath.IsEmpty())
1012 if (FPaths::IsRelative(InDirPath))
1016 UE_LOG_WITH_INFO(LogTemp, Fatal, TEXT(
"[%s] directory path is required to be an absolute path."), *InDirPath);
1020 else if (
false == FPaths::DirectoryExists(InDirPath))
1024 UE_LOG_WITH_INFO(LogTemp, Fatal, TEXT(
"[%s] directory does not exist."), *InDirPath);
1056 return FPlatformTime::Seconds();
1062 template<typename T, typename = TEnableIf<TIsFloatingPoint<T>::Value>>
1068 OutTimestamp = GetSeconds();
1074 template<typename T, typename = TEnableIf<TIsFloatingPoint<T>::Value>>
1080 return GetSeconds() - InLastTimestamp;
1108 static bool WaitUntilThenAct(TFunctionRef<
bool()> InCond,
1110 TFunctionRef<
void()> InPassedCondAct,
1112 float InTimeoutInSec,
1114 float InIntervalTimeInSec = 0.5f);
1138 static bool CheckWithTimeOut(
const TFunctionRef<
bool()>& InCondition,
1140 const TFunctionRef<
void()>& InActionUponTimeout,
1142 float InBeginTimeInSec,
1144 float InTimeoutInSec);
1152 check(IsValid(InWorld));
1156 InWorld->GetTimerManager().ClearTimer(InTimerHandle);
1162 template<
typename T,
typename TDelegate>
1168 check(IsValid(InObj));
1170 return InObj->GetWorld()->GetTimerManager().SetTimerForNextTick(InObj, InMethod);
1180 check(IsValid(InWorld));
1182 return InWorld->GetTimerManager().SetTimerForNextTick(InTimerDelegate);
1192 check(IsValid(InWorld));
1194 return InWorld->GetTimerManager().SetTimerForNextTick(MoveTemp(InCallback));
1200 template<
typename T>
1204 FTimerHandle& InTimerHandle,
1206 typename FTimerDelegate::template TMethodPtr<T>::FMethodPtr InMethod,
1208 float InRate = 0.5f)
1212 check(IsValid(InObj));
1214 InObj->GetWorld()->GetTimerManager().SetTimer(InTimerHandle, InObj, InMethod, InRate,
true);
1220 template<
typename T>
1224 FTimerHandle& InTimerHandle,
1226 TFunction<
void()> Callback,
1228 float InRate = 0.5f)
1232 check(IsValid(InObj));
1234 InObj->GetWorld()->GetTimerManager().SetTimer(InTimerHandle, MoveTemp(Callback), InRate,
true);
1244 check(IsValid(InWorld));
1248 InWorld->GetTimerManager().ClearTimer(InTimerHandle);
1262 const float InTimeOutSecs,
1264 const FString& InProcessName =
EMPTY_STR)
1270 if (
false == InProcess->Launch())
1274 UE_LOG_WITH_INFO_SHORT(LogTemp, Error, TEXT(
"[%s] Process failed being launched"), *InProcessName);
1286 bool bCancelled =
false;
1288 while (InProcess->Update())
1300 UE_LOG_WITH_INFO(LogTemp,
1304 TEXT(
"[%s] Process is about to be terminated after timeout [%f secs]"),
1314 InProcess->Cancel();
1320 return InProcess->GetReturnCode();
1334 static constexpr
const TCHAR* CIMAGE_WRAPPER_MODULE_NAME = TEXT(
"ImageWrapper");
1340 static void LoadImageWrapperModule();
1358 static UTexture2D* LoadImageToTexture(
const FString& InFullFilePath,
1360 const FString& InTextureName,
1362 const bool bInSaveToAsset =
false);
1366 static bool LoadImagesFromFolder(
const FString& InImageFolderPath,
1368 const TArray<ERRFileType>& InImageFileTypes,
1370 TArray<UTexture*>& OutImageTextureList,
1372 bool bIsLogged =
false);
1378 static UTextureLightProfile* LoadIESProfile(
const FString& InFullFilePath,
const FString& InLightProfileName);
1380 static bool LoadIESProfilesFromFolder(
const FString& InFolderPath,
1382 TArray<UTextureLightProfile*>& OutLightProfileList,
1384 bool bIsLogged =
false);
1404 template<
int8 InBitDepth>
1410 const FIntPoint& ImageSize,
1412 const int8 BitDepth,
1414 const ERGBFormat RGBFormat,
1416 TArray64<uint8>& OutCompressedData)
1422 verify(imageWrapper.IsValid());
1424 const auto& bitmap = InImageData.
GetImageData<InBitDepth>();
1428 if (ERGBFormat::Gray == RGBFormat)
1436 TArray<uint8> grayBitmap;
1438 for (
const auto& color : bitmap)
1442 grayBitmap.Add(color.R);
1446 imageWrapper->SetRaw(grayBitmap.GetData(),
1464 imageWrapper->SetRaw(
1466 bitmap.GetData(), bitmap.Num() * bitmap.GetTypeSize(), ImageSize.X, ImageSize.Y, RGBFormat, BitDepth);
1480 OutCompressedData = imageWrapper->GetCompressed(
1482 (
ERRFileType::IMAGE_JPG == InImageFileType) ? 100 :
static_cast<int32
>(EImageCompressionQuality::Default));
1520 static bool RenderThumbnail(UObject* InObject,
1522 uint32 InImageWidth,
1524 uint32 InImageHeight,
1526 const ThumbnailTools::EThumbnailTextureFlushMode::Type InFlushMode,
1528 FObjectThumbnail* OutThumbnail);
1546 static bool GenerateThumbnail(UObject* InObject, uint32 InImageWidth, uint32 InImageHeight,
const FString& InSaveImagePath);
1550 FORCEINLINE
static bool ScreenMsg(
const FColor& InColor,
const FString& InMessage,
float InTimeToDisplay = 50000.f)
1558 GEngine->AddOnScreenDebugMessage(-1, InTimeToDisplay, InColor, *InMessage);
1582 FORCEINLINE
static void PrintMessage(
const FString& InMessage,
bool bInError =
false,
float InTimeOnScreen = 100.f)
1590 UE_LOG(LogTemp, Error, TEXT(
"%s"), *InMessage);
1598 UE_LOG(LogTemp, Log, TEXT(
"%s"), *InMessage);
1602 ScreenMsg(bInError ? FColor::Red : FColor::Yellow, InMessage, InTimeOnScreen);
1604 #if RAPYUTA_SIM_DEBUG
1606 FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *InMessage, bInError ? TEXT(
"Error") : TEXT(
"Info"));