Files
UnrealEngine/Engine/Plugins/Experimental/SceneState/Source/SceneStateMachineGraph/Private/Nodes/SceneStateMachineTaskNode.cpp
2025-05-18 13:04:45 +08:00

262 lines
6.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Nodes/SceneStateMachineTaskNode.h"
#include "SceneStateBindingDelegates.h"
#include "SceneStateBindingUtils.h"
#include "SceneStateMachineGraphSchema.h"
#include "SceneStateUtils.h"
#include "Tasks/SceneStateBlueprintableTask.h"
#include "Tasks/SceneStateBlueprintableTaskWrapper.h"
#include "Tasks/SceneStateTaskBindingExtension.h"
#include "Tasks/SceneStateTaskDesc.h"
#include "Tasks/SceneStateTaskDescRegistry.h"
#define LOCTEXT_NAMESPACE "SceneStateMachineTaskNode"
USceneStateMachineTaskNode::USceneStateMachineTaskNode()
{
NodeName = TEXT("Task");
NodeType = UE::SceneState::Graph::EStateMachineNodeType::Task;
bCanRenameNode = false;
UE::SceneState::OnStructIdChanged.AddUObject(this, &USceneStateMachineTaskNode::OnStructIdChanged);
}
bool USceneStateMachineTaskNode::SetTaskStruct(const UScriptStruct* InTaskStruct)
{
if (Task.GetScriptStruct() != InTaskStruct)
{
if (InTaskStruct)
{
Task.InitializeAsScriptStruct(InTaskStruct);
}
else
{
Task.Reset();
}
OnTaskTypeChanged();
return true;
}
return false;
}
void USceneStateMachineTaskNode::SetTaskBlueprintClass(TSubclassOf<USceneStateBlueprintableTask> InTaskClass)
{
bool bTaskChanged = false;
if (Task.GetScriptStruct() != FSceneStateBlueprintableTaskWrapper::StaticStruct())
{
Task.InitializeAsScriptStruct(FSceneStateBlueprintableTaskWrapper::StaticStruct());
bTaskChanged = true;
}
FSceneStateBlueprintableTaskWrapper& TaskWrapper = Task.GetMutable<FSceneStateBlueprintableTaskWrapper>();
bTaskChanged |= TaskWrapper.SetTaskClass(InTaskClass);
if (bTaskChanged)
{
OnTaskTypeChanged();
}
}
bool USceneStateMachineTaskNode::FindDataViewById(const FGuid& InStructId, FStructView& OutDataView)
{
if (TaskId == InStructId)
{
OutDataView = GetTaskInstance();
return true;
}
const FSceneStateTask* ResolvedTask = Task.GetPtr<FSceneStateTask>();
if (!ResolvedTask)
{
return false;
}
if (const FSceneStateTaskBindingExtension* BindingExtension = ResolvedTask->GetBindingExtension())
{
uint16 DataIndex;
return BindingExtension->FindDataById(GetTaskInstance(), InStructId, OutDataView, /*out*/DataIndex);
}
return false;
}
void USceneStateMachineTaskNode::AllocateDefaultPins()
{
CreatePin(EGPD_Input, USceneStateMachineGraphSchema::PC_Task, USceneStateMachineGraphSchema::PN_In);
CreatePin(EGPD_Output, USceneStateMachineGraphSchema::PC_Task, USceneStateMachineGraphSchema::PN_Out);
// Hide pins that should be hidden
HidePins(MakeArrayView(&USceneStateMachineGraphSchema::PN_In, 1));
}
FText USceneStateMachineTaskNode::GetNodeTitle(ENodeTitleType::Type InTitleType) const
{
if (CachedNodeTitle.IsEmpty())
{
if (Task.IsValid())
{
const FSceneStateTaskDesc& TaskDesc = FSceneStateTaskDescRegistry::Get().GetTaskDesc(Task.GetScriptStruct());
const FSceneStateTaskDescContext Context = MakeContext();
FText Tooltip = TaskDesc.GetTooltip(Context);
if (!Tooltip.IsEmpty())
{
Tooltip = FText::Format(INVTEXT("\n{0}"), Tooltip);
}
CachedNodeTitle = FText::Format(LOCTEXT("NodeTitle", "{0}{1}"), TaskDesc.GetDisplayName(Context), Tooltip);
}
else
{
CachedNodeTitle = LOCTEXT("NodeTitle_InvalidTaskClass", "Invalid Task Class");
}
}
return CachedNodeTitle;
}
FText USceneStateMachineTaskNode::GetTooltipText() const
{
const FSceneStateTaskDesc& TaskDesc = FSceneStateTaskDescRegistry::Get().GetTaskDesc(Task.GetScriptStruct());
return TaskDesc.GetTooltip(MakeContext());
}
bool USceneStateMachineTaskNode::CanDuplicateNode() const
{
return true;
}
void USceneStateMachineTaskNode::PostPasteNode()
{
Super::PostPasteNode();
GenerateNewTaskId();
}
UObject* USceneStateMachineTaskNode::GetJumpTargetForDoubleClick() const
{
const FSceneStateTaskDesc& TaskDesc = FSceneStateTaskDescRegistry::Get().GetTaskDesc(Task.GetScriptStruct());
return TaskDesc.GetJumpTarget(MakeContext());
}
void USceneStateMachineTaskNode::PostLoad()
{
Super::PostLoad();
// Hide pins that should be hidden
HidePins(MakeArrayView(&USceneStateMachineGraphSchema::PN_In, 1));
}
void USceneStateMachineTaskNode::BeginDestroy()
{
Super::BeginDestroy();
UE::SceneState::OnStructIdChanged.RemoveAll(this);
}
void USceneStateMachineTaskNode::PostEditChangeProperty(FPropertyChangedEvent& InPropertyChangedEvent)
{
Super::PostEditChangeProperty(InPropertyChangedEvent);
CachedNodeTitle = FText::GetEmpty();
if (InPropertyChangedEvent.GetMemberPropertyName() == GET_MEMBER_NAME_CHECKED(USceneStateMachineTaskNode, Task))
{
OnTaskTypeChanged();
}
OnPostEditTaskDelegate.Broadcast();
}
void USceneStateMachineTaskNode::PostDuplicate(bool bInDuplicateForPIE)
{
Super::PostDuplicate(bInDuplicateForPIE);
if (!bInDuplicateForPIE)
{
GenerateNewTaskId();
RebuildTaskInstance();
}
}
void USceneStateMachineTaskNode::PostEditImport()
{
Super::PostEditImport();
GenerateNewTaskId();
RebuildTaskInstance();
}
FSceneStateTaskDescContext USceneStateMachineTaskNode::MakeContext() const
{
FSceneStateTaskDescContext Context;
Context.Task = Task;
Context.TaskInstance = TaskInstance;
Context.ContextObject = this;
return Context;
}
FSceneStateTaskDescMutableContext USceneStateMachineTaskNode::MakeMutableContext()
{
FSceneStateTaskDescMutableContext Context;
Context.Task = Task;
Context.TaskInstance = TaskInstance;
Context.ContextObject = this;
return Context;
}
void USceneStateMachineTaskNode::RebuildTaskInstance()
{
if (const FSceneStateTask* ResolvedTask = Task.GetPtr<FSceneStateTask>())
{
FStructView TaskInstanceView(TaskInstance.GetScriptStruct(), TaskInstance.GetMutableMemory());
ResolvedTask->BuildTaskInstance(this, TaskInstanceView);
}
}
void USceneStateMachineTaskNode::OnTaskTypeChanged()
{
if (const FSceneStateTask* ResolvedTask = Task.GetPtr<FSceneStateTask>())
{
if (const UScriptStruct* InstanceDataType = ResolvedTask->GetTaskInstanceType())
{
if (TaskInstance.GetScriptStruct() != InstanceDataType)
{
TaskInstance.InitializeAsScriptStruct(InstanceDataType);
FStructView TaskInstanceView(TaskInstance.GetScriptStruct(), TaskInstance.GetMutableMemory());
ResolvedTask->BuildTaskInstance(this, TaskInstanceView);
}
}
else
{
TaskInstance.Reset();
}
}
else
{
TaskInstance.Reset();
}
}
void USceneStateMachineTaskNode::OnStructIdChanged(const UE::SceneState::FStructIdChange& InChange)
{
// Only consider changes if they come from a binding owner that contains this task node
if (IsIn(InChange.BindingOwner))
{
const FSceneStateTaskDesc& TaskDesc = FSceneStateTaskDescRegistry::Get().GetTaskDesc(Task.GetScriptStruct());
TaskDesc.NotifyStructIdsChanged(MakeMutableContext(), InChange);
}
}
void USceneStateMachineTaskNode::GenerateNewTaskId()
{
const FGuid OldTaskId = TaskId;
TaskId = FGuid::NewGuid();
UE::SceneState::HandleStructIdChanged(*this, OldTaskId, TaskId);
}
#undef LOCTEXT_NAMESPACE