October3d55/M/MultiThread/Source/MultiThreadLibrary/Public/ThreadTasks.h

161 lines
3.9 KiB
C++

// Copyright UnexGames 2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ThreadTaskBase.h"
#include "HAL/ThreadManager.h"
#include "ThreadTasks.generated.h"
DECLARE_MULTICAST_DELEGATE(FThreadTaskDelegate);
UCLASS(HideDropdown, Blueprintable, hidecategories = (Object), meta = (DontUseGenericSpawnObject = "true"))
class MULTITHREADLIBRARY_API UThreadTasks : public UThreadTaskBase
{
GENERATED_BODY()
public:
virtual bool Start() override;
/**
* Called on Background Thread when the Task is executed.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, meta = (DisplayName = "Task Body"), Category = "MultiThreadLibrary")
void TaskBody();
virtual void TaskBody_Implementation();
public:
FThreadTaskDelegate TaskDelegate;
protected:
};
class MULTITHREADLIBRARY_API FThreadTaskOnly : public FTaskActionBase
{
ETaskResultBranches& Branches;
bool bStarted;
public:
FThreadTaskOnly(UObject* InObject, ETaskResultBranches& InBranches, const FLatentActionInfo& LatentInfo, TSubclassOf<class UThreadTasks> TaskClass, UThreadBase*& OutTask)
: FTaskActionBase(InObject, LatentInfo, TaskClass)
, Branches(InBranches)
, bStarted(false)
{
OutTask = Task;
UThreadTasks* LocalTask = Cast<UThreadTasks>(Task);
if (LocalTask)
{
Branches = ETaskResultBranches::OnStart;
LocalTask->BodyFunction();
bStarted = Task->Start();
}
else {
return;
}
}
virtual void UpdateOperation(FLatentResponse& Response) override
{
if (bStarted)
{
if (!IsCanceled())
{
if (!IsRunning())
{
Branches = ETaskResultBranches::OnCompleted;
Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);
}
}
else
{
Branches = ETaskResultBranches::OnCanceled;
Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);
}
}
else {
//If we reached this point it means the task was unable to start.
Branches = ETaskResultBranches::OnCompleted;
Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);
}
}
};
class MULTITHREADLIBRARY_API FThreadTaskWithBody : public FTaskActionBase
{
EtaskExecutionBranches& Branches;
bool bStarted;
public:
FThreadTaskWithBody(UObject* InObject, EtaskExecutionBranches& InBranches, const FLatentActionInfo& LatentInfo, TSubclassOf<class UThreadTasks> TaskClass, const ETaskExecutionType& InExecutionType, UThreadBase*& OutTask)
: FTaskActionBase(InObject, LatentInfo, TaskClass)
, Branches(InBranches)
, bStarted(false)
{
OutTask = Task;
UThreadTasks* LocalTask = Cast<UThreadTasks>(Task);
if (LocalTask)
{
Branches = EtaskExecutionBranches::OnStart;
LocalTask->BodyFunction();
LocalTask->TaskDelegate.AddLambda([LocalTask, &InBranches]
{
InBranches = EtaskExecutionBranches::OnTaskBody;
LocalTask->BodyFunction();
});
LocalTask->OnCancelDelegate.AddLambda([LocalTask, &InBranches]
{
InBranches = EtaskExecutionBranches::OnCanceled;
LocalTask->BodyFunction();
});
bStarted = Task->Start();
}
else {
return;
}
}
virtual ~FThreadTaskWithBody()
{
if (Task != nullptr && Task->IsValidLowLevel() && IsValid(Task) && !Task->IsUnreachable())
{
UThreadTasks* LocalTask = Cast<UThreadTasks>(Task);
if (LocalTask)
{
LocalTask->TaskDelegate.RemoveAll(this);
LocalTask->OnCancelDelegate.RemoveAll(this);
}
}
}
virtual void UpdateOperation(FLatentResponse& Response) override
{
if (bStarted)
{
if (!IsCanceled())
{
if (!IsRunning())
{
Branches = EtaskExecutionBranches::OnCompleted;
Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);
}
}
else
{
Response.DoneIf(true);
}
}
else {
//If we reached this point it means the task was unable to start.
Branches = EtaskExecutionBranches::OnCompleted;
Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);
}
}
};