Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

336 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimNextController.h"
#include "RigVMPythonUtils.h"
#include "AnimGraphUncookedOnlyUtils.h"
#include "AnimNextTraitStackUnitNode.h"
#include "Graph/RigDecorator_AnimNextCppTrait.h"
#include "Param/ParamType.h"
#include "RigVMModel/RigVMControllerActions.h"
#include "TraitCore/Trait.h"
#include "TraitCore/TraitRegistry.h"
#include "TraitCore/TraitUID.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(AnimNextController)
FName UAnimNextController::AddTraitStruct(URigVMUnitNode* InNode, const TInstancedStruct<FAnimNextTraitSharedData>& InTraitDefaults, int32 InTraitIndex, bool bSetupUndoRedo, bool bPrintPythonCommand)
{
if (!IsValidGraph())
{
return NAME_None;
}
if (!IsTransacting() && !IsGraphEditable())
{
return NAME_None;
}
const URigVMGraph* Graph = GetGraph();
check(Graph);
if (InNode == nullptr)
{
ReportError(TEXT("Invalid node supplied to AddTraitStruct."));
return NAME_None;
}
UE::UAF::FTraitRegistry& TraitRegistry = UE::UAF::FTraitRegistry::Get();
const UE::UAF::FTrait* Trait = TraitRegistry.Find(InTraitDefaults.GetScriptStruct());
if (Trait == nullptr)
{
ReportError(TEXT("Unknown Trait Type."));
return NAME_None;
}
UScriptStruct* CppDecoratorStruct = FRigDecorator_AnimNextCppDecorator::StaticStruct();
const FRigDecorator_AnimNextCppDecorator DefaultCppDecoratorStructInstance;
FRigDecorator_AnimNextCppDecorator CppDecoratorStructInstance;
CppDecoratorStructInstance.DecoratorSharedDataStruct = const_cast<UScriptStruct*>(InTraitDefaults.GetScriptStruct()); // TODO: Refactor const here
if (!CppDecoratorStructInstance.CanBeAddedToNode(InNode, nullptr))
{
ReportError(TEXT("Trait is not supported by the Node."));
return NAME_None; // This trait isn't supported on this node
}
FString DefaultValue;
FRigDecorator_AnimNextCppDecorator::StaticStruct()->ExportText(DefaultValue, &CppDecoratorStructInstance, &DefaultCppDecoratorStructInstance, nullptr, PPF_SerializedAsImportText, nullptr);
// Avoid multiple VM recompilations for internal operations
FRigVMControllerCompileBracketScope CompileScope(this);
// Must use struct name for name to allow for consistent pathing in node layouts
const FName TraitName = InTraitDefaults.GetScriptStruct()->GetFName();
FName NewTraitName = Super::AddTrait(InNode, CppDecoratorStruct, TraitName, DefaultValue, InTraitIndex, bSetupUndoRedo);
if (NewTraitName != NAME_None)
{
// Append defaults for shared data
FString TraitDefaultValue;
InTraitDefaults.GetScriptStruct()->ExportText(TraitDefaultValue, InTraitDefaults.GetMemory(), InTraitDefaults.GetMemory(), nullptr, PPF_SerializedAsImportText, nullptr);
URigVMPin* TraitPin = InNode->FindPin(NewTraitName.ToString());
TArray<FString> MemberValuePairs = URigVMPin::SplitDefaultValue(TraitDefaultValue);
for (const FString& MemberValuePair : MemberValuePairs)
{
FString MemberName, MemberValue;
if (MemberValuePair.Split(TEXT("="), &MemberName, &MemberValue))
{
if (URigVMPin* SubPin = TraitPin->FindSubPin(MemberName))
{
if(!MemberValue.IsEmpty())
{
PostProcessDefaultValue(SubPin, MemberValue);
if (!MemberValue.IsEmpty())
{
SetPinDefaultValue(SubPin, MemberValue, true, true, true, true);
}
}
}
}
}
}
return TraitName;
}
FName UAnimNextController::AddTraitByName(FName InNodeName, FName InNewTraitTypeName, int32 InPinIndex, const FString& InNewTraitDefaultValue, bool bSetupUndoRedo, bool bPrintPythonCommand)
{
if (!IsValidGraph())
{
return NAME_None;
}
if (!IsTransacting() && !IsGraphEditable())
{
return NAME_None;
}
if (InNodeName == NAME_None)
{
ReportError(TEXT("Invalid node name."));
return NAME_None;
}
const URigVMGraph* Graph = GetGraph();
check(Graph);
URigVMNode * Node = Graph->FindNodeByName(InNodeName);
if (Node == nullptr)
{
ReportError(TEXT("This graph does not contain a node with the provided name."));
return NAME_None;
}
UE::UAF::FTraitRegistry& TraitRegistry = UE::UAF::FTraitRegistry::Get();
const UE::UAF::FTrait* Trait = TraitRegistry.Find(InNewTraitTypeName);
if (Trait == nullptr)
{
ReportError(TEXT("Unknown Trait Type."));
return NAME_None;
}
const UScriptStruct* CppDecoratorStruct = FRigDecorator_AnimNextCppDecorator::StaticStruct();
UScriptStruct* ScriptStruct = Trait->GetTraitSharedDataStruct();
FString DefaultValue = InNewTraitDefaultValue;
if (DefaultValue.IsEmpty())
{
const FRigDecorator_AnimNextCppDecorator DefaultCppDecoratorStructInstance;
FRigDecorator_AnimNextCppDecorator CppDecoratorStructInstance;
CppDecoratorStructInstance.DecoratorSharedDataStruct = ScriptStruct;
if (!CppDecoratorStructInstance.CanBeAddedToNode(Node, nullptr))
{
ReportError(TEXT("Trait is not supported by the Node."));
return NAME_None; // This trait isn't supported on this node
}
FRigDecorator_AnimNextCppDecorator::StaticStruct()->ExportText(DefaultValue, &CppDecoratorStructInstance, &DefaultCppDecoratorStructInstance, nullptr, PPF_SerializedAsImportText, nullptr);
}
// Avoid multiple VM recompilations for internal operations
FRigVMControllerCompileBracketScope CompileScope(this);
// Must use struct name for name to allow for consistent pathing in node layouts
const FName TraitName = ScriptStruct->GetFName();
return AddTrait(InNodeName, *CppDecoratorStruct->GetPathName(), TraitName, DefaultValue, InPinIndex, bSetupUndoRedo, bPrintPythonCommand);
}
bool UAnimNextController::RemoveTraitByName(FName InNodeName, FName InTraitInstanceName, bool bSetupUndoRedo, bool bPrintPythonCommand)
{
if (!IsValidGraph())
{
return false;
}
if (!IsTransacting() && !IsGraphEditable())
{
return false;
}
if (InNodeName == NAME_None)
{
ReportError(TEXT("Invalid node name."));
return false;
}
// Avoid multiple VM recompilations for internal operations
FRigVMControllerCompileBracketScope CompileScope(this);
return RemoveTrait(InNodeName, InTraitInstanceName, bSetupUndoRedo, bPrintPythonCommand);
}
FName UAnimNextController::SwapTraitByName(FName InNodeName, FName InTraitInstanceName, int32 InCurrentTraitPinIndex, FName InNewTraitTypeName, const FString& InNewTraitDefaultValue, bool bSetupUndoRedo, bool bPrintPythonCommand)
{
if (!IsValidGraph())
{
return NAME_None;
}
if (!IsTransacting() && !IsGraphEditable())
{
return NAME_None;
}
if (InNodeName == NAME_None)
{
ReportError(TEXT("Invalid node name."));
return NAME_None;
}
// Avoid multiple VM recompilations, for each operation
FRigVMControllerCompileBracketScope CompileScope(this);
if (RemoveTraitByName(InNodeName, InTraitInstanceName, bSetupUndoRedo, bPrintPythonCommand))
{
return AddTraitByName(InNodeName, InNewTraitTypeName, InCurrentTraitPinIndex, InNewTraitDefaultValue, bSetupUndoRedo, bPrintPythonCommand);
}
return NAME_None;
}
bool UAnimNextController::SetTraitPinIndex(FName InNodeName, FName InTraitInstanceName, int32 InNewPinIndex, bool bSetupUndoRedo, bool bPrintPythonCommand)
{
if (!IsValidGraph())
{
return false;
}
if (!IsTransacting() && !IsGraphEditable())
{
return false;
}
if (InNodeName == NAME_None)
{
ReportError(TEXT("Invalid node name."));
return false;
}
const URigVMGraph* Graph = GetGraph();
check(Graph);
URigVMNode* Node = Graph->FindNodeByName(InNodeName);
if (Node == nullptr)
{
ReportError(TEXT("This graph does not contain a node with the provided name."));
return false;
}
if (!IsTransacting() && !IsGraphEditable())
{
return false;
}
URigVMPin* TraitPin = Node->FindTrait(InTraitInstanceName);
if (TraitPin == nullptr)
{
ReportError(TEXT("The node does not contain a Trait with the provided name."));
return false;
}
// Save current pin data for later
const FString TraitDefaultValue = TraitPin->GetDefaultValue();
// TODO zzz : Is there a better way to get a Trait* from a TraitPin ?
if (TSharedPtr<FStructOnScope> ScopedTrait = Node->GetTraitInstance(TraitPin->GetFName()))
{
const FRigVMTrait* Trait = (FRigVMTrait*)ScopedTrait->GetStructMemory();
if (const UScriptStruct* TraitSharedInstanceData = Trait->GetTraitSharedDataStruct())
{
UE::UAF::FTraitRegistry& TraitRegistry = UE::UAF::FTraitRegistry::Get();
if (const UE::UAF::FTrait* AnimNextTrait = TraitRegistry.Find(TraitSharedInstanceData))
{
// Avoid multiple VM recompilations, for each operation
FRigVMControllerCompileBracketScope CompileScope(this);
const int32 TraitPinInitialIndex = TraitPin->GetPinIndex();
if (RemoveTraitByName(InNodeName, InTraitInstanceName, bSetupUndoRedo, bPrintPythonCommand))
{
// Adjust indices due to pin removal
if (TraitPinInitialIndex < InNewPinIndex)
{
--InNewPinIndex;
}
// TOOO zzz : Why TraitName is a string ?
if (AddTraitByName(InNodeName, FName(AnimNextTrait->GetTraitName()), InNewPinIndex, TraitDefaultValue, bSetupUndoRedo, bPrintPythonCommand) != NAME_None)
{
return true;
}
}
}
}
}
return false;
}
URigVMUnitNode* UAnimNextController::AddUnitNodeWithPins(UScriptStruct* InScriptStruct, const FRigVMPinInfoArray& PinArray, const FName& InMethodName, const FVector2D& InPosition, const FString& InNodeName, bool bSetupUndoRedo, bool bPrintPythonCommand)
{
const bool bHasDynamicPins = PinArray.Num() != 0;
if (bHasDynamicPins)
{
OpenUndoBracket(TEXT("Add unit node with pins"));
}
URigVMUnitNode* Node = AddUnitNode(InScriptStruct, UAnimNextUnitNode::StaticClass(), InMethodName, InPosition, InNodeName, bSetupUndoRedo, bPrintPythonCommand);
if (Node == nullptr)
{
if (bHasDynamicPins)
{
CancelUndoBracket();
}
return nullptr;
}
if (bHasDynamicPins)
{
const FRigVMRegistry& Registry = FRigVMRegistry::Get();
const FRigVMPinInfoArray PreviousPins(Node, this);
for (int32 PinIndex = 0; PinIndex < PinArray.Num(); ++PinIndex)
{
const FString& PinPath = PinArray.GetPinPath(PinIndex);
FString ParentPinPath, PinName;
UObject* OuterForPin = Node;
if (URigVMPin::SplitPinPathAtEnd(PinPath, ParentPinPath, PinName))
{
OuterForPin = Node->FindPin(ParentPinPath);
}
CreatePinFromPinInfo(Registry, PreviousPins, PinArray[PinIndex], PinPath, OuterForPin);
}
CloseUndoBracket();
}
return Node;
}