279 lines
6.2 KiB
C++
279 lines
6.2 KiB
C++
// Copyright UnexGames 2025. All Rights Reserved.
|
|
|
|
#include "ThreadUtility.h"
|
|
#include "Engine/Engine.h"
|
|
#include "ThreadBase.h"
|
|
#if WITH_EDITOR
|
|
#include "Editor.h"
|
|
#else
|
|
#include "Misc/CoreDelegates.h"
|
|
#endif
|
|
|
|
#define LOCTEXT_NAMESPACE "UThreadUtility"
|
|
|
|
#if WITH_EDITOR
|
|
FDelegateHandle UThreadUtility::EndPIEHandle = FDelegateHandle();
|
|
#else
|
|
FDelegateHandle UThreadUtility::PreExitHandle = FDelegateHandle();
|
|
#endif
|
|
TArray<UObject*> UThreadUtility::RootObjects = {};
|
|
int32 UThreadUtility::TaskIndex = 0;
|
|
int32 UThreadUtility::MutexIndex = 0;
|
|
int32 UThreadUtility::ThreadPoolIndex = 0;
|
|
|
|
UThreadUtility::UThreadUtility()
|
|
{
|
|
#if WITH_EDITOR
|
|
EndPIEHandle = FEditorDelegates::PrePIEEnded.AddStatic(&UThreadUtility::OnEndPIE);
|
|
#else
|
|
PreExitHandle = FCoreDelegates::OnPreExit.AddStatic(&UThreadUtility::OnPreExit);
|
|
#endif
|
|
}
|
|
|
|
UThreadUtility::~UThreadUtility()
|
|
{
|
|
#if WITH_EDITOR
|
|
FEditorDelegates::PrePIEEnded.Remove(EndPIEHandle);
|
|
#else
|
|
FCoreDelegates::OnPreExit.Remove(PreExitHandle);
|
|
#endif
|
|
TaskIndex = 0;
|
|
MutexIndex = 0;
|
|
ThreadPoolIndex = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UObject* UThreadUtility::GetContextWorld(UObject* WorldContextObject)
|
|
{
|
|
return GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull);
|
|
}
|
|
|
|
|
|
bool UThreadUtility::CanUseAudioThread()
|
|
{
|
|
return (FPlatformMisc::AllowAudioThread());
|
|
}
|
|
|
|
|
|
|
|
bool UThreadUtility::IsPrintThreadSafe()
|
|
{
|
|
return (FPlatformMisc::IsLocalPrintThreadSafe());
|
|
}
|
|
|
|
|
|
|
|
bool UThreadUtility::IsUseRenderThread()
|
|
{
|
|
return (FPlatformMisc::UseRenderThread());
|
|
}
|
|
|
|
|
|
|
|
bool UThreadUtility::CanSupportMultiThreadedFileHandles()
|
|
{
|
|
return (FGenericPlatformMisc::SupportsMultithreadedFileHandles());
|
|
}
|
|
|
|
|
|
|
|
|
|
void UThreadUtility::CancelTask(UThreadBase* Task)
|
|
{
|
|
if (Task != nullptr && Task->IsValidLowLevel() && IsValid(Task) && !Task->IsUnreachable())
|
|
{
|
|
Task->Cancel();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UThreadUtility::WaitToFinish(UThreadBase* Task)
|
|
{
|
|
if (Task != nullptr && Task->IsValidLowLevel() && IsValid(Task) && !Task->IsUnreachable())
|
|
{
|
|
Task->WaitToFinish();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool UThreadUtility::IsRunning(UThreadBase* Task)
|
|
{
|
|
if (Task != nullptr && Task->IsValidLowLevel() && IsValid(Task) && !Task->IsUnreachable())
|
|
{
|
|
return Task->IsRunning();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool UThreadUtility::IsCanceled(UThreadBase* Task)
|
|
{
|
|
if (Task != nullptr && Task->IsValidLowLevel() && IsValid(Task) && !Task->IsUnreachable())
|
|
{
|
|
return Task->IsCanceled();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int32 UThreadUtility::MixThreeIntegers(int32 Integer1, int32 Integer2, int32 Integer3)
|
|
{
|
|
unsigned long a = (unsigned long)Integer1;
|
|
unsigned long b = (unsigned long)Integer2;
|
|
unsigned long c = (unsigned long)Integer3;
|
|
|
|
a = a - b; a = a - c; a = a ^ (c >> 13);
|
|
b = b - c; b = b - a; b = b ^ (a << 8);
|
|
c = c - a; c = c - b; c = c ^ (b >> 13);
|
|
a = a - b; a = a - c; a = a ^ (c >> 12);
|
|
b = b - c; b = b - a; b = b ^ (a << 16);
|
|
c = c - a; c = c - b; c = c ^ (b >> 5);
|
|
a = a - b; a = a - c; a = a ^ (c >> 3);
|
|
b = b - c; b = b - a; b = b ^ (a << 10);
|
|
c = c - a; c = c - b; c = c ^ (b >> 15);
|
|
return (int32)c;
|
|
}
|
|
|
|
|
|
void UThreadUtility::GetRandomScale(const FVector& Min, const FVector& Max, EScaleType Type, const FRandomStream& RandomStream, FVector& Scale)
|
|
{
|
|
|
|
TFunction<float(float, int32)> Interpolate = [&](float Alpha, int32 Axis)
|
|
{
|
|
return Min[Axis] + (Alpha * (Max[Axis] - Min[Axis]));
|
|
};
|
|
|
|
Scale = FVector(1.0f);
|
|
float LockRand = 0.0f;
|
|
|
|
switch (Type)
|
|
{
|
|
case EScaleType::Uniform:
|
|
Scale.X = Interpolate(RandomStream.GetFraction(), 0);
|
|
Scale.Y = Scale.X;
|
|
Scale.Z = Scale.X;
|
|
break;
|
|
|
|
case EScaleType::Free:
|
|
Scale.X = Interpolate(RandomStream.GetFraction(), 0);
|
|
Scale.Y = Interpolate(RandomStream.GetFraction(), 1);
|
|
Scale.Z = Interpolate(RandomStream.GetFraction(), 2);
|
|
break;
|
|
|
|
case EScaleType::LockXY:
|
|
LockRand = RandomStream.GetFraction();
|
|
Scale.X = Interpolate(LockRand, 0);
|
|
Scale.Y = Interpolate(LockRand, 1);
|
|
Scale.Z = Interpolate(RandomStream.GetFraction(), 2);
|
|
break;
|
|
|
|
case EScaleType::LockXZ:
|
|
LockRand = RandomStream.GetFraction();
|
|
Scale.X = Interpolate(LockRand, 0);
|
|
Scale.Y = Interpolate(RandomStream.GetFraction(), 1);
|
|
Scale.Z = Interpolate(LockRand, 2);
|
|
break;
|
|
|
|
case EScaleType::LockYZ:
|
|
LockRand = RandomStream.GetFraction();
|
|
Scale.X = Interpolate(RandomStream.GetFraction(), 0);
|
|
Scale.Y = Interpolate(LockRand, 1);
|
|
Scale.Z = Interpolate(LockRand, 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool UThreadUtility::IsSupportsMultithreading()
|
|
{
|
|
return(FPlatformProcess::SupportsMultithreading());
|
|
}
|
|
|
|
|
|
void UThreadUtility::SetNameToThread(FString ThreadName)
|
|
{
|
|
FPlatformProcess::SetThreadName(*ThreadName);
|
|
}
|
|
|
|
|
|
|
|
|
|
void UThreadUtility::AddToRoot(UObject* Object)
|
|
{
|
|
if (Object)
|
|
{
|
|
if (!Object->IsRooted())
|
|
{
|
|
if (!RootObjects.Contains(Object))
|
|
{
|
|
RootObjects.Add(Object);
|
|
Object->AddToRoot();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UThreadUtility::RemoveFromRoot(UObject* Object)
|
|
{
|
|
if(Object)
|
|
{
|
|
if (Object->IsRooted())
|
|
{
|
|
if (RootObjects.Contains(Object))
|
|
{
|
|
RootObjects.Remove(Object);
|
|
Object->RemoveFromRoot();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void UThreadUtility::OnEndPIE(const bool bIsSimulating)
|
|
{
|
|
for (auto Object : RootObjects)
|
|
{
|
|
if (Object != nullptr && Object->IsValidLowLevel() && IsValid(Object) && !Object->IsUnreachable())
|
|
{
|
|
if (Object->IsRooted())
|
|
{
|
|
if (RootObjects.Contains(Object))
|
|
{
|
|
Object->RemoveFromRoot();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RootObjects.Empty();
|
|
}
|
|
|
|
void UThreadUtility::OnPreExit()
|
|
{
|
|
for (auto Object : RootObjects)
|
|
{
|
|
if (Object)
|
|
{
|
|
if (Object->IsRooted())
|
|
{
|
|
if (RootObjects.Contains(Object))
|
|
{
|
|
Object->RemoveFromRoot();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RootObjects.Empty();
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|