October3d55/M/MultiThread/Source/MultiThreadLibrary/Private/ThreadUtility.cpp

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