Files
UnrealEngine/Engine/Plugins/Mutable/Source/CustomizableObjectEditor/Private/MuCOE/CustomizableObjectGraph.cpp
2025-05-18 13:04:45 +08:00

231 lines
6.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MuCOE/CustomizableObjectGraph.h"
#include "CustomizableObjectSchemaActions.h"
#include "MuCO/CustomizableObjectCustomVersion.h"
#include "MuCOE/EdGraphSchema_CustomizableObject.h"
#include "MuCOE/Nodes/CustomizableObjectNodeObject.h"
#include "MuCOE/Nodes/CustomizableObjectNodeTunnel.h"
class UObject;
UCustomizableObjectGraph::UCustomizableObjectGraph()
: Super()
{
Schema = UEdGraphSchema_CustomizableObject::StaticClass();
}
void UCustomizableObjectGraph::PostLoad()
{
Super::PostLoad();
// TODO UE-222779 If compatibility code has to be executed, loaded the full hierarchy and in sync the BackwardsCompatibleFixup
// Make sure all nodes have finished loading.
for (UEdGraphNode* Node : Nodes)
{
if (UCustomizableObjectNode* CustomizableObjectNode = Cast<UCustomizableObjectNode>(Node))
{
CustomizableObjectNode->ConditionalPostLoad();
}
}
// Remove any null links
//
// Links can become null if the node they're linked to can't be loaded
for (UEdGraphNode* Node : Nodes)
{
for (UEdGraphPin* Pin : Node->Pins)
{
Pin->LinkedTo.RemoveAll([](UEdGraphPin* Other) { return Other == nullptr; });
}
}
}
void UCustomizableObjectGraph::BackwardsCompatibleFixup(int32 CustomizableObjectCustomVersion)
{
TArray<TObjectPtr<UEdGraphNode>> NodesCopy = Nodes; // Copy to be able to remove nodes inside the BackwardsCompatibleFixup.
for (UEdGraphNode* Node : NodesCopy)
{
if (UCustomizableObjectNode* CustomizableObjectNode = Cast<UCustomizableObjectNode>(Node))
{
TArray<UEdGraphPin*> PinsCopy = CustomizableObjectNode->GetAllPins(); // Copy to be able to remove pins inside the BackwardsCompatibleFixup.
for (UEdGraphPin* Pin : PinsCopy)
{
if (!Pin)
{
continue;
}
UCustomizableObjectNodePinData* PinData = CustomizableObjectNode->GetPinData(*Pin);
if (!PinData)
{
continue;
}
PinData->BackwardsCompatibleFixup(CustomizableObjectCustomVersion);
}
CustomizableObjectNode->BackwardsCompatibleFixup(CustomizableObjectCustomVersion);
}
}
}
void UCustomizableObjectGraph::PostBackwardsCompatibleFixup()
{
// Do any additional work which require nodes to be valid (i.e., have executed BackwardsCompatibleFixup).
TArray<TObjectPtr<UEdGraphNode>> NodesCopy = Nodes; // Copy to be able to remove nodes inside the PostBackwardsCompatibleFixup.
for (UEdGraphNode* Node : NodesCopy)
{
if (UCustomizableObjectNode* CustomizableObjectNode = Cast<UCustomizableObjectNode>(Node))
{
CustomizableObjectNode->PostBackwardsCompatibleFixup();
}
}
}
void UCustomizableObjectGraph::NotifyNodeIdChanged(const FGuid& OldGuid, const FGuid& NewGuid)
{
NotifiedNodeIdsMap.FindOrAdd(OldGuid) = NewGuid;
if (TSet<FGuid>* NodesToNotify = NodesToNotifyMap.Find(OldGuid))
{
for (FGuid& NodeId : *NodesToNotify)
{
for (int32 i = 0; i < Nodes.Num(); ++i)
{
if (Nodes[i]->NodeGuid == NodeId)
{
if (UCustomizableObjectNode* Node = Cast<UCustomizableObjectNode>(Nodes[i]))
{
Node->UpdateReferencedNodeId(NewGuid);
}
}
}
}
NodesToNotify->Empty();
}
}
FGuid UCustomizableObjectGraph::RequestNotificationForNodeIdChange(const FGuid& OldGuid, const FGuid& NodeToNotifyGuid)
{
if (const FGuid* Value = NotifiedNodeIdsMap.Find(OldGuid))
{
return *Value;
}
NodesToNotifyMap.FindOrAdd(OldGuid).Add(NodeToNotifyGuid);
return OldGuid;
}
void UCustomizableObjectGraph::PostRename(UObject* OldOuter, const FName OldName)
{
// Regenerate the Base Object Guid
TArray<UCustomizableObjectNodeObject*> ObjectNodes;
GetNodesOfClass<UCustomizableObjectNodeObject>(ObjectNodes);
for (UCustomizableObjectNodeObject* ObjectNode : ObjectNodes)
{
if (ObjectNode->bIsBase)
{
ObjectNode->Identifier = FGuid::NewGuid();
break;
}
}
}
void UCustomizableObjectGraph::PostDuplicate(bool bDuplicateForPIE)
{
// In BeginPostDuplicate, nodes can call RequestNotificationForNodeIdChange
for (UEdGraphNode* Node : Nodes)
{
if (UCustomizableObjectNode* CustomizableObjectNode = Cast<UCustomizableObjectNode>(Node))
{
CustomizableObjectNode->BeginPostDuplicate(bDuplicateForPIE);
}
}
TMap<FGuid, FGuid> NewGuids;
for (UEdGraphNode* Node : Nodes)
{
// Generate new Guid
const FGuid NewGuid = FGuid::NewGuid();
NewGuids.Add(Node->NodeGuid) = NewGuid;
// Notify Guid is going to change. Recive the new Guid
NotifyNodeIdChanged(Node->NodeGuid, NewGuid);
}
// Chenge all nodes Guids
for (UEdGraphNode* Node : Nodes)
{
Node->NodeGuid = NewGuids[Node->NodeGuid];
}
Super::PostDuplicate(bDuplicateForPIE);
}
void UCustomizableObjectGraph::AddEssentialGraphNodes()
{
if (!IsMacro())
{
// Check whether the graph has a base node and create one if it doesn't since it is required
bool bGraphHasBase = false;
for (const TObjectPtr<UEdGraphNode>& AuxNode : Nodes)
{
UCustomizableObjectNodeObject* CustomizableObjectNodeObject = Cast<UCustomizableObjectNodeObject>(AuxNode);
if (CustomizableObjectNodeObject && CustomizableObjectNodeObject->bIsBase)
{
bGraphHasBase = true;
break;
}
}
if (!bGraphHasBase)
{
UCustomizableObjectNodeObject* NodeTemplate = NewObject<UCustomizableObjectNodeObject>();
FCustomizableObjectSchemaAction_NewNode::CreateNode(this, nullptr, FVector2D::ZeroVector, Cast<UEdGraphNode>(NodeTemplate));
}
}
else
{
UCustomizableObjectMacro* ParentMacro = Cast<UCustomizableObjectMacro>(GetOuter());
check(ParentMacro);
UCustomizableObjectNodeTunnel* InputNode = NewObject<UCustomizableObjectNodeTunnel>();
InputNode->bIsInputNode = true;
InputNode->ParentMacro = ParentMacro;
UCustomizableObjectNodeTunnel* OutputNode = NewObject<UCustomizableObjectNodeTunnel>();
OutputNode->bIsInputNode = false;
OutputNode->ParentMacro = ParentMacro;
FVector2D InputNodePos = FVector2D(-100.0f, 0.0f);
FVector2D OutputNodePos = FVector2D(100.0f, 0.0f);
FCustomizableObjectSchemaAction_NewNode::CreateNode(this, nullptr, InputNodePos, Cast<UEdGraphNode>(InputNode));
FCustomizableObjectSchemaAction_NewNode::CreateNode(this, nullptr, OutputNodePos, Cast<UEdGraphNode>(OutputNode));
}
}
bool UCustomizableObjectGraph::IsMacro() const
{
UObject* Outer = GetOuter();
check(Outer);
return Cast<UCustomizableObjectMacro>(Outer) != nullptr;
}