2019-12-27 09:26:59 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
2019-01-08 11:38:48 -05:00
|
|
|
|
|
|
|
|
#include "ControlRigBlueprint.h"
|
2021-03-25 16:51:36 -04:00
|
|
|
|
2019-01-08 11:38:48 -05:00
|
|
|
#include "ControlRigBlueprintGeneratedClass.h"
|
|
|
|
|
#include "EdGraph/EdGraph.h"
|
2019-05-31 18:25:32 -04:00
|
|
|
#include "EdGraphNode_Comment.h"
|
2019-01-08 11:38:48 -05:00
|
|
|
#include "Modules/ModuleManager.h"
|
|
|
|
|
#include "Engine/SkeletalMesh.h"
|
|
|
|
|
#include "BlueprintActionDatabaseRegistrar.h"
|
2019-05-21 19:25:23 -04:00
|
|
|
#include "ControlRig.h"
|
|
|
|
|
#include "Graph/ControlRigGraph.h"
|
|
|
|
|
#include "Graph/ControlRigGraphNode.h"
|
2020-12-14 08:58:12 -04:00
|
|
|
#include "Graph/ControlRigGraphSchema.h"
|
2021-03-25 16:51:36 -04:00
|
|
|
#include "UObject/ObjectSaveContext.h"
|
2019-09-17 19:12:19 -04:00
|
|
|
#include "UObject/UObjectGlobals.h"
|
2020-01-22 17:58:55 -05:00
|
|
|
#include "ControlRigObjectVersion.h"
|
|
|
|
|
#include "ControlRigDeveloper.h"
|
|
|
|
|
#include "Curves/CurveFloat.h"
|
|
|
|
|
#include "BlueprintCompilationManager.h"
|
|
|
|
|
#include "RigVMCompiler/RigVMCompiler.h"
|
|
|
|
|
#include "RigVMCore/RigVMRegistry.h"
|
|
|
|
|
#include "Units/Execution/RigUnit_BeginExecution.h"
|
2020-09-24 00:43:27 -04:00
|
|
|
#include "Units/Hierarchy/RigUnit_SetBoneTransform.h"
|
|
|
|
|
#include "Async/TaskGraphInterfaces.h"
|
|
|
|
|
#include "Misc/CoreDelegates.h"
|
2022-05-02 18:59:38 -04:00
|
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
2021-07-19 06:35:29 -04:00
|
|
|
#include "RigVMPythonUtils.h"
|
2021-11-18 08:00:07 -05:00
|
|
|
#include "RigVMTypeUtils.h"
|
2022-05-31 04:27:20 -04:00
|
|
|
#include "Algo/Count.h"
|
|
|
|
|
#include "Algo/Transform.h"
|
2022-03-30 05:21:45 -04:00
|
|
|
#include "RigVMModel/Nodes/RigVMAggregateNode.h"
|
2022-04-05 10:42:37 -04:00
|
|
|
#include "Units/ControlRigNodeWorkflow.h"
|
|
|
|
|
#include "Rigs/RigControlHierarchy.h"
|
2019-01-08 11:38:48 -05:00
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
#include "IControlRigEditorModule.h"
|
2021-08-16 23:19:04 -04:00
|
|
|
#include "Kismet2/KismetDebugUtilities.h"
|
2021-10-25 20:05:28 -04:00
|
|
|
#include "Kismet2/WatchedPin.h"
|
2019-05-21 19:25:23 -04:00
|
|
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
|
|
|
#include "ControlRigBlueprintUtils.h"
|
2019-09-17 19:12:19 -04:00
|
|
|
#include "Settings/ControlRigSettings.h"
|
2020-08-11 01:36:57 -04:00
|
|
|
#include "UnrealEdGlobals.h"
|
|
|
|
|
#include "Editor/UnrealEdEngine.h"
|
|
|
|
|
#include "CookOnTheSide/CookOnTheFlyServer.h"
|
2021-01-19 07:26:41 -04:00
|
|
|
#include "Widgets/Notifications/SNotificationList.h"
|
|
|
|
|
#include "Framework/Notifications/NotificationManager.h"
|
2022-05-31 04:27:20 -04:00
|
|
|
#include "ScopedTransaction.h"
|
2019-01-08 11:38:48 -05:00
|
|
|
#endif//WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "ControlRigBlueprint"
|
|
|
|
|
|
2022-05-31 16:55:43 -04:00
|
|
|
static TArray<UClass*> GetClassObjectsInPackage(UPackage* InPackage)
|
|
|
|
|
{
|
|
|
|
|
TArray<UObject*> Objects;
|
|
|
|
|
GetObjectsWithOuter(InPackage, Objects, false);
|
|
|
|
|
|
|
|
|
|
TArray<UClass*> ClassObjects;
|
|
|
|
|
for (UObject* Object : Objects)
|
|
|
|
|
{
|
|
|
|
|
if (UClass* Class = Cast<UClass>(Object))
|
|
|
|
|
{
|
|
|
|
|
ClassObjects.Add(Class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ClassObjects;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 14:44:58 -04:00
|
|
|
FEdGraphPinType FControlRigPublicFunctionArg::GetPinType() const
|
|
|
|
|
{
|
|
|
|
|
FRigVMExternalVariable Variable;
|
|
|
|
|
Variable.Name = Name;
|
|
|
|
|
Variable.bIsArray = bIsArray;
|
|
|
|
|
Variable.TypeName = CPPType;
|
|
|
|
|
|
|
|
|
|
if(CPPTypeObjectPath.IsValid())
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeObject = URigVMPin::FindObjectFromCPPTypeObjectPath(CPPTypeObjectPath.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 08:00:07 -05:00
|
|
|
return RigVMTypeUtils::PinTypeFromExternalVariable(Variable);
|
2021-03-03 14:44:58 -04:00
|
|
|
}
|
|
|
|
|
|
2021-11-03 12:01:42 -04:00
|
|
|
bool FControlRigPublicFunctionData::IsMutable() const
|
|
|
|
|
{
|
|
|
|
|
for(const FControlRigPublicFunctionArg& Arg : Arguments)
|
|
|
|
|
{
|
|
|
|
|
if(!Arg.CPPTypeObjectPath.IsNone())
|
|
|
|
|
{
|
|
|
|
|
if(UScriptStruct* Struct = Cast<UScriptStruct>(
|
|
|
|
|
URigVMPin::FindObjectFromCPPTypeObjectPath(Arg.CPPTypeObjectPath.ToString())))
|
|
|
|
|
{
|
|
|
|
|
if(Struct->IsChildOf(FRigVMExecuteContext::StaticStruct()))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
TArray<UControlRigBlueprint*> UControlRigBlueprint::sCurrentlyOpenedRigBlueprints;
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprint::UControlRigBlueprint(const FObjectInitializer& ObjectInitializer)
|
2019-01-08 11:38:48 -05:00
|
|
|
{
|
2019-05-21 19:25:23 -04:00
|
|
|
bSuspendModelNotificationsForSelf = false;
|
|
|
|
|
bSuspendModelNotificationsForOthers = false;
|
2020-09-24 00:43:27 -04:00
|
|
|
bSuspendAllNotifications = false;
|
2022-05-31 04:27:20 -04:00
|
|
|
bSuspendPythonMessagesForRigVMClient = true;
|
2019-09-17 19:12:19 -04:00
|
|
|
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
2021-10-20 11:56:18 -04:00
|
|
|
GizmoLibrary_DEPRECATED = nullptr;
|
|
|
|
|
ShapeLibraries.Add(UControlRigSettings::Get()->DefaultShapeLibrary);
|
2019-09-17 19:12:19 -04:00
|
|
|
#endif
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
bRecompileOnLoad = 0;
|
|
|
|
|
bAutoRecompileVM = true;
|
|
|
|
|
bVMRecompilationRequired = false;
|
2021-04-07 13:09:20 -04:00
|
|
|
bIsCompiling = false;
|
2020-01-22 17:58:55 -05:00
|
|
|
VMRecompilationBracket = 0;
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
RigVMClient.SetOuterClientHost(this, GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, RigVMClient));
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> DisableClientNotifs(RigVMClient.bSuspendNotifications, true);
|
2022-06-10 10:03:01 -04:00
|
|
|
RigVMClient.AddModel(RigVMModelPrefix, false, &ObjectInitializer, false);
|
|
|
|
|
RigVMClient.GetOrCreateFunctionLibrary(false, &ObjectInitializer, false);
|
2022-05-31 04:27:20 -04:00
|
|
|
}
|
|
|
|
|
|
2021-01-14 15:00:40 -04:00
|
|
|
FunctionLibraryEdGraph = ObjectInitializer.CreateDefaultSubobject<UControlRigGraph>(this, TEXT("RigVMFunctionLibraryEdGraph"));
|
|
|
|
|
FunctionLibraryEdGraph->Schema = UControlRigGraphSchema::StaticClass();
|
|
|
|
|
FunctionLibraryEdGraph->bAllowRenaming = 0;
|
|
|
|
|
FunctionLibraryEdGraph->bEditable = 0;
|
|
|
|
|
FunctionLibraryEdGraph->bAllowDeletion = 0;
|
|
|
|
|
FunctionLibraryEdGraph->bIsFunctionDefinition = false;
|
|
|
|
|
FunctionLibraryEdGraph->Initialize(this);
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
Validator = ObjectInitializer.CreateDefaultSubobject<UControlRigValidator>(this, TEXT("ControlRigValidator"));
|
|
|
|
|
|
2021-05-19 09:16:54 -04:00
|
|
|
DebugBoneRadius = 1.f;
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
bDirtyDuringLoad = false;
|
2021-01-19 07:26:41 -04:00
|
|
|
bErrorsDuringCompilation = false;
|
2020-09-24 00:43:27 -04:00
|
|
|
|
|
|
|
|
SupportedEventNames.Reset();
|
|
|
|
|
bExposesAnimatableControls = false;
|
2021-01-19 07:26:41 -04:00
|
|
|
|
|
|
|
|
VMCompileSettings.ASTSettings.ReportDelegate.BindUObject(this, &UControlRigBlueprint::HandleReportFromCompiler);
|
2021-02-22 13:36:33 -04:00
|
|
|
|
2021-04-07 13:09:20 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
CompileLog.SetSourcePath(GetPathName());
|
|
|
|
|
CompileLog.bLogDetailedResults = false;
|
|
|
|
|
CompileLog.EventDisplayThresholdMs = false;
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
Hierarchy = CreateDefaultSubobject<URigHierarchy>(TEXT("Hierarchy"));
|
2021-09-17 11:26:26 -04:00
|
|
|
URigHierarchyController* Controller = Hierarchy->GetController(true);
|
2021-06-21 08:03:43 -04:00
|
|
|
// give BP a chance to propagate hierarchy changes to available control rig instances
|
2021-09-17 11:26:26 -04:00
|
|
|
Controller->OnModified().AddUObject(this, &UControlRigBlueprint::HandleHierarchyModified);
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
|
2021-04-15 14:30:33 -04:00
|
|
|
UControlRigBlueprint::UControlRigBlueprint()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
void UControlRigBlueprint::InitializeModelIfRequired(bool bRecompileVM)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2019-07-16 11:49:59 -04:00
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if (RigVMClient.GetController(0) == nullptr)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
check(RigVMClient.Num() == 1);
|
|
|
|
|
check(RigVMClient.GetFunctionLibrary());
|
|
|
|
|
|
|
|
|
|
RigVMClient.GetOrCreateController(RigVMClient.GetDefaultModel());
|
|
|
|
|
RigVMClient.GetOrCreateController(RigVMClient.GetFunctionLibrary());
|
2020-09-01 14:07:48 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
bool bRecompileRequired = false;
|
2019-05-21 19:25:23 -04:00
|
|
|
for (int32 i = 0; i < UbergraphPages.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* Graph = Cast<UControlRigGraph>(UbergraphPages[i]))
|
|
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
PopulateModelFromGraphForBackwardsCompatibility(Graph);
|
2020-09-24 00:43:27 -04:00
|
|
|
if (bRecompileVM)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
bRecompileRequired = true;
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
|
2019-05-21 19:25:23 -04:00
|
|
|
Graph->Initialize(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-17 19:12:19 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if(bRecompileRequired)
|
|
|
|
|
{
|
|
|
|
|
RecompileVM();
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 15:00:40 -04:00
|
|
|
FunctionLibraryEdGraph->Initialize(this);
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
2019-01-08 11:38:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprintGeneratedClass* UControlRigBlueprint::GetControlRigBlueprintGeneratedClass() const
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprintGeneratedClass* Result = Cast<UControlRigBlueprintGeneratedClass>(*GeneratedClass);
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprintGeneratedClass* UControlRigBlueprint::GetControlRigBlueprintSkeletonClass() const
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprintGeneratedClass* Result = Cast<UControlRigBlueprintGeneratedClass>(*SkeletonGeneratedClass);
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
2019-09-17 19:12:19 -04:00
|
|
|
|
2019-01-08 11:38:48 -05:00
|
|
|
UClass* UControlRigBlueprint::GetBlueprintClass() const
|
|
|
|
|
{
|
|
|
|
|
return UControlRigBlueprintGeneratedClass::StaticClass();
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-01 14:29:05 -04:00
|
|
|
UClass* UControlRigBlueprint::RegenerateClass(UClass* ClassToRegenerate, UObject* PreviousCDO)
|
|
|
|
|
{
|
|
|
|
|
UClass* Result = nullptr;
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> NotificationGuard(bSuspendAllNotifications, true);
|
|
|
|
|
Result = Super::RegenerateClass(ClassToRegenerate, PreviousCDO);
|
|
|
|
|
}
|
2022-02-18 10:27:44 -05:00
|
|
|
Hierarchy->CleanupInvalidCaches();
|
2021-04-01 14:29:05 -04:00
|
|
|
PropagateHierarchyFromBPToInstances();
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 11:38:48 -05:00
|
|
|
void UControlRigBlueprint::LoadModulesRequiredForCompilation()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 13:22:54 -04:00
|
|
|
bool UControlRigBlueprint::ExportGraphToText(UEdGraph* InEdGraph, FString& OutText)
|
|
|
|
|
{
|
|
|
|
|
OutText.Empty();
|
|
|
|
|
|
|
|
|
|
if (URigVMGraph* RigGraph = GetModel(InEdGraph))
|
|
|
|
|
{
|
|
|
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(RigGraph->GetOuter()))
|
|
|
|
|
{
|
|
|
|
|
if (URigVMController* Controller = GetOrCreateController(CollapseNode->GetGraph()))
|
|
|
|
|
{
|
|
|
|
|
TArray<FName> NodeNamesToExport;
|
|
|
|
|
NodeNamesToExport.Add(CollapseNode->GetFName());
|
|
|
|
|
OutText = Controller->ExportNodesToText(NodeNamesToExport);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// always return true so that the default mechanism doesn't take over
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::CanImportGraphFromText(const FString& InClipboardText)
|
|
|
|
|
{
|
|
|
|
|
return GetTemplateController()->CanImportNodesFromText(InClipboardText);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
void UControlRigBlueprint::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
|
|
|
|
|
{
|
|
|
|
|
Super::PostEditChangeChainProperty(PropertyChangedEvent);
|
|
|
|
|
PostEditChangeChainPropertyEvent.Broadcast(PropertyChangedEvent);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 16:55:43 -04:00
|
|
|
void UControlRigBlueprint::PostRename(UObject* OldOuter, const FName OldName)
|
|
|
|
|
{
|
|
|
|
|
Super::PostRename(OldOuter, OldName);
|
|
|
|
|
|
|
|
|
|
// Whenever the asset is renamed/moved, generated classes parented to the old package
|
|
|
|
|
// are not moved to the new package automatically (see FAssetRenameManager), so we
|
|
|
|
|
// have to manually perform the move/rename, to avoid invalid reference to the old package
|
|
|
|
|
|
|
|
|
|
// Note: while asset duplication doesn't duplicate the classes either, it is not a problem there
|
|
|
|
|
// because we always recompile in post duplicate.
|
|
|
|
|
TArray<UClass*> ClassObjects = GetClassObjectsInPackage(OldOuter->GetPackage());
|
|
|
|
|
|
|
|
|
|
for (UClass* ClassObject : ClassObjects)
|
|
|
|
|
{
|
|
|
|
|
if (URigVMMemoryStorageGeneratorClass* MemoryClass = Cast<URigVMMemoryStorageGeneratorClass>(ClassObject))
|
|
|
|
|
{
|
|
|
|
|
MemoryClass->Rename(nullptr, GetPackage(), REN_ForceNoResetLoaders | REN_DoNotDirty | REN_DontCreateRedirectors | REN_NonTransactional);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::GetPreloadDependencies(TArray<UObject*>& OutDeps)
|
|
|
|
|
{
|
|
|
|
|
Super::GetPreloadDependencies(OutDeps);
|
|
|
|
|
|
|
|
|
|
TArray<UClass*> ClassObjects = GetClassObjectsInPackage(GetPackage());
|
|
|
|
|
|
|
|
|
|
for (UClass* ClassObject : ClassObjects)
|
|
|
|
|
{
|
|
|
|
|
if (URigVMMemoryStorageGeneratorClass* MemoryClass = Cast<URigVMMemoryStorageGeneratorClass>(ClassObject))
|
|
|
|
|
{
|
|
|
|
|
OutDeps.Add(MemoryClass);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
FRigVMClient* UControlRigBlueprint::GetRigVMClient()
|
|
|
|
|
{
|
|
|
|
|
return &RigVMClient;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FRigVMClient* UControlRigBlueprint::GetRigVMClient() const
|
|
|
|
|
{
|
|
|
|
|
return &RigVMClient;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UObject* UControlRigBlueprint::GetEditorObjectForRigVMGraph(URigVMGraph* InVMGraph) const
|
|
|
|
|
{
|
|
|
|
|
if(InVMGraph)
|
|
|
|
|
{
|
|
|
|
|
if(InVMGraph->GetOutermost() != GetOutermost())
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<UEdGraph*> EdGraphs;
|
|
|
|
|
GetAllGraphs(EdGraphs);
|
|
|
|
|
|
|
|
|
|
bool bIsFunctionDefinition = false;
|
|
|
|
|
if (URigVMLibraryNode* LibraryNode = Cast<URigVMLibraryNode>(InVMGraph->GetOuter()))
|
|
|
|
|
{
|
|
|
|
|
bIsFunctionDefinition = LibraryNode->GetGraph()->IsA<URigVMFunctionLibrary>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (UEdGraph* EdGraph : EdGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* RigGraph = Cast<UControlRigGraph>(EdGraph))
|
|
|
|
|
{
|
|
|
|
|
if (RigGraph->bIsFunctionDefinition != bIsFunctionDefinition)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((RigGraph->ModelNodePath == InVMGraph->GetNodePath()) ||
|
|
|
|
|
(RigGraph->ModelNodePath.IsEmpty() && (RigVMClient.GetDefaultModel() == InVMGraph)))
|
|
|
|
|
{
|
|
|
|
|
return RigGraph;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::HandleRigVMGraphAdded(const FRigVMClient* InClient, const FString& InNodePath)
|
|
|
|
|
{
|
|
|
|
|
if(URigVMGraph* Model = InClient->GetModel(InNodePath))
|
|
|
|
|
{
|
|
|
|
|
Model->SetExecuteContextStruct(FControlRigExecuteContext::StaticStruct());
|
|
|
|
|
|
|
|
|
|
if(!HasAnyFlags(RF_ClassDefaultObject | RF_NeedInitialization | RF_NeedLoad | RF_NeedPostLoad) &&
|
|
|
|
|
GetOuter() != GetTransientPackage())
|
|
|
|
|
{
|
|
|
|
|
CreateEdGraph(Model, true);
|
|
|
|
|
RecompileVM();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
if(!bSuspendPythonMessagesForRigVMClient)
|
|
|
|
|
{
|
|
|
|
|
const FString BlueprintName = URigVMController::GetSanitizedName(GetName(), true, false);
|
|
|
|
|
RigVMPythonUtils::Print(BlueprintName,
|
|
|
|
|
FString::Printf(TEXT("blueprint.add_model('%s')"),
|
|
|
|
|
*Model->GetName()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::HandleRigVMGraphRemoved(const FRigVMClient* InClient, const FString& InNodePath)
|
|
|
|
|
{
|
|
|
|
|
if(URigVMGraph* Model = InClient->GetModel(InNodePath))
|
|
|
|
|
{
|
|
|
|
|
RemoveEdGraph(Model);
|
|
|
|
|
RecompileVM();
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
if(!bSuspendPythonMessagesForRigVMClient)
|
|
|
|
|
{
|
|
|
|
|
const FString BlueprintName = URigVMController::GetSanitizedName(GetName(), true, false);
|
|
|
|
|
RigVMPythonUtils::Print(BlueprintName,
|
|
|
|
|
FString::Printf(TEXT("blueprint.remove_model('%s')"),
|
|
|
|
|
*Model->GetName()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::HandleRigVMGraphRenamed(const FRigVMClient* InClient, const FString& InOldNodePath, const FString& InNewNodePath)
|
|
|
|
|
{
|
|
|
|
|
if(URigVMGraph* Model = InClient->GetModel(InNewNodePath))
|
|
|
|
|
{
|
|
|
|
|
TArray<UEdGraph*> EdGraphs;
|
|
|
|
|
GetAllGraphs(EdGraphs);
|
|
|
|
|
|
|
|
|
|
for (UEdGraph* EdGraph : EdGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* RigGraph = Cast<UControlRigGraph>(EdGraph))
|
|
|
|
|
{
|
|
|
|
|
RigGraph->HandleRigVMGraphRenamed(InOldNodePath, InNewNodePath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::HandleConfigureRigVMController(const FRigVMClient* InClient,
|
|
|
|
|
URigVMController* InControllerToConfigure)
|
|
|
|
|
{
|
|
|
|
|
InControllerToConfigure->OnModified().AddUObject(this, &UControlRigBlueprint::HandleModifiedEvent);
|
|
|
|
|
|
|
|
|
|
InControllerToConfigure->UnfoldStructDelegate.BindLambda([](const UStruct* InStruct) -> bool {
|
|
|
|
|
|
|
|
|
|
if (InStruct == TBaseStructure<FQuat>::Get())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (InStruct == FRuntimeFloatCurve::StaticStruct())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (InStruct == FRigPose::StaticStruct())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
TWeakObjectPtr<UControlRigBlueprint> WeakThis(this);
|
|
|
|
|
|
|
|
|
|
// this delegate is used by the controller to determine variable validity
|
|
|
|
|
// during a bind process. the controller itself doesn't own the variables,
|
|
|
|
|
// so we need a delegate to request them from the owning blueprint
|
|
|
|
|
InControllerToConfigure->GetExternalVariablesDelegate.BindLambda([](URigVMGraph* InGraph) -> TArray<FRigVMExternalVariable> {
|
|
|
|
|
|
|
|
|
|
if (InGraph)
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigBlueprint* Blueprint = InGraph->GetTypedOuter<UControlRigBlueprint>())
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigBlueprintGeneratedClass* RigClass = Blueprint->GetControlRigBlueprintGeneratedClass())
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */)))
|
|
|
|
|
{
|
|
|
|
|
return CDO->GetExternalVariablesImpl(true /* rely on variables within blueprint */);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return TArray<FRigVMExternalVariable>();
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this delegate is used by the controller to retrieve the current bytecode of the VM
|
|
|
|
|
InControllerToConfigure->GetCurrentByteCodeDelegate.BindLambda([WeakThis]() -> const FRigVMByteCode* {
|
|
|
|
|
|
|
|
|
|
if (WeakThis.IsValid())
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigBlueprintGeneratedClass* RigClass = WeakThis->GetControlRigBlueprintGeneratedClass())
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(false)))
|
|
|
|
|
{
|
|
|
|
|
if (CDO->VM)
|
|
|
|
|
{
|
|
|
|
|
return &CDO->VM->GetByteCode();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
InControllerToConfigure->IsFunctionAvailableDelegate.BindLambda([WeakThis](URigVMLibraryNode* InFunction) -> bool
|
|
|
|
|
{
|
|
|
|
|
if(InFunction == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(URigVMFunctionLibrary* Library = Cast<URigVMFunctionLibrary>(InFunction->GetOuter()))
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigBlueprint* Blueprint = Cast<UControlRigBlueprint>(Library->GetOuter()))
|
|
|
|
|
{
|
|
|
|
|
if(Blueprint->IsFunctionPublic(InFunction->GetFName()))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if it is private - we still see it as public if we are within the same blueprint
|
|
|
|
|
if(WeakThis.IsValid())
|
|
|
|
|
{
|
|
|
|
|
if(WeakThis.Get() == Blueprint)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
InControllerToConfigure->IsDependencyCyclicDelegate.BindLambda([WeakThis](UObject* InDependentObject, UObject* InDependencyObject) -> bool
|
|
|
|
|
{
|
|
|
|
|
if(InDependentObject == nullptr || InDependencyObject == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprint* DependentBlueprint = InDependentObject->GetTypedOuter<UControlRigBlueprint>();
|
|
|
|
|
UControlRigBlueprint* DependencyBlueprint = InDependencyObject->GetTypedOuter<UControlRigBlueprint>();
|
|
|
|
|
|
|
|
|
|
if(DependentBlueprint == nullptr || DependencyBlueprint == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(DependentBlueprint == DependencyBlueprint)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TArray<UControlRigBlueprint*> DependencyDependencies = DependencyBlueprint->GetDependencies(true);
|
|
|
|
|
return DependencyDependencies.Contains(DependentBlueprint);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
// this sets up three delegates:
|
|
|
|
|
// a) get external variables (mapped to Controller->GetExternalVariables)
|
|
|
|
|
// b) bind pin to variable (mapped to Controller->BindPinToVariable)
|
|
|
|
|
// c) create external variable (mapped to the passed in tfunction)
|
|
|
|
|
// the last one is defined within the blueprint since the controller
|
|
|
|
|
// doesn't own the variables and can't create one itself.
|
|
|
|
|
InControllerToConfigure->SetupDefaultUnitNodeDelegates(TDelegate<FName(FRigVMExternalVariable, FString)>::CreateLambda(
|
|
|
|
|
[WeakThis](FRigVMExternalVariable InVariableToCreate, FString InDefaultValue) -> FName {
|
|
|
|
|
if (WeakThis.IsValid())
|
|
|
|
|
{
|
|
|
|
|
return WeakThis->AddCRMemberVariableFromExternal(InVariableToCreate, InDefaultValue);
|
|
|
|
|
}
|
|
|
|
|
return NAME_None;
|
|
|
|
|
}
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
TWeakObjectPtr<URigVMController> WeakController = InControllerToConfigure;
|
|
|
|
|
InControllerToConfigure->RequestBulkEditDialogDelegate.BindLambda([WeakThis, WeakController](URigVMLibraryNode* InFunction, ERigVMControllerBulkEditType InEditType) -> FRigVMController_BulkEditResult
|
|
|
|
|
{
|
|
|
|
|
if(WeakThis.IsValid() && WeakController.IsValid())
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprint* StrongThis = WeakThis.Get();
|
|
|
|
|
URigVMController* StrongController = WeakController.Get();
|
|
|
|
|
if(StrongThis->OnRequestBulkEditDialog().IsBound())
|
|
|
|
|
{
|
|
|
|
|
return StrongThis->OnRequestBulkEditDialog().Execute(StrongThis, StrongController, InFunction, InEditType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return FRigVMController_BulkEditResult();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
InControllerToConfigure->RequestBreakLinksDialogDelegate.BindLambda([WeakThis, WeakController](TArray<URigVMLink*> InLinks) -> bool
|
|
|
|
|
{
|
|
|
|
|
if(WeakThis.IsValid() && WeakController.IsValid())
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprint* StrongThis = WeakThis.Get();
|
|
|
|
|
if(StrongThis->OnRequestBreakLinksDialog().IsBound())
|
|
|
|
|
{
|
|
|
|
|
return StrongThis->OnRequestBreakLinksDialog().Execute(InLinks);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
InControllerToConfigure->RequestNewExternalVariableDelegate.BindLambda([WeakThis](FRigVMGraphVariableDescription InVariable, bool bInIsPublic, bool bInIsReadOnly) -> FName
|
|
|
|
|
{
|
|
|
|
|
if (WeakThis.IsValid())
|
|
|
|
|
{
|
|
|
|
|
for (FBPVariableDescription& ExistingVariable : WeakThis->NewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (ExistingVariable.VarName == InVariable.Name)
|
|
|
|
|
{
|
|
|
|
|
return FName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRigVMExternalVariable ExternalVariable = InVariable.ToExternalVariable();
|
|
|
|
|
return WeakThis->AddMemberVariable(InVariable.Name,
|
|
|
|
|
ExternalVariable.TypeObject ? ExternalVariable.TypeObject->GetPathName() : ExternalVariable.TypeName.ToString(),
|
|
|
|
|
bInIsPublic,
|
|
|
|
|
bInIsReadOnly,
|
|
|
|
|
InVariable.DefaultValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FName();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InControllerToConfigure->RequestJumpToHyperlinkDelegate.BindLambda([WeakThis](const UObject* InSubject)
|
|
|
|
|
{
|
|
|
|
|
if (WeakThis.IsValid())
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprint* StrongThis = WeakThis.Get();
|
|
|
|
|
if(StrongThis->OnRequestJumpToHyperlink().IsBound())
|
|
|
|
|
{
|
|
|
|
|
StrongThis->OnRequestJumpToHyperlink().Execute(InSubject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
InControllerToConfigure->ConfigureWorkflowOptionsDelegate.BindLambda([WeakThis](URigVMUserWorkflowOptions* Options)
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigWorkflowOptions* ControlRigNodeWorkflowOptions = Cast<UControlRigWorkflowOptions>(Options))
|
|
|
|
|
{
|
|
|
|
|
ControlRigNodeWorkflowOptions->Hierarchy = nullptr;
|
|
|
|
|
ControlRigNodeWorkflowOptions->Selection.Reset();
|
|
|
|
|
|
|
|
|
|
if(const UControlRigBlueprint* StrongThis = WeakThis.Get())
|
|
|
|
|
{
|
|
|
|
|
if(UControlRig* ControlRig = Cast<UControlRig>(StrongThis->GetObjectBeingDebugged()))
|
|
|
|
|
{
|
|
|
|
|
ControlRigNodeWorkflowOptions->Hierarchy = ControlRig->GetHierarchy();
|
|
|
|
|
}
|
|
|
|
|
ControlRigNodeWorkflowOptions->Selection = StrongThis->Hierarchy->GetSelectedKeys();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 13:22:54 -04:00
|
|
|
bool UControlRigBlueprint::TryImportGraphFromText(const FString& InClipboardText, UEdGraph** OutGraphPtr)
|
|
|
|
|
{
|
|
|
|
|
if (OutGraphPtr)
|
|
|
|
|
{
|
|
|
|
|
*OutGraphPtr = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (URigVMController* FunctionLibraryController = GetOrCreateController(GetLocalFunctionLibrary()))
|
|
|
|
|
{
|
2021-03-10 05:52:25 -04:00
|
|
|
TGuardValue<FRigVMController_RequestLocalizeFunctionDelegate> RequestLocalizeDelegateGuard(
|
|
|
|
|
FunctionLibraryController->RequestLocalizeFunctionDelegate,
|
|
|
|
|
FRigVMController_RequestLocalizeFunctionDelegate::CreateLambda([this](URigVMLibraryNode* InFunctionToLocalize)
|
|
|
|
|
{
|
|
|
|
|
BroadcastRequestLocalizeFunctionDialog(InFunctionToLocalize);
|
|
|
|
|
|
|
|
|
|
const URigVMLibraryNode* LocalizedFunctionNode = GetLocalFunctionLibrary()->FindPreviouslyLocalizedFunction(InFunctionToLocalize);
|
|
|
|
|
return LocalizedFunctionNode != nullptr;
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2021-07-27 09:37:12 -04:00
|
|
|
TArray<FName> ImportedNodeNames = FunctionLibraryController->ImportNodesFromText(InClipboardText, true, true);
|
2021-01-27 13:22:54 -04:00
|
|
|
if (ImportedNodeNames.Num() == 0)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(GetLocalFunctionLibrary()->FindFunction(ImportedNodeNames[0]));
|
|
|
|
|
if (ImportedNodeNames.Num() > 1 || CollapseNode == nullptr || CollapseNode->GetContainedGraph() == nullptr)
|
|
|
|
|
{
|
|
|
|
|
FunctionLibraryController->Undo();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UEdGraph* EdGraph = GetEdGraph(CollapseNode->GetContainedGraph());
|
|
|
|
|
if (OutGraphPtr)
|
|
|
|
|
{
|
|
|
|
|
*OutGraphPtr = EdGraph;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BroadcastGraphImported(EdGraph);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// always return true so that the default mechanism doesn't take over
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 11:38:48 -05:00
|
|
|
USkeletalMesh* UControlRigBlueprint::GetPreviewMesh() const
|
|
|
|
|
{
|
2019-07-16 11:49:59 -04:00
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
|
|
|
|
|
2021-08-10 14:19:17 -04:00
|
|
|
#if WITH_EDITORONLY_DATA
|
2019-01-08 11:38:48 -05:00
|
|
|
if (!PreviewSkeletalMesh.IsValid())
|
|
|
|
|
{
|
|
|
|
|
PreviewSkeletalMesh.LoadSynchronous();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PreviewSkeletalMesh.Get();
|
2021-08-10 14:19:17 -04:00
|
|
|
#else
|
|
|
|
|
return nullptr;
|
|
|
|
|
#endif
|
2019-01-08 11:38:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::SetPreviewMesh(USkeletalMesh* PreviewMesh, bool bMarkAsDirty/*=true*/)
|
|
|
|
|
{
|
2021-08-10 14:19:17 -04:00
|
|
|
#if WITH_EDITORONLY_DATA
|
2019-01-08 11:38:48 -05:00
|
|
|
if(bMarkAsDirty)
|
|
|
|
|
{
|
|
|
|
|
Modify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PreviewSkeletalMesh = PreviewMesh;
|
2021-08-10 14:19:17 -04:00
|
|
|
#endif
|
2019-01-08 11:38:48 -05:00
|
|
|
}
|
|
|
|
|
|
2021-03-03 14:44:58 -04:00
|
|
|
void UControlRigBlueprint::Serialize(FArchive& Ar)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
RigVMClient.SetOuterClientHost(this, GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, RigVMClient));
|
|
|
|
|
|
2021-03-03 14:44:58 -04:00
|
|
|
Super::Serialize(Ar);
|
|
|
|
|
|
|
|
|
|
if(Ar.IsObjectReferenceCollector())
|
|
|
|
|
{
|
2021-07-28 17:11:36 -04:00
|
|
|
TArray<UControlRigBlueprint*> ReferencedBlueprints = GetReferencedControlRigBlueprints();
|
2021-03-03 14:44:58 -04:00
|
|
|
|
2021-07-28 17:11:36 -04:00
|
|
|
for(UControlRigBlueprint* ReferencedBlueprint : ReferencedBlueprints)
|
2021-03-03 14:44:58 -04:00
|
|
|
{
|
|
|
|
|
Ar << ReferencedBlueprints;
|
|
|
|
|
}
|
2022-01-27 03:46:30 -05:00
|
|
|
|
|
|
|
|
for(const TSoftObjectPtr<UControlRigShapeLibrary>& ShapeLibraryPtr : ShapeLibraries)
|
|
|
|
|
{
|
|
|
|
|
if(ShapeLibraryPtr.IsValid())
|
|
|
|
|
{
|
|
|
|
|
UControlRigShapeLibrary* ShapeLibrary = ShapeLibraryPtr.Get();
|
|
|
|
|
Ar << ShapeLibrary;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-03 14:44:58 -04:00
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
if(Ar.IsLoading())
|
|
|
|
|
{
|
|
|
|
|
if(Model_DEPRECATED || FunctionLibrary_DEPRECATED)
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> DisableClientNotifs(RigVMClient.bSuspendNotifications, true);
|
|
|
|
|
RigVMClient.SetFromDeprecatedData(Model_DEPRECATED, FunctionLibrary_DEPRECATED);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-03 14:44:58 -04:00
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
void UControlRigBlueprint::PreSave(const class ITargetPlatform* TargetPlatform)
|
|
|
|
|
{
|
2021-03-25 16:51:36 -04:00
|
|
|
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
|
2020-09-24 00:43:27 -04:00
|
|
|
Super::PreSave(TargetPlatform);
|
2021-03-25 16:51:36 -04:00
|
|
|
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::PreSave(FObjectPreSaveContext ObjectSaveContext)
|
|
|
|
|
{
|
|
|
|
|
Super::PreSave(ObjectSaveContext);
|
2020-09-24 00:43:27 -04:00
|
|
|
|
|
|
|
|
SupportedEventNames.Reset();
|
|
|
|
|
if (UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass())
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */)))
|
|
|
|
|
{
|
|
|
|
|
SupportedEventNames = CDO->GetSupportedEvents();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bExposesAnimatableControls = false;
|
2021-02-22 13:36:33 -04:00
|
|
|
Hierarchy->ForEach<FRigControlElement>([this](FRigControlElement* ControlElement) -> bool
|
|
|
|
|
{
|
2022-05-11 08:12:21 -04:00
|
|
|
if (Hierarchy->IsAnimatable(ControlElement))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
bExposesAnimatableControls = true;
|
2021-02-22 13:36:33 -04:00
|
|
|
return false;
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
2021-02-22 13:36:33 -04:00
|
|
|
return true;
|
|
|
|
|
});
|
2021-03-03 14:44:58 -04:00
|
|
|
|
|
|
|
|
for(FControlRigPublicFunctionData& FunctionData : PublicFunctions)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if(URigVMLibraryNode* FunctionNode = RigVMClient.GetFunctionLibrary()->FindFunction(FunctionData.Name))
|
2021-03-03 14:44:58 -04:00
|
|
|
{
|
|
|
|
|
if(UControlRigGraph* Graph = Cast<UControlRigGraph>(GetEdGraph(FunctionNode->GetContainedGraph())))
|
|
|
|
|
{
|
|
|
|
|
FunctionData = Graph->GetPublicFunctionData();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-10 07:13:27 -05:00
|
|
|
|
|
|
|
|
FunctionReferenceNodeData = GetReferenceNodeData();
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
|
2019-09-17 19:12:19 -04:00
|
|
|
void UControlRigBlueprint::PostLoad()
|
|
|
|
|
{
|
|
|
|
|
Super::PostLoad();
|
|
|
|
|
|
2021-09-15 12:41:49 -04:00
|
|
|
bVMRecompilationRequired = true;
|
2021-07-28 17:11:36 -04:00
|
|
|
{
|
2021-09-20 12:22:17 -04:00
|
|
|
TGuardValue<bool> IsCompilingGuard(bIsCompiling, true);
|
|
|
|
|
|
2021-09-10 10:04:27 -04:00
|
|
|
TArray<UControlRigBlueprint*> ReferencedBlueprints = GetReferencedControlRigBlueprints();
|
2021-01-06 16:30:00 -04:00
|
|
|
|
2021-09-10 10:04:27 -04:00
|
|
|
// PostLoad all referenced BPs so that their function graphs are fully loaded
|
|
|
|
|
// and ready to be inlined into this BP during compilation
|
|
|
|
|
for (UControlRigBlueprint* BP : ReferencedBlueprints)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
if (BP->HasAllFlags(RF_NeedPostLoad))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
BP->ConditionalPostLoad();
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-22 13:36:33 -04:00
|
|
|
|
2021-09-10 10:04:27 -04:00
|
|
|
// temporarily disable default value validation during load time, serialized values should always be accepted
|
|
|
|
|
TGuardValue<bool> DisablePinDefaultValueValidation(GetOrCreateController()->bValidatePinDefaults, false);
|
|
|
|
|
|
|
|
|
|
// correct the offset transforms
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::ControlOffsetTransform)
|
|
|
|
|
{
|
|
|
|
|
HierarchyContainer_DEPRECATED.ControlHierarchy.PostLoad();
|
|
|
|
|
if (HierarchyContainer_DEPRECATED.ControlHierarchy.Num() > 0)
|
|
|
|
|
{
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (FRigControl& Control : HierarchyContainer_DEPRECATED.ControlHierarchy)
|
|
|
|
|
{
|
|
|
|
|
const FTransform PreviousOffsetTransform = Control.GetTransformFromValue(ERigControlValueType::Initial);
|
|
|
|
|
Control.OffsetTransform = PreviousOffsetTransform;
|
|
|
|
|
Control.InitialValue = Control.Value;
|
|
|
|
|
|
|
|
|
|
if (Control.ControlType == ERigControlType::Transform)
|
|
|
|
|
{
|
|
|
|
|
Control.InitialValue = FRigControlValue::Make<FTransform>(FTransform::Identity);
|
|
|
|
|
}
|
|
|
|
|
else if (Control.ControlType == ERigControlType::TransformNoScale)
|
|
|
|
|
{
|
|
|
|
|
Control.InitialValue = FRigControlValue::Make<FTransformNoScale>(FTransformNoScale::Identity);
|
|
|
|
|
}
|
|
|
|
|
else if (Control.ControlType == ERigControlType::EulerTransform)
|
|
|
|
|
{
|
|
|
|
|
Control.InitialValue = FRigControlValue::Make<FEulerTransform>(FEulerTransform::Identity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// convert the hierarchy from V1 to V2
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::RigHierarchyV2)
|
|
|
|
|
{
|
|
|
|
|
Modify();
|
|
|
|
|
|
|
|
|
|
TGuardValue<bool> SuspendNotifGuard(Hierarchy->GetSuspendNotificationsFlag(), true);
|
|
|
|
|
|
|
|
|
|
Hierarchy->Reset();
|
|
|
|
|
GetHierarchyController()->ImportFromHierarchyContainer(HierarchyContainer_DEPRECATED, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remove all non-controlrig-graphs
|
|
|
|
|
TArray<UEdGraph*> NewUberGraphPages;
|
|
|
|
|
for (UEdGraph* Graph : UbergraphPages)
|
2019-09-17 19:12:19 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
UControlRigGraph* RigGraph = Cast<UControlRigGraph>(Graph);
|
|
|
|
|
if (RigGraph)
|
|
|
|
|
{
|
|
|
|
|
NewUberGraphPages.Add(RigGraph);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-11-18 14:37:34 -05:00
|
|
|
Graph->MarkAsGarbage();
|
2021-09-10 10:04:27 -04:00
|
|
|
Graph->Rename(nullptr, GetTransientPackage(), REN_ForceNoResetLoaders);
|
|
|
|
|
}
|
2019-09-17 19:12:19 -04:00
|
|
|
}
|
2021-09-10 10:04:27 -04:00
|
|
|
UbergraphPages = NewUberGraphPages;
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2022-03-30 05:21:45 -04:00
|
|
|
TArray<TGuardValue<bool>> EditableGraphGuards;
|
|
|
|
|
{
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
|
|
|
|
EditableGraphGuards.Emplace(Graph->bEditable, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-10 10:04:27 -04:00
|
|
|
InitializeModelIfRequired(false /* recompile vm */);
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2021-10-19 06:29:19 -04:00
|
|
|
PatchFunctionReferencesOnLoad();
|
2021-09-10 10:04:27 -04:00
|
|
|
PatchVariableNodesOnLoad();
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
PatchVariableNodesWithIncorrectType();
|
2021-11-24 05:32:05 -05:00
|
|
|
PatchRigElementKeyCacheOnLoad();
|
2021-11-29 11:26:01 -05:00
|
|
|
PatchBoundVariables();
|
2022-03-15 15:51:41 -04:00
|
|
|
PatchPropagateToChildren();
|
2022-03-07 10:20:24 -05:00
|
|
|
PatchParameterNodesOnLoad();
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
2022-01-13 22:49:09 -05:00
|
|
|
// refresh the graph such that the pin hierarchies matches their CPPTypeObject
|
|
|
|
|
// this step is needed everytime we open a BP in the editor, b/c even after load
|
|
|
|
|
// model data can change while the Control Rig BP is not opened
|
|
|
|
|
// for example, if a user defined struct changed after BP load,
|
|
|
|
|
// any pin that references the struct needs to be regenerated
|
|
|
|
|
RefreshAllModels();
|
2021-09-10 10:04:27 -04:00
|
|
|
|
|
|
|
|
// perform backwards compat value upgrades
|
|
|
|
|
TArray<URigVMGraph*> GraphsToValidate = GetAllModels();
|
|
|
|
|
for (int32 GraphIndex = 0; GraphIndex < GraphsToValidate.Num(); GraphIndex++)
|
|
|
|
|
{
|
|
|
|
|
URigVMGraph* GraphToValidate = GraphsToValidate[GraphIndex];
|
|
|
|
|
if(GraphToValidate == nullptr)
|
2021-01-14 15:00:40 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
continue;
|
2021-01-14 15:00:40 -04:00
|
|
|
}
|
|
|
|
|
|
2021-09-10 10:04:27 -04:00
|
|
|
for(URigVMNode* Node : GraphToValidate->GetNodes())
|
2021-03-05 04:30:31 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
URigVMController* Controller = GetOrCreateController(GraphToValidate);
|
|
|
|
|
Controller->RemoveUnusedOrphanedPins(Node, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(URigVMNode* Node : GraphToValidate->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
TArray<URigVMPin*> Pins = Node->GetAllPinsRecursively();
|
|
|
|
|
for(URigVMPin* Pin : Pins)
|
2021-03-05 04:30:31 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
if(Pin->GetCPPTypeObject() == StaticEnum<ERigElementType>())
|
2021-03-05 04:30:31 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
if(Pin->GetDefaultValue() == TEXT("Space"))
|
2021-03-05 04:30:31 -04:00
|
|
|
{
|
2021-09-10 10:04:27 -04:00
|
|
|
if(URigVMController* Controller = GetController(GraphToValidate))
|
|
|
|
|
{
|
|
|
|
|
Controller->SuspendNotifications(true);
|
|
|
|
|
Controller->SetPinDefaultValue(Pin->GetPinPath(), TEXT("Null"), false, false, false);
|
|
|
|
|
Controller->SuspendNotifications(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-01 06:29:29 -05:00
|
|
|
|
|
|
|
|
// avoid function reference related validation for temp assets, a temp asset may get generated during
|
|
|
|
|
// certain content validation process. It is usually just a simple file-level copy of the source asset
|
|
|
|
|
// so these references are usually not fixed-up properly. Thus, it is meaningless to validate them.
|
|
|
|
|
// They should not be allowed to dirty the source asset either.
|
|
|
|
|
if (!this->GetPackage()->GetName().StartsWith("/Temp/"))
|
2021-09-10 10:04:27 -04:00
|
|
|
{
|
2021-12-01 06:29:29 -05:00
|
|
|
if(URigVMFunctionReferenceNode* FunctionReferenceNode = Cast<URigVMFunctionReferenceNode>(Node))
|
2021-09-10 10:04:27 -04:00
|
|
|
{
|
2021-12-01 06:29:29 -05:00
|
|
|
if(URigVMLibraryNode* DependencyNode = FunctionReferenceNode->GetReferencedNode())
|
2021-09-10 10:04:27 -04:00
|
|
|
{
|
2021-12-01 06:29:29 -05:00
|
|
|
if(UControlRigBlueprint* DependencyBlueprint = DependencyNode->GetTypedOuter<UControlRigBlueprint>())
|
2021-09-10 10:04:27 -04:00
|
|
|
{
|
2021-12-01 06:29:29 -05:00
|
|
|
if(DependencyBlueprint != this)
|
|
|
|
|
{
|
2022-02-10 07:13:27 -05:00
|
|
|
if(URigVMBuildData* BuildData = URigVMController::GetBuildData())
|
|
|
|
|
{
|
|
|
|
|
BuildData->UpdateReferencesForFunctionReferenceNode(FunctionReferenceNode);
|
|
|
|
|
}
|
2021-12-01 06:29:29 -05:00
|
|
|
}
|
2021-09-10 10:04:27 -04:00
|
|
|
}
|
2021-03-05 04:30:31 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-10 10:04:27 -04:00
|
|
|
}
|
2021-04-15 14:30:33 -04:00
|
|
|
|
2021-09-10 10:04:27 -04:00
|
|
|
CompileLog.Messages.Reset();
|
|
|
|
|
CompileLog.NumErrors = CompileLog.NumWarnings = 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2021-03-05 04:30:31 -04:00
|
|
|
|
2021-10-20 11:56:18 -04:00
|
|
|
// upgrade the gizmo libraries to shape libraries
|
2022-02-24 19:26:12 -05:00
|
|
|
if(!GizmoLibrary_DEPRECATED.IsNull() || GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::RenameGizmoToShape)
|
2021-10-20 11:56:18 -04:00
|
|
|
{
|
|
|
|
|
// if it's an older file and it doesn't have the GizmoLibrary stored,
|
|
|
|
|
// refer to the previous default.
|
|
|
|
|
ShapeLibraries.Reset();
|
2021-10-26 14:46:01 -04:00
|
|
|
|
2022-02-24 19:26:12 -05:00
|
|
|
if(!GizmoLibrary_DEPRECATED.IsNull())
|
2021-10-26 14:46:01 -04:00
|
|
|
{
|
2022-02-24 19:26:12 -05:00
|
|
|
ShapeLibrariesToLoadOnPackageLoaded.Add(GizmoLibrary_DEPRECATED.ToString());
|
2021-10-26 14:46:01 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-01-25 05:00:23 -05:00
|
|
|
static const FString DefaultGizmoLibraryPath = TEXT("/ControlRig/Controls/DefaultGizmoLibrary.DefaultGizmoLibrary");
|
|
|
|
|
ShapeLibrariesToLoadOnPackageLoaded.Add(DefaultGizmoLibraryPath);
|
2021-10-26 14:46:01 -04:00
|
|
|
}
|
2021-10-20 11:56:18 -04:00
|
|
|
|
2021-10-26 14:46:01 -04:00
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(false /* create if needed */));
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
2022-01-25 05:00:23 -05:00
|
|
|
ArchetypeInstances.Insert(CDO, 0);
|
|
|
|
|
|
2021-10-26 14:46:01 -04:00
|
|
|
for (UObject* Instance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(Instance))
|
|
|
|
|
{
|
2022-01-25 05:00:23 -05:00
|
|
|
InstanceRig->ShapeLibraries.Reset();
|
2021-10-26 14:46:01 -04:00
|
|
|
InstanceRig->GizmoLibrary_DEPRECATED.Reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-20 11:56:18 -04:00
|
|
|
}
|
|
|
|
|
|
2021-09-20 12:22:17 -04:00
|
|
|
#if WITH_EDITOR
|
2022-04-12 08:45:06 -04:00
|
|
|
if(GIsEditor)
|
|
|
|
|
{
|
2022-04-19 13:15:16 -04:00
|
|
|
// delay compilation until the package has been loaded
|
2022-04-12 08:45:06 -04:00
|
|
|
FCoreUObjectDelegates::OnEndLoadPackage.AddUObject(this, &UControlRigBlueprint::HandlePackageDone);
|
|
|
|
|
}
|
2021-09-20 12:22:17 -04:00
|
|
|
#else
|
2021-09-15 12:41:49 -04:00
|
|
|
RecompileVMIfRequired();
|
2021-09-20 12:22:17 -04:00
|
|
|
#endif
|
2020-01-22 17:58:55 -05:00
|
|
|
RequestControlRigInit();
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
FCoreUObjectDelegates::OnObjectModified.RemoveAll(this);
|
|
|
|
|
OnChanged().RemoveAll(this);
|
|
|
|
|
FCoreUObjectDelegates::OnObjectModified.AddUObject(this, &UControlRigBlueprint::OnPreVariableChange);
|
|
|
|
|
OnChanged().AddUObject(this, &UControlRigBlueprint::OnPostVariableChange);
|
|
|
|
|
|
|
|
|
|
if (UPackage* Package = GetOutermost())
|
|
|
|
|
{
|
|
|
|
|
Package->SetDirtyFlag(bDirtyDuringLoad);
|
|
|
|
|
}
|
2022-04-12 08:45:06 -04:00
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
// if we are running with -game we are in editor code,
|
|
|
|
|
// but GIsEditor is turned off
|
|
|
|
|
if(!GIsEditor)
|
|
|
|
|
{
|
2022-05-19 08:04:52 -04:00
|
|
|
HandlePackageDone();
|
2022-04-12 08:45:06 -04:00
|
|
|
}
|
|
|
|
|
#endif
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
|
2021-09-20 12:22:17 -04:00
|
|
|
#if WITH_EDITOR
|
2022-02-17 22:02:59 -05:00
|
|
|
void UControlRigBlueprint::HandlePackageDone(const FEndLoadPackageContext& Context)
|
2021-09-20 12:22:17 -04:00
|
|
|
{
|
2022-02-17 22:02:59 -05:00
|
|
|
if (!Context.LoadedPackages.Contains(GetPackage()))
|
2021-09-20 12:22:17 -04:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-05-19 08:04:52 -04:00
|
|
|
HandlePackageDone();
|
|
|
|
|
}
|
2021-09-20 12:22:17 -04:00
|
|
|
|
2022-05-19 08:04:52 -04:00
|
|
|
void UControlRigBlueprint::HandlePackageDone()
|
|
|
|
|
{
|
2021-09-20 12:22:17 -04:00
|
|
|
FCoreUObjectDelegates::OnEndLoadPackage.RemoveAll(this);
|
2022-01-25 05:00:23 -05:00
|
|
|
|
|
|
|
|
if (ShapeLibrariesToLoadOnPackageLoaded.Num() > 0)
|
|
|
|
|
{
|
|
|
|
|
for(const FString& ShapeLibraryToLoadOnPackageLoaded : ShapeLibrariesToLoadOnPackageLoaded)
|
|
|
|
|
{
|
|
|
|
|
ShapeLibraries.Add(LoadObject<UControlRigShapeLibrary>(nullptr, *ShapeLibraryToLoadOnPackageLoaded));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(false /* create if needed */));
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
ArchetypeInstances.Insert(CDO, 0);
|
|
|
|
|
|
|
|
|
|
for (UObject* Instance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(Instance))
|
|
|
|
|
{
|
|
|
|
|
InstanceRig->ShapeLibraries = ShapeLibraries;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShapeLibrariesToLoadOnPackageLoaded.Reset();
|
|
|
|
|
}
|
2022-02-10 07:13:27 -05:00
|
|
|
|
|
|
|
|
if(URigVMBuildData* BuildData = URigVMController::GetBuildData())
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if(URigVMFunctionLibrary* FunctionLibrary = RigVMClient.GetFunctionLibrary())
|
2022-02-10 07:13:27 -05:00
|
|
|
{
|
|
|
|
|
// for backwards compatibility load the function references from the
|
|
|
|
|
// model's storage over to the centralized build data
|
|
|
|
|
if(!FunctionLibrary->FunctionReferences_DEPRECATED.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
// let's also update the asset data of the dependents
|
|
|
|
|
const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
|
|
|
|
|
|
|
|
|
for(const TTuple< TObjectPtr<URigVMLibraryNode>, FRigVMFunctionReferenceArray >& Pair :
|
|
|
|
|
FunctionLibrary->FunctionReferences_DEPRECATED)
|
|
|
|
|
{
|
|
|
|
|
TSoftObjectPtr<URigVMLibraryNode> FunctionKey(Pair.Key);
|
|
|
|
|
|
|
|
|
|
for(int32 ReferenceIndex = 0; ReferenceIndex < Pair.Value.Num(); ReferenceIndex++)
|
|
|
|
|
{
|
|
|
|
|
// update the build data
|
|
|
|
|
BuildData->RegisterFunctionReference(FunctionKey, Pair.Value[ReferenceIndex]);
|
|
|
|
|
|
|
|
|
|
// find all control rigs matching the reference node
|
|
|
|
|
FAssetData AssetData = AssetRegistryModule.Get().GetAssetByObjectPath(
|
|
|
|
|
Pair.Value[ReferenceIndex].ToSoftObjectPath().GetAssetPathName());
|
|
|
|
|
|
|
|
|
|
// if the asset has never been loaded - make sure to load it once and mark as dirty
|
|
|
|
|
if(AssetData.IsValid() && !AssetData.IsAssetLoaded())
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigBlueprint* Dependent = Cast<UControlRigBlueprint>(AssetData.GetAsset()))
|
|
|
|
|
{
|
|
|
|
|
if(Dependent != this)
|
|
|
|
|
{
|
|
|
|
|
Dependent->MarkPackageDirty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FunctionLibrary->FunctionReferences_DEPRECATED.Reset();
|
|
|
|
|
MarkPackageDirty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// update the build data from the current function references
|
|
|
|
|
const TArray<FRigVMReferenceNodeData> ReferenceNodeDatas = GetReferenceNodeData();
|
|
|
|
|
for(const FRigVMReferenceNodeData& ReferenceNodeData : ReferenceNodeDatas)
|
|
|
|
|
{
|
|
|
|
|
BuildData->RegisterFunctionReference(ReferenceNodeData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BuildData->ClearInvalidReferences();
|
|
|
|
|
}
|
2021-09-20 12:22:17 -04:00
|
|
|
|
2021-10-06 12:58:15 -04:00
|
|
|
PropagateHierarchyFromBPToInstances();
|
2022-05-18 15:28:05 -04:00
|
|
|
RemoveDeprecatedVMMemoryClass();
|
2021-09-20 12:22:17 -04:00
|
|
|
RecompileVM();
|
|
|
|
|
RequestControlRigInit();
|
2021-10-06 12:58:15 -04:00
|
|
|
BroadcastControlRigPackageDone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::BroadcastControlRigPackageDone()
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
CDO->BroadCastEndLoadPackage();
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* Instance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(Instance))
|
|
|
|
|
{
|
|
|
|
|
InstanceRig->BroadCastEndLoadPackage();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-20 12:22:17 -04:00
|
|
|
}
|
2022-05-18 15:28:05 -04:00
|
|
|
|
|
|
|
|
void UControlRigBlueprint::RemoveDeprecatedVMMemoryClass() const
|
|
|
|
|
{
|
|
|
|
|
TArray<UObject*> Objects;
|
2022-05-31 16:55:43 -04:00
|
|
|
GetObjectsWithOuter(this, Objects, false);
|
2022-05-18 15:28:05 -04:00
|
|
|
|
|
|
|
|
for (UObject* Object : Objects)
|
|
|
|
|
{
|
|
|
|
|
if (URigVMMemoryStorageGeneratorClass* DeprecatedClass = Cast<URigVMMemoryStorageGeneratorClass>(Object))
|
|
|
|
|
{
|
|
|
|
|
DeprecatedClass->Rename(nullptr, GetTransientPackage(), REN_ForceNoResetLoaders | REN_DoNotDirty | REN_DontCreateRedirectors | REN_NonTransactional);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-20 12:22:17 -04:00
|
|
|
#endif
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::RecompileVM()
|
|
|
|
|
{
|
2021-04-07 13:09:20 -04:00
|
|
|
if(bIsCompiling)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
if(RigClass == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-07 13:09:20 -04:00
|
|
|
TGuardValue<bool> CompilingGuard(bIsCompiling, true);
|
|
|
|
|
|
2021-01-19 07:26:41 -04:00
|
|
|
bErrorsDuringCompilation = false;
|
|
|
|
|
|
2021-08-20 12:55:39 -04:00
|
|
|
RigGraphDisplaySettings.MinMicroSeconds = RigGraphDisplaySettings.LastMinMicroSeconds = DBL_MAX;
|
|
|
|
|
RigGraphDisplaySettings.MaxMicroSeconds = RigGraphDisplaySettings.LastMaxMicroSeconds = (double)INDEX_NONE;
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
if (CDO->VM != nullptr)
|
|
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
TGuardValue<bool> ReentrantGuardSelf(bSuspendModelNotificationsForSelf, true);
|
|
|
|
|
TGuardValue<bool> ReentrantGuardOthers(bSuspendModelNotificationsForOthers, true);
|
|
|
|
|
|
2021-09-21 05:06:09 -04:00
|
|
|
CDO->PostInitInstanceIfRequired();
|
2021-08-05 07:57:17 -04:00
|
|
|
CDO->VMRuntimeSettings = VMRuntimeSettings;
|
2021-02-22 13:36:33 -04:00
|
|
|
CDO->GetHierarchy()->CopyHierarchy(Hierarchy);
|
2020-09-24 00:43:27 -04:00
|
|
|
|
|
|
|
|
if (!HasAnyFlags(RF_Transient | RF_Transactional))
|
|
|
|
|
{
|
|
|
|
|
CDO->Modify(false);
|
|
|
|
|
}
|
|
|
|
|
CDO->VM->Reset();
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2021-02-23 04:37:42 -04:00
|
|
|
FRigNameCache TempNameCache;
|
2020-09-24 00:43:27 -04:00
|
|
|
FRigUnitContext InitContext;
|
|
|
|
|
InitContext.State = EControlRigState::Init;
|
2021-02-22 13:36:33 -04:00
|
|
|
InitContext.Hierarchy = CDO->DynamicHierarchy;
|
2021-02-23 04:37:42 -04:00
|
|
|
InitContext.NameCache = &TempNameCache;
|
2020-09-24 00:43:27 -04:00
|
|
|
|
|
|
|
|
FRigUnitContext UpdateContext = InitContext;
|
2021-02-23 04:37:42 -04:00
|
|
|
UpdateContext.State = EControlRigState::Update;
|
2020-09-24 00:43:27 -04:00
|
|
|
|
|
|
|
|
void* InitContextPtr = &InitContext;
|
|
|
|
|
void* UpdateContextPtr = &UpdateContext;
|
|
|
|
|
|
|
|
|
|
TArray<FRigVMUserDataArray> UserData;
|
|
|
|
|
UserData.Add(FRigVMUserDataArray(&InitContextPtr, 1));
|
|
|
|
|
UserData.Add(FRigVMUserDataArray(&UpdateContextPtr, 1));
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2021-04-07 13:09:20 -04:00
|
|
|
CompileLog.Messages.Reset();
|
|
|
|
|
CompileLog.NumErrors = CompileLog.NumWarnings = 0;
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
URigVMCompiler* Compiler = URigVMCompiler::StaticClass()->GetDefaultObject<URigVMCompiler>();
|
2021-04-29 09:08:58 -04:00
|
|
|
Compiler->Settings = (bCompileInDebugMode) ? FRigVMCompileSettings::Fast() : VMCompileSettings;
|
2022-05-31 04:27:20 -04:00
|
|
|
Compiler->Compile(RigVMClient.GetAllModels(false, false), GetOrCreateController(), CDO->VM, CDO->GetExternalVariablesImpl(false), UserData, &PinToOperandMap);
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2021-01-19 07:26:41 -04:00
|
|
|
if (bErrorsDuringCompilation)
|
|
|
|
|
{
|
2021-09-30 09:59:07 -04:00
|
|
|
if(Compiler->Settings.SurpressErrors)
|
|
|
|
|
{
|
|
|
|
|
Compiler->Settings.Reportf(EMessageSeverity::Info, this,
|
|
|
|
|
TEXT("Compilation Errors may be suppressed for ControlRigBlueprint: %s. See VM Compile Setting in Class Settings for more Details"), *this->GetName());
|
|
|
|
|
}
|
2021-09-15 12:41:49 -04:00
|
|
|
bVMRecompilationRequired = false;
|
2021-04-07 13:09:20 -04:00
|
|
|
if(CDO->VM)
|
|
|
|
|
{
|
|
|
|
|
VMCompiledEvent.Broadcast(this, CDO->VM);
|
|
|
|
|
}
|
2021-01-19 07:26:41 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* Instance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(Instance))
|
|
|
|
|
{
|
2022-01-18 04:58:41 -05:00
|
|
|
// No objects should be created during load, so PostInitInstanceIfRequired, which creates a new VM and
|
|
|
|
|
// DynamicHierarchy, should not be called during load
|
|
|
|
|
if (!InstanceRig->HasAllFlags(RF_NeedPostLoad))
|
|
|
|
|
{
|
|
|
|
|
InstanceRig->PostInitInstanceIfRequired();
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
InstanceRig->InstantiateVMFromCDO();
|
2022-01-19 10:12:58 -05:00
|
|
|
InstanceRig->CopyExternalVariableDefaultValuesFromCDO();
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bVMRecompilationRequired = false;
|
|
|
|
|
VMCompiledEvent.Broadcast(this, CDO->VM);
|
2021-04-21 11:25:07 -04:00
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
RefreshControlRigBreakpoints();
|
|
|
|
|
#endif
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::RecompileVMIfRequired()
|
|
|
|
|
{
|
|
|
|
|
if (bVMRecompilationRequired)
|
|
|
|
|
{
|
|
|
|
|
RecompileVM();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::RequestAutoVMRecompilation()
|
|
|
|
|
{
|
|
|
|
|
bVMRecompilationRequired = true;
|
|
|
|
|
if (bAutoRecompileVM && VMRecompilationBracket == 0)
|
|
|
|
|
{
|
|
|
|
|
RecompileVMIfRequired();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::IncrementVMRecompileBracket()
|
|
|
|
|
{
|
|
|
|
|
VMRecompilationBracket++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::DecrementVMRecompileBracket()
|
|
|
|
|
{
|
|
|
|
|
if (VMRecompilationBracket == 1)
|
|
|
|
|
{
|
|
|
|
|
if (bAutoRecompileVM)
|
|
|
|
|
{
|
|
|
|
|
RecompileVMIfRequired();
|
|
|
|
|
}
|
|
|
|
|
VMRecompilationBracket = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (VMRecompilationBracket > 0)
|
|
|
|
|
{
|
|
|
|
|
VMRecompilationBracket--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-13 22:49:09 -05:00
|
|
|
void UControlRigBlueprint::RefreshAllModels()
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> IsCompilingGuard(bIsCompiling, true);
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
TArray<URigVMGraph*> GraphsToDetach = RigVMClient.GetAllModels(true, false);
|
2022-01-13 22:49:09 -05:00
|
|
|
|
|
|
|
|
if (ensure(IsInGameThread()))
|
|
|
|
|
{
|
|
|
|
|
for (URigVMGraph* GraphToDetach : GraphsToDetach)
|
|
|
|
|
{
|
|
|
|
|
URigVMController* Controller = GetOrCreateController(GraphToDetach);
|
|
|
|
|
// temporarily disable default value validation during load time, serialized values should always be accepted
|
|
|
|
|
TGuardValue<bool> PerGraphDisablePinDefaultValueValidation(Controller->bValidatePinDefaults, false);
|
|
|
|
|
Controller->DetachLinksFromPinObjects();
|
|
|
|
|
TArray<URigVMNode*> Nodes = GraphToDetach->GetNodes();
|
|
|
|
|
for (URigVMNode* Node : Nodes)
|
|
|
|
|
{
|
|
|
|
|
Controller->RepopulatePinsOnNode(Node, true, false, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SetupPinRedirectorsForBackwardsCompatibility();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (URigVMGraph* GraphToDetach : GraphsToDetach)
|
|
|
|
|
{
|
|
|
|
|
URigVMController* Controller = GetOrCreateController(GraphToDetach);
|
|
|
|
|
Controller->ReattachLinksToPinObjects(true /* follow redirectors */, nullptr, false, true);
|
|
|
|
|
}
|
2022-01-19 12:37:29 -05:00
|
|
|
|
2022-05-20 09:28:06 -04:00
|
|
|
PatchTemplateNodesWithPreferredPermutation();
|
2022-01-19 12:37:29 -05:00
|
|
|
|
|
|
|
|
TArray<URigVMGraph*> GraphsToClean = GetAllModels();
|
|
|
|
|
|
|
|
|
|
for(int32 GraphIndex=0; GraphIndex<GraphsToClean.Num(); GraphIndex++)
|
|
|
|
|
{
|
|
|
|
|
URigVMGraph* GraphToClean = GraphsToClean[GraphIndex];
|
|
|
|
|
URigVMController* Controller = GetOrCreateController(GraphToClean);
|
|
|
|
|
for(URigVMNode* ModelNode : GraphToClean->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
Controller->RemoveUnusedOrphanedPins(ModelNode, false);
|
|
|
|
|
}
|
2022-05-09 07:34:28 -04:00
|
|
|
|
2022-05-10 09:29:27 -04:00
|
|
|
for(URigVMNode* ModelNode : GraphToClean->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMTemplateNode* TemplateNode = Cast<URigVMTemplateNode>(ModelNode))
|
|
|
|
|
{
|
|
|
|
|
TemplateNode->InvalidateCache();
|
2022-05-20 09:28:06 -04:00
|
|
|
TemplateNode->PostLoad();
|
2022-05-10 09:29:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-05-20 09:28:06 -04:00
|
|
|
#if WITH_EDITOR
|
2022-05-20 11:00:38 -04:00
|
|
|
if (Controller->RecomputeAllTemplateFilteredTypes(false))
|
|
|
|
|
{
|
|
|
|
|
ensureMsgf(false, TEXT("Pin type changed during load %s"), *GetPackage()->GetPathName());
|
|
|
|
|
}
|
2022-05-20 09:28:06 -04:00
|
|
|
#endif
|
2022-01-19 12:37:29 -05:00
|
|
|
}
|
2022-01-13 22:49:09 -05:00
|
|
|
}
|
|
|
|
|
|
2021-01-19 07:26:41 -04:00
|
|
|
void UControlRigBlueprint::HandleReportFromCompiler(EMessageSeverity::Type InSeverity, UObject* InSubject, const FString& InMessage)
|
|
|
|
|
{
|
2021-04-07 13:09:20 -04:00
|
|
|
UObject* SubjectForMessage = InSubject;
|
|
|
|
|
if(URigVMNode* ModelNode = Cast<URigVMNode>(SubjectForMessage))
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigBlueprint* RigBlueprint = ModelNode->GetTypedOuter<UControlRigBlueprint>())
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigGraph* EdGraph = Cast<UControlRigGraph>(RigBlueprint->GetEdGraph(ModelNode->GetGraph())))
|
|
|
|
|
{
|
|
|
|
|
if(UEdGraphNode* EdNode = EdGraph->FindNodeForModelNodeName(ModelNode->GetFName()))
|
|
|
|
|
{
|
|
|
|
|
SubjectForMessage = EdNode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FCompilerResultsLog* Log = CurrentMessageLog ? CurrentMessageLog : &CompileLog;
|
2021-01-19 07:26:41 -04:00
|
|
|
if (InSeverity == EMessageSeverity::Error)
|
|
|
|
|
{
|
|
|
|
|
Status = BS_Error;
|
|
|
|
|
MarkPackageDirty();
|
|
|
|
|
|
2021-09-30 09:59:07 -04:00
|
|
|
// see UnitTest "ControlRig.Basics.OrphanedPins" to learn why errors are suppressed this way
|
|
|
|
|
if (VMCompileSettings.SurpressErrors)
|
|
|
|
|
{
|
|
|
|
|
Log->bSilentMode = true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-07 13:09:20 -04:00
|
|
|
if(InMessage.Contains(TEXT("@@")))
|
|
|
|
|
{
|
|
|
|
|
Log->Error(*InMessage, SubjectForMessage);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Log->Error(*InMessage);
|
|
|
|
|
}
|
2021-01-19 07:26:41 -04:00
|
|
|
|
2021-04-07 13:09:20 -04:00
|
|
|
BroadCastReportCompilerMessage(InSeverity, InSubject, InMessage);
|
2021-09-30 09:59:07 -04:00
|
|
|
|
|
|
|
|
// see UnitTest "ControlRig.Basics.OrphanedPins" to learn why errors are suppressed this way
|
|
|
|
|
if (!VMCompileSettings.SurpressErrors)
|
|
|
|
|
{
|
|
|
|
|
FScriptExceptionHandler::Get().HandleException(ELogVerbosity::Error, *InMessage, *FString());
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-19 07:26:41 -04:00
|
|
|
bErrorsDuringCompilation = true;
|
|
|
|
|
}
|
|
|
|
|
else if (InSeverity == EMessageSeverity::Warning)
|
|
|
|
|
{
|
2021-04-07 13:09:20 -04:00
|
|
|
if(InMessage.Contains(TEXT("@@")))
|
|
|
|
|
{
|
|
|
|
|
Log->Warning(*InMessage, SubjectForMessage);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Log->Warning(*InMessage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BroadCastReportCompilerMessage(InSeverity, InSubject, InMessage);
|
2021-01-19 07:26:41 -04:00
|
|
|
FScriptExceptionHandler::Get().HandleException(ELogVerbosity::Warning, *InMessage, *FString());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-04-07 13:09:20 -04:00
|
|
|
if(InMessage.Contains(TEXT("@@")))
|
|
|
|
|
{
|
|
|
|
|
Log->Note(*InMessage, SubjectForMessage);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Log->Note(*InMessage);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-19 07:26:41 -04:00
|
|
|
UE_LOG(LogControlRigDeveloper, Display, TEXT("%s"), *InMessage);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-07 13:09:20 -04:00
|
|
|
if (UControlRigGraphNode* EdGraphNode = Cast<UControlRigGraphNode>(SubjectForMessage))
|
2021-01-19 07:26:41 -04:00
|
|
|
{
|
2021-04-07 13:09:20 -04:00
|
|
|
EdGraphNode->ErrorType = (int32)InSeverity;
|
|
|
|
|
EdGraphNode->ErrorMsg = InMessage;
|
|
|
|
|
EdGraphNode->bHasCompilerMessage = EdGraphNode->ErrorType <= int32(EMessageSeverity::Info);
|
2021-01-19 07:26:41 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-28 17:11:36 -04:00
|
|
|
TArray<UControlRigBlueprint*> UControlRigBlueprint::GetReferencedControlRigBlueprints()
|
|
|
|
|
{
|
|
|
|
|
TArray<UControlRigBlueprint*> ReferencedBlueprints;
|
|
|
|
|
|
|
|
|
|
TArray<UEdGraph*> EdGraphs;
|
|
|
|
|
GetAllGraphs(EdGraphs);
|
|
|
|
|
for (UEdGraph* EdGraph : EdGraphs)
|
|
|
|
|
{
|
|
|
|
|
for(UEdGraphNode* Node : EdGraph->Nodes)
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigGraphNode* RigNode = Cast<UControlRigGraphNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
if(URigVMFunctionReferenceNode* FunctionRefNode = Cast<URigVMFunctionReferenceNode>(RigNode->GetModelNode()))
|
|
|
|
|
{
|
|
|
|
|
if(URigVMLibraryNode* ReferencedNode = FunctionRefNode->GetReferencedNode())
|
|
|
|
|
{
|
|
|
|
|
if(URigVMFunctionLibrary* ReferencedFunctionLibrary = ReferencedNode->GetLibrary())
|
|
|
|
|
{
|
|
|
|
|
if(ReferencedFunctionLibrary == GetLocalFunctionLibrary())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(UControlRigBlueprint* ReferencedBlueprint = Cast<UControlRigBlueprint>(ReferencedFunctionLibrary->GetOuter()))
|
|
|
|
|
{
|
|
|
|
|
ReferencedBlueprints.AddUnique(ReferencedBlueprint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ReferencedBlueprints;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 11:25:07 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::ClearBreakpoints()
|
|
|
|
|
{
|
2021-06-17 08:12:16 -04:00
|
|
|
for(URigVMNode* Node : RigVMBreakpointNodes)
|
|
|
|
|
{
|
|
|
|
|
Node->SetHasBreakpoint(false);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-28 04:17:19 -04:00
|
|
|
RigVMBreakpointNodes.Empty();
|
2021-04-21 11:25:07 -04:00
|
|
|
RefreshControlRigBreakpoints();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::AddBreakpoint(const FString& InBreakpointNodePath)
|
|
|
|
|
{
|
|
|
|
|
URigVMLibraryNode* FunctionNode = nullptr;
|
|
|
|
|
|
|
|
|
|
// Find the node in the graph
|
2022-05-31 04:27:20 -04:00
|
|
|
for(const URigVMGraph* Model : RigVMClient)
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
URigVMNode* BreakpointNode = Model->FindNode(InBreakpointNodePath);
|
|
|
|
|
if (BreakpointNode == nullptr)
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
// If we cannot find the node, it might be because it is inside a function
|
|
|
|
|
FString FunctionName = InBreakpointNodePath, Right;
|
|
|
|
|
URigVMNode::SplitNodePathAtStart(InBreakpointNodePath, FunctionName, Right);
|
|
|
|
|
|
|
|
|
|
// Look inside the local function library
|
|
|
|
|
if (URigVMLibraryNode* LibraryNode = GetLocalFunctionLibrary()->FindFunction(FName(FunctionName)))
|
|
|
|
|
{
|
|
|
|
|
BreakpointNode = LibraryNode->GetContainedGraph()->FindNode(Right);
|
|
|
|
|
FunctionNode = LibraryNode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(BreakpointNode)
|
|
|
|
|
{
|
|
|
|
|
return AddBreakpoint(BreakpointNode, FunctionNode);
|
2021-04-21 11:25:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
return false;
|
2021-04-21 11:25:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::AddBreakpoint(URigVMNode* InBreakpointNode, URigVMLibraryNode* LibraryNode)
|
|
|
|
|
{
|
|
|
|
|
if (InBreakpointNode == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool bSuccess = true;
|
|
|
|
|
if (LibraryNode)
|
|
|
|
|
{
|
|
|
|
|
// If the breakpoint node is inside a library node, find all references to the library node
|
|
|
|
|
TArray<TSoftObjectPtr<URigVMFunctionReferenceNode>> References = LibraryNode->GetLibrary()->GetReferencesForFunction(LibraryNode->GetFName());
|
|
|
|
|
for (TSoftObjectPtr<URigVMFunctionReferenceNode> Reference : References)
|
|
|
|
|
{
|
|
|
|
|
if (!Reference.IsValid())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprint* ReferenceBlueprint = Reference->GetTypedOuter<UControlRigBlueprint>();
|
|
|
|
|
|
|
|
|
|
// If the reference is not inside another function, add a breakpoint in the blueprint containing the
|
|
|
|
|
// reference, without a function specified
|
|
|
|
|
bool bIsInsideFunction = Reference->GetRootGraph()->IsA<URigVMFunctionLibrary>();
|
|
|
|
|
if(!bIsInsideFunction)
|
|
|
|
|
{
|
|
|
|
|
bSuccess &= ReferenceBlueprint->AddBreakpoint(InBreakpointNode);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Otherwise, we need to add breakpoints to all the blueprints that reference this
|
|
|
|
|
// function (when the blueprint graph is flattened)
|
|
|
|
|
|
|
|
|
|
// Get all the functions containing this reference
|
|
|
|
|
URigVMNode* Node = Reference.Get();
|
|
|
|
|
while (Node->GetGraph() != ReferenceBlueprint->GetLocalFunctionLibrary())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMLibraryNode* ParentLibraryNode = Cast<URigVMLibraryNode>(Node->GetGraph()->GetOuter()))
|
|
|
|
|
{
|
|
|
|
|
// Recursively add breakpoints to the reference blueprint, specifying the parent function
|
|
|
|
|
bSuccess &= ReferenceBlueprint->AddBreakpoint(InBreakpointNode, ParentLibraryNode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Node = Cast<URigVMNode>(Node->GetGraph()->GetOuter());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-04-28 04:17:19 -04:00
|
|
|
if (!RigVMBreakpointNodes.Contains(InBreakpointNode))
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
|
|
|
|
// Add the breakpoint to the VM
|
|
|
|
|
bSuccess = AddBreakpointToControlRig(InBreakpointNode);
|
2021-04-29 09:08:58 -04:00
|
|
|
BreakpointAddedEvent.Broadcast();
|
2021-04-21 11:25:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::AddBreakpointToControlRig(URigVMNode* InBreakpointNode)
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(false));
|
|
|
|
|
const FRigVMByteCode* ByteCode = GetController()->GetCurrentByteCode();
|
|
|
|
|
TSet<FString> AddedCallpaths;
|
|
|
|
|
|
|
|
|
|
if (CDO && ByteCode)
|
|
|
|
|
{
|
|
|
|
|
FRigVMInstructionArray Instructions = ByteCode->GetInstructions();
|
2022-05-31 04:27:20 -04:00
|
|
|
|
2021-04-21 11:25:07 -04:00
|
|
|
// For each instruction, see if the node is in the callpath
|
|
|
|
|
// Only add one breakpoint for each callpath related to this node (i.e. if a node produces multiple
|
|
|
|
|
// instructions, only add a breakpoint to the first instruction)
|
|
|
|
|
for (int32 i = 0; i< Instructions.Num(); ++i)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
const FRigVMASTProxy Proxy = FRigVMASTProxy::MakeFromCallPath(ByteCode->GetCallPathForInstruction(i), Model);
|
|
|
|
|
if (Proxy.GetCallstack().Contains(InBreakpointNode))
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
// Find the callpath related to the breakpoint node
|
|
|
|
|
FRigVMASTProxy BreakpointProxy = Proxy;
|
|
|
|
|
while(BreakpointProxy.GetSubject() != InBreakpointNode)
|
|
|
|
|
{
|
|
|
|
|
BreakpointProxy = BreakpointProxy.GetParent();
|
|
|
|
|
}
|
|
|
|
|
const FString& BreakpointCallPath = BreakpointProxy.GetCallstack().GetCallPath();
|
2021-04-21 11:25:07 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
// Only add this callpath breakpoint once
|
|
|
|
|
if (!AddedCallpaths.Contains(BreakpointCallPath))
|
|
|
|
|
{
|
|
|
|
|
AddedCallpaths.Add(BreakpointCallPath);
|
|
|
|
|
CDO->AddBreakpoint(i, InBreakpointNode, BreakpointProxy.GetCallstack().Num());
|
|
|
|
|
}
|
2021-04-21 11:25:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (AddedCallpaths.Num() > 0)
|
|
|
|
|
{
|
2021-04-28 04:17:19 -04:00
|
|
|
RigVMBreakpointNodes.AddUnique(InBreakpointNode);
|
2021-04-21 11:25:07 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::RemoveBreakpoint(const FString& InBreakpointNodePath)
|
|
|
|
|
{
|
|
|
|
|
// Find the node in the graph
|
2022-05-31 04:27:20 -04:00
|
|
|
URigVMNode* BreakpointNode = nullptr;
|
|
|
|
|
|
|
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
BreakpointNode = Model->FindNode(InBreakpointNodePath);
|
|
|
|
|
if (BreakpointNode == nullptr)
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
// If we cannot find the node, it might be because it is inside a function
|
|
|
|
|
FString FunctionName = InBreakpointNodePath, Right;
|
|
|
|
|
URigVMNode::SplitNodePathAtStart(InBreakpointNodePath, FunctionName, Right);
|
|
|
|
|
|
|
|
|
|
// Look inside the local function library
|
|
|
|
|
if (URigVMLibraryNode* LibraryNode = GetLocalFunctionLibrary()->FindFunction(FName(FunctionName)))
|
|
|
|
|
{
|
|
|
|
|
BreakpointNode = LibraryNode->GetContainedGraph()->FindNode(Right);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(BreakpointNode)
|
|
|
|
|
{
|
|
|
|
|
break;
|
2021-04-21 11:25:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if(BreakpointNode)
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
bool bSuccess = RemoveBreakpoint(BreakpointNode);
|
|
|
|
|
|
|
|
|
|
// Remove the breakpoint from all the loaded dependent blueprints
|
|
|
|
|
TArray<UControlRigBlueprint*> DependentBlueprints = GetDependentBlueprints(true, true);
|
|
|
|
|
DependentBlueprints.Remove(this);
|
|
|
|
|
for (UControlRigBlueprint* Dependent : DependentBlueprints)
|
|
|
|
|
{
|
|
|
|
|
bSuccess &= Dependent->RemoveBreakpoint(BreakpointNode);
|
|
|
|
|
}
|
|
|
|
|
return bSuccess;
|
2021-04-21 11:25:07 -04:00
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
return false;
|
2021-04-21 11:25:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::RemoveBreakpoint(URigVMNode* InBreakpointNode)
|
|
|
|
|
{
|
2021-04-28 04:17:19 -04:00
|
|
|
if (RigVMBreakpointNodes.Contains(InBreakpointNode))
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
2021-04-28 04:17:19 -04:00
|
|
|
RigVMBreakpointNodes.Remove(InBreakpointNode);
|
2021-04-21 11:25:07 -04:00
|
|
|
|
|
|
|
|
// Multiple breakpoint nodes might set a breakpoint to the same instruction. When we remove
|
|
|
|
|
// one of the breakpoint nodes, we do not want to remove the instruction breakpoint if there
|
|
|
|
|
// is another breakpoint node addressing it. For that reason, we just recompute all the
|
|
|
|
|
// breakpoint instructions.
|
|
|
|
|
// Refreshing breakpoints in the control rig will keep the state it had before.
|
|
|
|
|
RefreshControlRigBreakpoints();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::RefreshControlRigBreakpoints()
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(false));
|
2022-06-09 09:38:29 -04:00
|
|
|
CDO->GetDebugInfo().Reset();
|
2021-04-28 04:17:19 -04:00
|
|
|
for (URigVMNode* Node : RigVMBreakpointNodes)
|
2021-04-21 11:25:07 -04:00
|
|
|
{
|
|
|
|
|
AddBreakpointToControlRig(Node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-10 07:13:27 -05:00
|
|
|
TArray<FRigVMReferenceNodeData> UControlRigBlueprint::GetReferenceNodeData() const
|
|
|
|
|
{
|
|
|
|
|
TArray<FRigVMReferenceNodeData> Data;
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
const TArray<URigVMGraph*> AllModels = GetAllModels();
|
2022-02-10 07:13:27 -05:00
|
|
|
for (URigVMGraph* ModelToVisit : AllModels)
|
|
|
|
|
{
|
|
|
|
|
for(URigVMNode* Node : ModelToVisit->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if(URigVMFunctionReferenceNode* ReferenceNode = Cast<URigVMFunctionReferenceNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
Data.Add(FRigVMReferenceNodeData(ReferenceNode));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Data;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 11:25:07 -04:00
|
|
|
#endif
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::RequestControlRigInit()
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
CDO->RequestInit();
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* Instance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(Instance))
|
|
|
|
|
{
|
|
|
|
|
InstanceRig->RequestInit();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
URigVMGraph* UControlRigBlueprint::GetModel(const UEdGraph* InEdGraph) const
|
|
|
|
|
{
|
|
|
|
|
if (InEdGraph == nullptr)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return GetDefaultModel();
|
2020-12-07 07:55:48 -04:00
|
|
|
}
|
|
|
|
|
|
2021-03-10 13:35:54 -04:00
|
|
|
if(InEdGraph->GetOutermost() != GetOutermost())
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 15:00:40 -04:00
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
if (InEdGraph == FunctionLibraryEdGraph)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetFunctionLibrary();
|
2021-01-14 15:00:40 -04:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
const UControlRigGraph* RigGraph = Cast< UControlRigGraph>(InEdGraph);
|
|
|
|
|
check(RigGraph);
|
2022-05-31 04:27:20 -04:00
|
|
|
return GetModel(RigGraph->ModelNodePath);
|
2020-12-07 07:55:48 -04:00
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
URigVMGraph* UControlRigBlueprint::GetModel(const FString& InNodePath) const
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetModel(InNodePath);
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
URigVMGraph* UControlRigBlueprint::GetDefaultModel() const
|
|
|
|
|
{
|
|
|
|
|
return RigVMClient.GetDefaultModel();
|
|
|
|
|
}
|
2020-12-14 08:58:12 -04:00
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
TArray<URigVMGraph*> UControlRigBlueprint::GetAllModels() const
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetAllModels(true, true);
|
2020-12-07 07:55:48 -04:00
|
|
|
}
|
|
|
|
|
|
2021-01-12 06:47:41 -04:00
|
|
|
URigVMFunctionLibrary* UControlRigBlueprint::GetLocalFunctionLibrary() const
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetFunctionLibrary();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
URigVMGraph* UControlRigBlueprint::AddModel(FString InName, bool bSetupUndoRedo, bool bPrintPythonCommand)
|
|
|
|
|
{
|
|
|
|
|
const FString DesiredName = FString::Printf(TEXT("%s %s"),
|
|
|
|
|
UControlRigBlueprint::RigVMModelPrefix, *InName);
|
|
|
|
|
|
|
|
|
|
TGuardValue<bool> EnablePythonPrint(bSuspendPythonMessagesForRigVMClient, !bPrintPythonCommand);
|
|
|
|
|
return RigVMClient.AddModel(*DesiredName, bSetupUndoRedo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::RemoveModel(FString InName, bool bSetupUndoRedo, bool bPrintPythonCommand)
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> EnablePythonPrint(bSuspendPythonMessagesForRigVMClient, !bPrintPythonCommand);
|
|
|
|
|
return RigVMClient.RemoveModel(InName, bSetupUndoRedo);
|
2021-01-12 06:47:41 -04:00
|
|
|
}
|
|
|
|
|
|
2022-04-06 08:26:45 -04:00
|
|
|
URigVMController* UControlRigBlueprint::GetController(const URigVMGraph* InGraph) const
|
2020-12-07 07:55:48 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetController(InGraph);
|
2020-12-07 07:55:48 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-16 13:02:50 -04:00
|
|
|
URigVMController* UControlRigBlueprint::GetControllerByName(const FString InGraphName) const
|
|
|
|
|
{
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (Graph->GetName() == InGraphName || Graph->GetGraphName() == InGraphName)
|
2021-06-16 13:02:50 -04:00
|
|
|
{
|
|
|
|
|
return GetController(Graph);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
URigVMController* UControlRigBlueprint::GetOrCreateController(URigVMGraph* InGraph)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetOrCreateController(InGraph);
|
2020-12-07 07:55:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
URigVMController* UControlRigBlueprint::GetController(const UEdGraph* InEdGraph) const
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetController(InEdGraph);
|
2020-12-07 07:55:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
URigVMController* UControlRigBlueprint::GetOrCreateController(const UEdGraph* InEdGraph)
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return RigVMClient.GetOrCreateController(InEdGraph);
|
2020-12-07 07:55:48 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-16 13:02:50 -04:00
|
|
|
TArray<FString> UControlRigBlueprint::GeneratePythonCommands(const FString InNewBlueprintName)
|
|
|
|
|
{
|
2022-04-07 13:03:59 -04:00
|
|
|
TArray<FString> InternalCommands;
|
|
|
|
|
InternalCommands.Add(TEXT("unreal.load_module('ControlRigDeveloper')"));
|
|
|
|
|
InternalCommands.Add(TEXT("factory = unreal.ControlRigBlueprintFactory"));
|
|
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint = factory.create_new_control_rig_asset(desired_package_path = '%s')"), *InNewBlueprintName));
|
|
|
|
|
InternalCommands.Add(TEXT("library = blueprint.get_local_function_library()"));
|
|
|
|
|
InternalCommands.Add(TEXT("library_controller = blueprint.get_controller(library)"));
|
|
|
|
|
InternalCommands.Add(TEXT("hierarchy = blueprint.hierarchy"));
|
|
|
|
|
InternalCommands.Add(TEXT("hierarchy_controller = hierarchy.get_controller()"));
|
2021-06-16 13:02:50 -04:00
|
|
|
|
|
|
|
|
// Hierarchy
|
2022-04-07 13:03:59 -04:00
|
|
|
InternalCommands.Append(Hierarchy->GetController(true)->GeneratePythonCommands());
|
2021-06-16 13:02:50 -04:00
|
|
|
|
|
|
|
|
// Add variables
|
|
|
|
|
for (const FBPVariableDescription& Variable : NewVariables)
|
|
|
|
|
{
|
2021-11-18 08:00:07 -05:00
|
|
|
const FRigVMExternalVariable ExternalVariable = RigVMTypeUtils::ExternalVariableFromBPVariableDescription(Variable);
|
|
|
|
|
FString CPPType;
|
|
|
|
|
UObject* CPPTypeObject = nullptr;
|
|
|
|
|
RigVMTypeUtils::CPPTypeFromExternalVariable(ExternalVariable, CPPType, &CPPTypeObject);
|
|
|
|
|
if (CPPTypeObject)
|
|
|
|
|
{
|
|
|
|
|
if (ExternalVariable.bIsArray)
|
|
|
|
|
{
|
|
|
|
|
CPPType = RigVMTypeUtils::ArrayTypeFromBaseType(CPPTypeObject->GetPathName());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CPPType = CPPTypeObject->GetPathName();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-16 13:02:50 -04:00
|
|
|
// FName AddMemberVariable(const FName& InName, const FString& InCPPType, bool bIsPublic = false, bool bIsReadOnly = false, FString InDefaultValue = TEXT(""));
|
2022-04-07 13:03:59 -04:00
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint.add_member_variable('%s', '%s', %s, %s)"),
|
2021-06-16 13:02:50 -04:00
|
|
|
*ExternalVariable.Name.ToString(),
|
2021-11-18 08:00:07 -05:00
|
|
|
*CPPType,
|
2021-06-16 13:02:50 -04:00
|
|
|
ExternalVariable.bIsPublic ? TEXT("True") : TEXT("False"),
|
|
|
|
|
ExternalVariable.bIsReadOnly ? TEXT("True") : TEXT("False")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create graphs
|
|
|
|
|
{
|
|
|
|
|
// Find all graphs to process and sort them by dependencies
|
|
|
|
|
TArray<URigVMGraph*> ProcessedGraphs;
|
|
|
|
|
while (ProcessedGraphs.Num() < GetAllModels().Num())
|
|
|
|
|
{
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
|
|
|
|
if (ProcessedGraphs.Contains(Graph))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool bFoundUnprocessedReference = false;
|
|
|
|
|
for (auto Node : Graph->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMFunctionReferenceNode* Reference = Cast<URigVMFunctionReferenceNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
if (Reference->GetContainedGraph()->GetPackage() != GetPackage())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ProcessedGraphs.Contains(Reference->GetContainedGraph()))
|
|
|
|
|
{
|
|
|
|
|
bFoundUnprocessedReference = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
if (!ProcessedGraphs.Contains(CollapseNode->GetContainedGraph()))
|
|
|
|
|
{
|
|
|
|
|
bFoundUnprocessedReference = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!bFoundUnprocessedReference)
|
|
|
|
|
{
|
|
|
|
|
ProcessedGraphs.Add(Graph);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dump python commands for each graph
|
|
|
|
|
for (URigVMGraph* Graph : ProcessedGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (Graph->IsA<URigVMFunctionLibrary>())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
URigVMController* Controller = GetController(Graph);
|
|
|
|
|
if (Graph->GetParentGraph())
|
|
|
|
|
{
|
|
|
|
|
// Add them all as functions (even collapsed graphs)
|
|
|
|
|
// The controller will deal with deleting collapsed graph function when it creates the collapse node
|
|
|
|
|
{
|
|
|
|
|
// Add Function
|
2022-04-07 13:03:59 -04:00
|
|
|
InternalCommands.Add(FString::Printf(TEXT("function_%s = library_controller.add_function_to_library('%s', mutable=%s)\ngraph = function_%s.get_contained_graph()"),
|
2021-06-16 13:02:50 -04:00
|
|
|
*RigVMPythonUtils::NameToPep8(Graph->GetGraphName()),
|
|
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
Graph->GetEntryNode()->IsMutable() ? TEXT("True") : TEXT("False"),
|
|
|
|
|
*RigVMPythonUtils::NameToPep8(Graph->GetGraphName())));
|
2022-05-02 12:25:41 -04:00
|
|
|
|
|
|
|
|
URigVMLibraryNode* LibraryNode = Cast<URigVMLibraryNode>(Graph->GetOuter());
|
|
|
|
|
|
|
|
|
|
InternalCommands.Add(FString::Printf(TEXT("library_controller.set_node_category_by_name('%s', '%s')"),
|
|
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
*LibraryNode->GetNodeCategory()));
|
|
|
|
|
|
|
|
|
|
InternalCommands.Add(FString::Printf(TEXT("library_controller.set_node_keywords_by_name('%s', '%s')"),
|
|
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
*LibraryNode->GetNodeKeywords() ));
|
|
|
|
|
|
|
|
|
|
InternalCommands.Add(FString::Printf(TEXT("library_controller.set_node_description_by_name('%s', '%s')"),
|
|
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
*LibraryNode->GetNodeDescription()));
|
|
|
|
|
|
|
|
|
|
InternalCommands.Add(FString::Printf(TEXT("library_controller.set_node_color_by_name('%s', %s)"),
|
|
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
*RigVMPythonUtils::LinearColorToPythonString(LibraryNode->GetNodeColor()) ));
|
2021-06-16 13:02:50 -04:00
|
|
|
|
|
|
|
|
URigVMFunctionEntryNode* EntryNode = Graph->GetEntryNode();
|
|
|
|
|
URigVMFunctionReturnNode* ReturnNode = Graph->GetReturnNode();
|
|
|
|
|
|
|
|
|
|
// Set Entry and Return nodes in the correct position
|
|
|
|
|
{
|
|
|
|
|
//bool SetNodePositionByName(const FName& InNodeName, const FVector2D& InPosition, bool bSetupUndoRedo = true, bool bMergeUndoAction = false);
|
2022-04-07 13:03:59 -04:00
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint.get_controller_by_name('%s').set_node_position_by_name('Entry', unreal.Vector2D(%f, %f))"),
|
2021-06-16 13:02:50 -04:00
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
EntryNode->GetPosition().X,
|
|
|
|
|
EntryNode->GetPosition().Y));
|
|
|
|
|
|
2022-04-07 13:03:59 -04:00
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint.get_controller_by_name('%s').set_node_position_by_name('Return', unreal.Vector2D(%f, %f))"),
|
2021-06-16 13:02:50 -04:00
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
ReturnNode->GetPosition().X,
|
|
|
|
|
ReturnNode->GetPosition().Y));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add Exposed Pins
|
|
|
|
|
{
|
2022-05-05 11:55:01 -04:00
|
|
|
|
|
|
|
|
bool bHitFirstExecute = false;
|
2021-06-16 13:02:50 -04:00
|
|
|
for (auto Pin : EntryNode->GetPins())
|
|
|
|
|
{
|
|
|
|
|
if (Pin->GetDirection() != ERigVMPinDirection::Output)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-05 11:55:01 -04:00
|
|
|
if(Pin->IsExecuteContext())
|
|
|
|
|
{
|
|
|
|
|
if(!bHitFirstExecute)
|
|
|
|
|
{
|
|
|
|
|
bHitFirstExecute = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 13:02:50 -04:00
|
|
|
// FName AddExposedPin(const FName& InPinName, ERigVMPinDirection InDirection, const FString& InCPPType, const FName& InCPPTypeObjectPath, const FString& InDefaultValue, bool bSetupUndoRedo = true);
|
2022-05-13 05:53:36 -04:00
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint.get_controller_by_name('%s').add_exposed_pin('%s', %s, '%s', '%s', '%s')"),
|
2021-06-16 13:02:50 -04:00
|
|
|
*Graph->GetGraphName(),
|
|
|
|
|
*Pin->GetName(),
|
2022-05-13 05:53:36 -04:00
|
|
|
*RigVMPythonUtils::EnumValueToPythonString<ERigVMPinDirection>((int64)ERigVMPinDirection::Input),
|
2021-06-16 13:02:50 -04:00
|
|
|
*Pin->GetCPPType(),
|
|
|
|
|
Pin->GetCPPTypeObject() ? *Pin->GetCPPTypeObject()->GetPathName() : TEXT(""),
|
|
|
|
|
*Pin->GetDefaultValue()));
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-05 11:55:01 -04:00
|
|
|
bHitFirstExecute = false;
|
2021-06-16 13:02:50 -04:00
|
|
|
for (auto Pin : ReturnNode->GetPins())
|
|
|
|
|
{
|
|
|
|
|
if (Pin->GetDirection() != ERigVMPinDirection::Input)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-05 11:55:01 -04:00
|
|
|
if(Pin->IsExecuteContext())
|
|
|
|
|
{
|
|
|
|
|
if(!bHitFirstExecute)
|
|
|
|
|
{
|
|
|
|
|
bHitFirstExecute = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 13:02:50 -04:00
|
|
|
// FName AddExposedPin(const FName& InPinName, ERigVMPinDirection InDirection, const FString& InCPPType, const FName& InCPPTypeObjectPath, const FString& InDefaultValue, bool bSetupUndoRedo = true);
|
2022-05-13 05:53:36 -04:00
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint.get_controller_by_name('%s').add_exposed_pin('%s', %s, '%s', '%s', '%s')"),
|
2021-06-16 13:02:50 -04:00
|
|
|
*Graph->GetGraphName(),
|
2022-05-13 05:53:36 -04:00
|
|
|
*Pin->GetName(),
|
|
|
|
|
*RigVMPythonUtils::EnumValueToPythonString<ERigVMPinDirection>((int64)ERigVMPinDirection::Output),
|
2021-06-16 13:02:50 -04:00
|
|
|
*Pin->GetCPPType(),
|
2022-05-02 12:25:41 -04:00
|
|
|
Pin->GetCPPTypeObject() ? *Pin->GetCPPTypeObject()->GetPathName() : TEXT(""),
|
2021-06-16 13:02:50 -04:00
|
|
|
*Pin->GetDefaultValue()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
else if(Graph != GetDefaultModel())
|
|
|
|
|
{
|
|
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint.add_model('%s')"),
|
|
|
|
|
*Graph->GetName()));
|
|
|
|
|
}
|
2021-06-16 13:02:50 -04:00
|
|
|
|
2022-04-07 13:03:59 -04:00
|
|
|
InternalCommands.Append(Controller->GeneratePythonCommands());
|
2021-06-16 13:02:50 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-10 14:19:17 -04:00
|
|
|
#if WITH_EDITORONLY_DATA
|
2021-06-16 13:02:50 -04:00
|
|
|
FString PreviewMeshPath = GetPreviewMesh()->GetPathName();
|
2022-04-07 13:03:59 -04:00
|
|
|
InternalCommands.Add(FString::Printf(TEXT("blueprint.set_preview_mesh(unreal.load_object(name='%s', outer=None))"),
|
2021-06-16 13:02:50 -04:00
|
|
|
*PreviewMeshPath));
|
2021-08-10 14:19:17 -04:00
|
|
|
#endif
|
2021-06-16 13:02:50 -04:00
|
|
|
|
2022-04-07 13:03:59 -04:00
|
|
|
// Split multiple commands into different array elements
|
|
|
|
|
TArray<FString> InnerFunctionCmds;
|
|
|
|
|
for (FString Cmd : InternalCommands)
|
|
|
|
|
{
|
|
|
|
|
FString Left, Right=Cmd;
|
|
|
|
|
while (Right.Split(TEXT("\n"), &Left, &Right))
|
|
|
|
|
{
|
|
|
|
|
InnerFunctionCmds.Add(Left);
|
|
|
|
|
}
|
|
|
|
|
InnerFunctionCmds.Add(Right);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Define a function and insert all the commands
|
|
|
|
|
// We do not want to pollute the global state with our definitions
|
|
|
|
|
TArray<FString> Commands;
|
|
|
|
|
Commands.Add(FString::Printf(TEXT("import unreal\n"
|
|
|
|
|
"def create_control_rig():\n")));
|
|
|
|
|
for (const FString& InnerCmd : InnerFunctionCmds)
|
|
|
|
|
{
|
|
|
|
|
Commands.Add(FString::Printf(TEXT("\t%s"), *InnerCmd));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Commands.Add(TEXT("create_control_rig()\n"));
|
2021-06-16 13:02:50 -04:00
|
|
|
return Commands;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
URigVMGraph* UControlRigBlueprint::GetTemplateModel()
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
if (TemplateModel == nullptr)
|
|
|
|
|
{
|
|
|
|
|
TemplateModel = NewObject<URigVMGraph>(this, TEXT("TemplateModel"));
|
|
|
|
|
TemplateModel->SetFlags(RF_Transient);
|
2022-04-21 09:10:19 -04:00
|
|
|
TemplateModel->SetExecuteContextStruct(FControlRigExecuteContext::StaticStruct());
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
|
|
|
|
return TemplateModel;
|
|
|
|
|
#else
|
|
|
|
|
return nullptr;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
URigVMController* UControlRigBlueprint::GetTemplateController()
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
if (TemplateController == nullptr)
|
|
|
|
|
{
|
|
|
|
|
TemplateController = NewObject<URigVMController>(this, TEXT("TemplateController"));
|
|
|
|
|
TemplateController->SetGraph(GetTemplateModel());
|
|
|
|
|
TemplateController->EnableReporting(false);
|
|
|
|
|
TemplateController->SetFlags(RF_Transient);
|
|
|
|
|
}
|
|
|
|
|
return TemplateController;
|
|
|
|
|
#else
|
|
|
|
|
return nullptr;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UEdGraph* UControlRigBlueprint::GetEdGraph(URigVMGraph* InModel) const
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
return Cast<UEdGraph>(GetEditorObjectForRigVMGraph(InModel));
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UEdGraph* UControlRigBlueprint::GetEdGraph(const FString& InNodePath) const
|
|
|
|
|
{
|
|
|
|
|
if (URigVMGraph* ModelForNodePath = GetModel(InNodePath))
|
|
|
|
|
{
|
|
|
|
|
return GetEdGraph(ModelForNodePath);
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 05:52:25 -04:00
|
|
|
bool UControlRigBlueprint::IsFunctionPublic(const FName& InFunctionName) const
|
|
|
|
|
{
|
|
|
|
|
for(const FControlRigPublicFunctionData& PublicFunction : PublicFunctions)
|
|
|
|
|
{
|
|
|
|
|
if(PublicFunction.Name == InFunctionName)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::MarkFunctionPublic(const FName& InFunctionName, bool bIsPublic)
|
|
|
|
|
{
|
|
|
|
|
if(IsFunctionPublic(InFunctionName) == bIsPublic)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Modify();
|
|
|
|
|
|
|
|
|
|
if(bIsPublic)
|
|
|
|
|
{
|
|
|
|
|
if(URigVMLibraryNode* FunctionNode = GetLocalFunctionLibrary()->FindFunction(InFunctionName))
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigGraph* RigGraph = Cast<UControlRigGraph>(GetEdGraph(FunctionNode->GetContainedGraph())))
|
|
|
|
|
{
|
|
|
|
|
const FControlRigPublicFunctionData NewFunctionData = RigGraph->GetPublicFunctionData();
|
|
|
|
|
for(FControlRigPublicFunctionData& ExistingFunctionData : PublicFunctions)
|
|
|
|
|
{
|
|
|
|
|
if(ExistingFunctionData.Name == NewFunctionData.Name)
|
|
|
|
|
{
|
|
|
|
|
ExistingFunctionData = NewFunctionData;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PublicFunctions.Add(NewFunctionData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for(int32 Index = 0; Index < PublicFunctions.Num(); Index++)
|
|
|
|
|
{
|
|
|
|
|
if(PublicFunctions[Index].Name == InFunctionName)
|
|
|
|
|
{
|
|
|
|
|
PublicFunctions.RemoveAt(Index);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-15 14:30:33 -04:00
|
|
|
TArray<UControlRigBlueprint*> UControlRigBlueprint::GetDependencies(bool bRecursive) const
|
|
|
|
|
{
|
|
|
|
|
TArray<UControlRigBlueprint*> Dependencies;
|
|
|
|
|
|
|
|
|
|
TArray<URigVMGraph*> Graphs = GetAllModels();
|
|
|
|
|
for(URigVMGraph* Graph : Graphs)
|
|
|
|
|
{
|
|
|
|
|
for(URigVMNode* Node : Graph->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if(URigVMFunctionReferenceNode* FunctionReferenceNode = Cast<URigVMFunctionReferenceNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
if(URigVMLibraryNode* LibraryNode = FunctionReferenceNode->GetReferencedNode())
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigBlueprint* DependencyBlueprint = LibraryNode->GetTypedOuter<UControlRigBlueprint>())
|
|
|
|
|
{
|
|
|
|
|
if(DependencyBlueprint != this)
|
|
|
|
|
{
|
|
|
|
|
if(!Dependencies.Contains(DependencyBlueprint))
|
|
|
|
|
{
|
|
|
|
|
Dependencies.Add(DependencyBlueprint);
|
|
|
|
|
|
|
|
|
|
if(bRecursive)
|
|
|
|
|
{
|
|
|
|
|
TArray<UControlRigBlueprint*> ChildDependencies = DependencyBlueprint->GetDependencies(true);
|
|
|
|
|
for(UControlRigBlueprint* ChildDependency : ChildDependencies)
|
|
|
|
|
{
|
|
|
|
|
Dependencies.AddUnique(ChildDependency);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Dependencies;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<FAssetData> UControlRigBlueprint::GetDependentAssets() const
|
|
|
|
|
{
|
|
|
|
|
TArray<FAssetData> Dependents;
|
|
|
|
|
TArray<FName> AssetPaths;
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if(URigVMFunctionLibrary* FunctionLibrary = RigVMClient.GetFunctionLibrary())
|
2021-04-15 14:30:33 -04:00
|
|
|
{
|
|
|
|
|
const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
|
|
|
TArray<URigVMLibraryNode*> Functions = FunctionLibrary->GetFunctions();
|
|
|
|
|
for(URigVMLibraryNode* Function : Functions)
|
|
|
|
|
{
|
|
|
|
|
const FName FunctionName = Function->GetFName();
|
|
|
|
|
if(IsFunctionPublic(FunctionName))
|
|
|
|
|
{
|
|
|
|
|
TArray<TSoftObjectPtr<URigVMFunctionReferenceNode>> References = FunctionLibrary->GetReferencesForFunction(FunctionName);
|
|
|
|
|
for(const TSoftObjectPtr<URigVMFunctionReferenceNode>& Reference : References)
|
|
|
|
|
{
|
|
|
|
|
const FName AssetPath = Reference.ToSoftObjectPath().GetAssetPathName();
|
|
|
|
|
if(AssetPath.ToString().StartsWith(TEXT("/Engine/Transient")))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!AssetPaths.Contains(AssetPath))
|
|
|
|
|
{
|
|
|
|
|
AssetPaths.Add(AssetPath);
|
|
|
|
|
|
|
|
|
|
const FAssetData AssetData = AssetRegistryModule.Get().GetAssetByObjectPath(*AssetPath.ToString());
|
|
|
|
|
if(AssetData.IsValid())
|
|
|
|
|
{
|
|
|
|
|
Dependents.Add(AssetData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Dependents;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 11:25:07 -04:00
|
|
|
TArray<UControlRigBlueprint*> UControlRigBlueprint::GetDependentBlueprints(bool bRecursive, bool bOnlyLoaded) const
|
2021-04-15 14:30:33 -04:00
|
|
|
{
|
|
|
|
|
TArray<FAssetData> Assets = GetDependentAssets();
|
|
|
|
|
TArray<UControlRigBlueprint*> Dependents;
|
|
|
|
|
|
|
|
|
|
for(const FAssetData& Asset : Assets)
|
|
|
|
|
{
|
2021-04-21 11:25:07 -04:00
|
|
|
if (!bOnlyLoaded || Asset.IsAssetLoaded())
|
2021-04-15 14:30:33 -04:00
|
|
|
{
|
2021-04-21 11:25:07 -04:00
|
|
|
if(UControlRigBlueprint* Dependent = Cast<UControlRigBlueprint>(Asset.GetAsset()))
|
2021-04-15 14:30:33 -04:00
|
|
|
{
|
2021-04-21 11:25:07 -04:00
|
|
|
if(!Dependents.Contains(Dependent))
|
2021-04-15 14:30:33 -04:00
|
|
|
{
|
2021-04-21 11:25:07 -04:00
|
|
|
Dependents.Add(Dependent);
|
|
|
|
|
|
|
|
|
|
if(bRecursive && Dependent != this)
|
2021-04-15 14:30:33 -04:00
|
|
|
{
|
2021-04-21 11:25:07 -04:00
|
|
|
TArray<UControlRigBlueprint*> ParentDependents = Dependent->GetDependentBlueprints(true);
|
|
|
|
|
for(UControlRigBlueprint* ParentDependent : ParentDependents)
|
|
|
|
|
{
|
|
|
|
|
Dependents.AddUnique(ParentDependent);
|
|
|
|
|
}
|
2021-04-15 14:30:33 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Dependents;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 11:38:48 -05:00
|
|
|
void UControlRigBlueprint::GetTypeActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
|
|
|
|
{
|
2019-07-16 11:49:59 -04:00
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
IControlRigEditorModule::Get().GetTypeActions((UControlRigBlueprint*)this, ActionRegistrar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::GetInstanceActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
|
|
|
|
{
|
|
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
|
|
|
|
|
|
|
|
|
IControlRigEditorModule::Get().GetInstanceActions((UControlRigBlueprint*)this, ActionRegistrar);
|
2019-01-08 11:38:48 -05:00
|
|
|
}
|
|
|
|
|
|
2019-07-11 12:35:32 -04:00
|
|
|
void UControlRigBlueprint::SetObjectBeingDebugged(UObject* NewObject)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* PreviousRigBeingDebugged = Cast<UControlRig>(GetObjectBeingDebugged());
|
|
|
|
|
if (PreviousRigBeingDebugged && PreviousRigBeingDebugged != NewObject)
|
|
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
PreviousRigBeingDebugged->DrawInterface.Reset();
|
2019-07-11 12:35:32 -04:00
|
|
|
PreviousRigBeingDebugged->ControlRigLog = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Super::SetObjectBeingDebugged(NewObject);
|
2020-09-24 00:43:27 -04:00
|
|
|
|
|
|
|
|
if (Validator)
|
|
|
|
|
{
|
|
|
|
|
if (Validator->GetControlRig() != nullptr)
|
|
|
|
|
{
|
|
|
|
|
Validator->SetControlRig(Cast<UControlRig>(GetObjectBeingDebugged()));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-17 19:12:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::PostTransacted(const FTransactionObjectEvent& TransactionEvent)
|
|
|
|
|
{
|
|
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
|
|
|
|
Super::PostTransacted(TransactionEvent);
|
|
|
|
|
|
|
|
|
|
if (TransactionEvent.GetEventType() == ETransactionObjectEventType::UndoRedo)
|
|
|
|
|
{
|
2021-10-20 04:50:20 -04:00
|
|
|
TArray<FName> PropertiesChanged = TransactionEvent.GetChangedProperties();
|
2022-05-31 04:27:20 -04:00
|
|
|
if (PropertiesChanged.Contains(GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, Hierarchy)))
|
2019-09-17 19:12:19 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
int32 TransactionIndex = GEditor->Trans->FindTransactionIndex(TransactionEvent.GetTransactionId());
|
|
|
|
|
const FTransaction* Transaction = GEditor->Trans->GetTransaction(TransactionIndex);
|
|
|
|
|
|
|
|
|
|
if (Transaction->GenerateDiff().TransactionTitle == TEXT("Transform Gizmo"))
|
|
|
|
|
{
|
|
|
|
|
PropagatePoseFromBPToInstances();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
PropagateHierarchyFromBPToInstances();
|
2019-09-17 19:12:19 -04:00
|
|
|
|
|
|
|
|
// make sure the bone name list is up 2 date for the editor graph
|
2021-02-22 13:36:33 -04:00
|
|
|
for (UEdGraph* Graph : UbergraphPages)
|
|
|
|
|
{
|
|
|
|
|
UControlRigGraph* RigGraph = Cast<UControlRigGraph>(Graph);
|
2019-09-17 19:12:19 -04:00
|
|
|
if (RigGraph == nullptr)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-02-22 13:36:33 -04:00
|
|
|
RigGraph->CacheNameLists(Hierarchy, &DrawContainer);
|
2019-09-17 19:12:19 -04:00
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
RequestAutoVMRecompilation();
|
|
|
|
|
MarkPackageDirty();
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if (PropertiesChanged.Contains(GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, DrawContainer)))
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
|
|
|
|
PropagateDrawInstructionsFromBPToInstances();
|
2019-09-17 19:12:19 -04:00
|
|
|
}
|
2021-08-20 12:55:39 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if (PropertiesChanged.Contains(GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, VMRuntimeSettings)))
|
2021-08-20 12:55:39 -04:00
|
|
|
{
|
|
|
|
|
PropagateRuntimeSettingsFromBPToInstances();
|
|
|
|
|
}
|
2021-10-20 04:50:20 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if (PropertiesChanged.Contains(GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, NewVariables)))
|
2021-10-20 04:50:20 -04:00
|
|
|
{
|
|
|
|
|
if (RefreshEditorEvent.IsBound())
|
|
|
|
|
{
|
|
|
|
|
RefreshEditorEvent.Broadcast(this);
|
|
|
|
|
}
|
|
|
|
|
MarkPackageDirty();
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
if (PropertiesChanged.Contains(GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, RigVMClient)) ||
|
|
|
|
|
PropertiesChanged.Contains(GET_MEMBER_NAME_CHECKED(UControlRigBlueprint, UbergraphPages)))
|
|
|
|
|
{
|
|
|
|
|
RigVMClient.PostTransacted(TransactionEvent);
|
|
|
|
|
|
|
|
|
|
RecompileVM();
|
|
|
|
|
MarkPackageDirty();
|
|
|
|
|
}
|
2019-09-17 19:12:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
void UControlRigBlueprint::ReplaceDeprecatedNodes()
|
|
|
|
|
{
|
|
|
|
|
TArray<UEdGraph*> EdGraphs;
|
|
|
|
|
GetAllGraphs(EdGraphs);
|
|
|
|
|
|
|
|
|
|
for (UEdGraph* EdGraph : EdGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* RigGraph = Cast<UControlRigGraph>(EdGraph))
|
|
|
|
|
{
|
|
|
|
|
RigGraph->Schema = UControlRigGraphSchema::StaticClass();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Super::ReplaceDeprecatedNodes();
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-13 14:45:23 -04:00
|
|
|
void UControlRigBlueprint::PostDuplicate(bool bDuplicateForPIE)
|
2021-09-13 13:52:43 -04:00
|
|
|
{
|
2022-02-23 11:18:49 -05:00
|
|
|
RefreshAllModels();
|
|
|
|
|
|
2021-09-13 14:45:23 -04:00
|
|
|
Super::PostDuplicate(bDuplicateForPIE);
|
|
|
|
|
|
2021-09-17 11:26:26 -04:00
|
|
|
if (URigHierarchyController* Controller = Hierarchy->GetController(true))
|
2021-09-13 13:52:43 -04:00
|
|
|
{
|
2021-09-17 11:26:26 -04:00
|
|
|
Controller->OnModified().RemoveAll(this);
|
|
|
|
|
Controller->OnModified().AddUObject(this, &UControlRigBlueprint::HandleHierarchyModified);
|
2021-09-13 13:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
|
2021-11-07 23:43:01 -05:00
|
|
|
RecompileVM();
|
2021-09-13 13:52:43 -04:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
FRigVMGraphModifiedEvent& UControlRigBlueprint::OnModified()
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
return ModifiedEvent;
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
FOnVMCompiledEvent& UControlRigBlueprint::OnVMCompiled()
|
|
|
|
|
{
|
|
|
|
|
return VMCompiledEvent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<UControlRigBlueprint*> UControlRigBlueprint::GetCurrentlyOpenRigBlueprints()
|
|
|
|
|
{
|
|
|
|
|
return sCurrentlyOpenedRigBlueprints;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-26 11:52:22 -04:00
|
|
|
UClass* UControlRigBlueprint::GetControlRigClass()
|
|
|
|
|
{
|
|
|
|
|
return GeneratedClass;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UControlRig* UControlRigBlueprint::CreateControlRig()
|
|
|
|
|
{
|
|
|
|
|
RecompileVMIfRequired();
|
|
|
|
|
|
|
|
|
|
UControlRig* Rig = NewObject<UControlRig>(this, GetControlRigClass());
|
|
|
|
|
Rig->Initialize(true);
|
|
|
|
|
return Rig;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
TArray<UStruct*> UControlRigBlueprint::GetAvailableRigUnits()
|
|
|
|
|
{
|
|
|
|
|
const TArray<FRigVMFunction>& Functions = FRigVMRegistry::Get().GetFunctions();
|
|
|
|
|
|
|
|
|
|
TArray<UStruct*> Structs;
|
|
|
|
|
UStruct* BaseStruct = FRigUnit::StaticStruct();
|
|
|
|
|
|
|
|
|
|
for (const FRigVMFunction& Function : Functions)
|
|
|
|
|
{
|
|
|
|
|
if (Function.Struct)
|
|
|
|
|
{
|
|
|
|
|
if (Function.Struct->IsChildOf(BaseStruct))
|
|
|
|
|
{
|
|
|
|
|
Structs.Add(Function.Struct);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Structs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
2022-03-18 07:41:19 -04:00
|
|
|
TArray<FRigVMGraphVariableDescription> UControlRigBlueprint::GetMemberVariables() const
|
|
|
|
|
{
|
|
|
|
|
TArray<FRigVMGraphVariableDescription> Variables;
|
|
|
|
|
for (const FBPVariableDescription& BPVariable : NewVariables)
|
|
|
|
|
{
|
|
|
|
|
FRigVMGraphVariableDescription NewVariable;
|
|
|
|
|
NewVariable.Name = BPVariable.VarName;
|
|
|
|
|
NewVariable.DefaultValue = BPVariable.DefaultValue;
|
|
|
|
|
FString CPPType;
|
|
|
|
|
UObject* CPPTypeObject;
|
|
|
|
|
RigVMTypeUtils::CPPTypeFromPinType(BPVariable.VarType, CPPType, &CPPTypeObject);
|
|
|
|
|
NewVariable.CPPType = CPPType;
|
|
|
|
|
NewVariable.CPPTypeObject = CPPTypeObject;
|
|
|
|
|
Variables.Add(NewVariable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Variables;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-21 10:14:22 -04:00
|
|
|
FName UControlRigBlueprint::AddMemberVariable(const FName& InName, const FString& InCPPType, bool bIsPublic, bool bIsReadOnly, FString InDefaultValue)
|
2020-11-26 11:52:22 -04:00
|
|
|
{
|
2021-11-29 11:26:01 -05:00
|
|
|
FRigVMExternalVariable Variable = RigVMTypeUtils::ExternalVariableFromCPPTypePath(InName, InCPPType, bIsPublic, bIsReadOnly);
|
2021-01-21 10:14:22 -04:00
|
|
|
FName Result = AddCRMemberVariableFromExternal(Variable, InDefaultValue);
|
2020-11-26 11:52:22 -04:00
|
|
|
if (!Result.IsNone())
|
|
|
|
|
{
|
|
|
|
|
FBPCompileRequest Request(this, EBlueprintCompileOptions::None, nullptr);
|
|
|
|
|
FBlueprintCompilationManager::CompileSynchronously(Request);
|
|
|
|
|
}
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-22 04:23:56 -04:00
|
|
|
bool UControlRigBlueprint::RemoveMemberVariable(const FName& InName)
|
|
|
|
|
{
|
|
|
|
|
const int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InName);
|
|
|
|
|
if (VarIndex == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBlueprintEditorUtils::RemoveMemberVariable(this, InName);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::RenameMemberVariable(const FName& InOldName, const FName& InNewName)
|
|
|
|
|
{
|
|
|
|
|
int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InOldName);
|
|
|
|
|
if (VarIndex == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InNewName);
|
|
|
|
|
if (VarIndex != INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBlueprintEditorUtils::RenameMemberVariable(this, InOldName, InNewName);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::ChangeMemberVariableType(const FName& InName, const FString& InCPPType, bool bIsPublic,
|
|
|
|
|
bool bIsReadOnly, FString InDefaultValue)
|
|
|
|
|
{
|
|
|
|
|
int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InName);
|
|
|
|
|
if (VarIndex == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRigVMExternalVariable Variable;
|
|
|
|
|
Variable.Name = InName;
|
|
|
|
|
Variable.bIsPublic = bIsPublic;
|
|
|
|
|
Variable.bIsReadOnly = bIsReadOnly;
|
|
|
|
|
|
|
|
|
|
FString CPPType = InCPPType;
|
|
|
|
|
if (CPPType.StartsWith(TEXT("TMap<")))
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogControlRigDeveloper, Warning, TEXT("TMap Variables are not supported."));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 08:00:07 -05:00
|
|
|
Variable.bIsArray = RigVMTypeUtils::IsArrayType(CPPType);
|
2021-07-22 04:23:56 -04:00
|
|
|
if (Variable.bIsArray)
|
|
|
|
|
{
|
2021-11-24 05:34:30 -05:00
|
|
|
CPPType = RigVMTypeUtils::BaseTypeFromArrayType(CPPType);
|
2021-07-22 04:23:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPPType == TEXT("bool"))
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeName = *CPPType;
|
|
|
|
|
Variable.Size = sizeof(bool);
|
|
|
|
|
}
|
|
|
|
|
else if (CPPType == TEXT("float"))
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeName = *CPPType;
|
|
|
|
|
Variable.Size = sizeof(float);
|
|
|
|
|
}
|
|
|
|
|
else if (CPPType == TEXT("double"))
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeName = *CPPType;
|
|
|
|
|
Variable.Size = sizeof(double);
|
|
|
|
|
}
|
|
|
|
|
else if (CPPType == TEXT("int32"))
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeName = *CPPType;
|
|
|
|
|
Variable.Size = sizeof(int32);
|
|
|
|
|
}
|
|
|
|
|
else if (CPPType == TEXT("FString"))
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeName = *CPPType;
|
|
|
|
|
Variable.Size = sizeof(FString);
|
|
|
|
|
}
|
|
|
|
|
else if (CPPType == TEXT("FName"))
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeName = *CPPType;
|
|
|
|
|
Variable.Size = sizeof(FName);
|
|
|
|
|
}
|
|
|
|
|
else if(UScriptStruct* ScriptStruct = URigVMPin::FindObjectFromCPPTypeObjectPath<UScriptStruct>(CPPType))
|
|
|
|
|
{
|
|
|
|
|
Variable.TypeName = *ScriptStruct->GetStructCPPName();
|
|
|
|
|
Variable.TypeObject = ScriptStruct;
|
|
|
|
|
Variable.Size = ScriptStruct->GetStructureSize();
|
|
|
|
|
}
|
|
|
|
|
else if (UEnum* Enum= URigVMPin::FindObjectFromCPPTypeObjectPath<UEnum>(CPPType))
|
|
|
|
|
{
|
2022-03-01 04:23:55 -05:00
|
|
|
Variable.TypeName = *RigVMTypeUtils::CPPTypeFromEnum(Enum);
|
2021-07-22 04:23:56 -04:00
|
|
|
Variable.TypeObject = Enum;
|
|
|
|
|
Variable.Size = Enum->GetResourceSizeBytes(EResourceSizeMode::EstimatedTotal);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 08:00:07 -05:00
|
|
|
FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromExternalVariable(Variable);
|
2021-07-22 04:23:56 -04:00
|
|
|
if (!PinType.PinCategory.IsValid())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBlueprintEditorUtils::ChangeMemberVariableType(this, InName, PinType);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-20 11:56:18 -04:00
|
|
|
const FControlRigShapeDefinition* UControlRigBlueprint::GetControlShapeByName(const FName& InName) const
|
|
|
|
|
{
|
|
|
|
|
return UControlRigShapeLibrary::GetShapeByName(InName, ShapeLibraries);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
FName UControlRigBlueprint::AddTransientControl(URigVMPin* InPin)
|
|
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
TUniquePtr<FControlValueScope> ValueScope;
|
2021-06-12 00:44:35 -04:00
|
|
|
if (!UControlRigEditorSettings::Get()->bResetControlsOnPinValueInteraction) // if we need to retain the controls
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
ValueScope = MakeUnique<FControlValueScope>(this);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
// for now we only allow one pin control at the same time
|
|
|
|
|
ClearTransientControls();
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
FRigElementKey SpaceKey;
|
2021-08-30 12:31:17 -04:00
|
|
|
FTransform OffsetTransform = FTransform::Identity;
|
2020-12-02 10:59:58 -04:00
|
|
|
if (URigVMUnitNode* UnitNode = Cast<URigVMUnitNode>(InPin->GetPinForLink()->GetNode()))
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2020-12-02 10:59:58 -04:00
|
|
|
if (TSharedPtr<FStructOnScope> DefaultStructScope = UnitNode->ConstructStructInstance())
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
FRigUnit* DefaultStruct = (FRigUnit*)DefaultStructScope->GetStructMemory();
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
FString PinPath = InPin->GetPinForLink()->GetPinPath();
|
|
|
|
|
FString Left, Right;
|
|
|
|
|
|
|
|
|
|
if (URigVMPin::SplitPinPathAtStart(PinPath, Left, Right))
|
2021-08-30 12:31:17 -04:00
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
SpaceKey = DefaultStruct->DetermineSpaceForPin(Right, Hierarchy);
|
2021-08-30 12:31:17 -04:00
|
|
|
|
|
|
|
|
URigHierarchy* RigHierarchy = Hierarchy;
|
|
|
|
|
|
|
|
|
|
// use the active rig instead of the CDO rig because we want to access the evaluation result of the rig graph
|
|
|
|
|
// to calculate the offset transform, for example take a look at RigUnit_ModifyTransform
|
|
|
|
|
if (UControlRig* RigBeingDebugged = Cast<UControlRig>(GetObjectBeingDebugged()))
|
|
|
|
|
{
|
|
|
|
|
RigHierarchy = RigBeingDebugged->GetHierarchy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OffsetTransform = DefaultStruct->DetermineOffsetTransformForPin(Right, RigHierarchy);
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
FName ReturnName = NAME_None;
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
|
|
|
|
{
|
2021-08-30 12:31:17 -04:00
|
|
|
FName ControlName = InstancedControlRig->AddTransientControl(InPin, SpaceKey, OffsetTransform);
|
2020-01-22 17:58:55 -05:00
|
|
|
if (ReturnName == NAME_None)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
ReturnName = ControlName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ReturnName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FName UControlRigBlueprint::RemoveTransientControl(URigVMPin* InPin)
|
|
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
TUniquePtr<FControlValueScope> ValueScope;
|
2021-06-12 00:44:35 -04:00
|
|
|
if (!UControlRigEditorSettings::Get()->bResetControlsOnPinValueInteraction) // if we need to retain the controls
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
ValueScope = MakeUnique<FControlValueScope>(this);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
|
|
|
|
|
FName RemovedName = NAME_None;
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
|
|
|
|
{
|
|
|
|
|
FName Name = InstancedControlRig->RemoveTransientControl(InPin);
|
|
|
|
|
if (RemovedName == NAME_None)
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
RemovedName = Name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RemovedName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FName UControlRigBlueprint::AddTransientControl(const FRigElementKey& InElement)
|
|
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
TUniquePtr<FControlValueScope> ValueScope;
|
2021-06-12 00:44:35 -04:00
|
|
|
if (!UControlRigEditorSettings::Get()->bResetControlsOnPinValueInteraction) // if we need to retain the controls
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
ValueScope = MakeUnique<FControlValueScope>(this);
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
|
|
|
|
|
FName ReturnName = NAME_None;
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
2021-04-08 10:49:40 -04:00
|
|
|
|
|
|
|
|
// hierarchy transforms will be reset when ClearTransientControls() is called,
|
|
|
|
|
// so to retain any bone transform modifications we have to save them
|
|
|
|
|
TMap<UObject*, FTransform> SavedElementLocalTransforms;
|
2020-01-22 17:58:55 -05:00
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
2021-02-22 13:36:33 -04:00
|
|
|
{
|
2021-04-08 10:49:40 -04:00
|
|
|
if (InstancedControlRig->DynamicHierarchy)
|
|
|
|
|
{
|
|
|
|
|
SavedElementLocalTransforms.FindOrAdd(InstancedControlRig) = InstancedControlRig->DynamicHierarchy->GetLocalTransform(InElement);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for now we only allow one pin control at the same time
|
|
|
|
|
ClearTransientControls();
|
|
|
|
|
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
|
|
|
|
{
|
|
|
|
|
// restore the element transforms so that transient controls are created at the right place
|
|
|
|
|
if (const FTransform* SavedTransform = SavedElementLocalTransforms.Find(InstancedControlRig))
|
|
|
|
|
{
|
|
|
|
|
if (InstancedControlRig->DynamicHierarchy)
|
|
|
|
|
{
|
|
|
|
|
InstancedControlRig->DynamicHierarchy->SetLocalTransform(InElement, *SavedTransform);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
FName ControlName = InstancedControlRig->AddTransientControl(InElement);
|
|
|
|
|
if (ReturnName == NAME_None)
|
2021-02-22 13:36:33 -04:00
|
|
|
{
|
2021-03-01 18:14:52 -04:00
|
|
|
ReturnName = ControlName;
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ReturnName;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FName UControlRigBlueprint::RemoveTransientControl(const FRigElementKey& InElement)
|
|
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
TUniquePtr<FControlValueScope> ValueScope;
|
2021-06-12 00:44:35 -04:00
|
|
|
if (!UControlRigEditorSettings::Get()->bResetControlsOnPinValueInteraction) // if we need to retain the controls
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
ValueScope = MakeUnique<FControlValueScope>(this);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
|
|
|
|
|
FName RemovedName = NAME_None;
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
|
|
|
|
{
|
|
|
|
|
FName Name = InstancedControlRig->RemoveTransientControl(InElement);
|
|
|
|
|
if (RemovedName == NAME_None)
|
|
|
|
|
{
|
|
|
|
|
RemovedName = Name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RemovedName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::ClearTransientControls()
|
|
|
|
|
{
|
2020-09-24 00:43:27 -04:00
|
|
|
TUniquePtr<FControlValueScope> ValueScope;
|
2021-06-12 00:44:35 -04:00
|
|
|
if (!UControlRigEditorSettings::Get()->bResetControlsOnPinValueInteraction) // if we need to retain the controls
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
ValueScope = MakeUnique<FControlValueScope>(this);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
|
|
|
|
{
|
|
|
|
|
InstancedControlRig->ClearTransientControls();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-26 13:57:42 -04:00
|
|
|
void UControlRigBlueprint::SetTransientControlValue(const FRigElementKey& InElement)
|
|
|
|
|
{
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
|
|
|
|
|
TArray<FRigControl> PreviousControls;
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
|
|
|
|
{
|
|
|
|
|
InstancedControlRig->SetTransientControlValue(InElement);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::PopulateModelFromGraphForBackwardsCompatibility(UControlRigGraph* InGraph)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2019-07-16 11:49:59 -04:00
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
2021-02-01 09:58:26 -04:00
|
|
|
|
|
|
|
|
|
2019-07-16 11:49:59 -04:00
|
|
|
|
2021-01-06 16:30:00 -04:00
|
|
|
// temporarily disable default value validation during load time, serialized values should always be accepted
|
|
|
|
|
TGuardValue<bool> DisablePinDefaultValueValidation(GetOrCreateController()->bValidatePinDefaults, false);
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
int32 LinkerVersion = GetLinkerCustomVersion(FControlRigObjectVersion::GUID);
|
|
|
|
|
if (LinkerVersion >= FControlRigObjectVersion::SwitchedToRigVM)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
if (LinkerVersion < FControlRigObjectVersion::RemovalOfHierarchyRefPins)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogControlRigDeveloper, Warning, TEXT("Control Rig is too old (prior 4.23) - cannot automatically upgrade. Clearing graph."));
|
|
|
|
|
RebuildGraphFromModel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 19:25:23 -04:00
|
|
|
TGuardValue<bool> ReentrantGuardSelf(bSuspendModelNotificationsForSelf, true);
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> ReentrantGuardOthers(bSuspendModelNotificationsForOthers, true);
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
struct LocalHelpers
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
static FString FixUpPinPath(const FString& InPinPath)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
FString PinPath = InPinPath;
|
|
|
|
|
if (!PinPath.Contains(TEXT(".")))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
PinPath += TEXT(".Value");
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
PinPath = PinPath.Replace(TEXT("["), TEXT("."), ESearchCase::IgnoreCase);
|
|
|
|
|
PinPath = PinPath.Replace(TEXT("]"), TEXT(""), ESearchCase::IgnoreCase);
|
|
|
|
|
|
|
|
|
|
return PinPath;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (UEdGraphNode* Node : InGraph->Nodes)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraphNode* RigNode = Cast<UControlRigGraphNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
FName PropertyName = RigNode->PropertyName_DEPRECATED;
|
|
|
|
|
FVector2D NodePosition = FVector2D((float)RigNode->NodePosX, (float)RigNode->NodePosY);
|
|
|
|
|
FString StructPath = RigNode->StructPath_DEPRECATED;
|
|
|
|
|
|
|
|
|
|
if (StructPath.IsEmpty() && PropertyName != NAME_None)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if(FStructProperty* StructProperty = CastField<FStructProperty>(GetControlRigBlueprintGeneratedClass()->FindPropertyByName(PropertyName)))
|
|
|
|
|
{
|
|
|
|
|
StructPath = StructProperty->Struct->GetPathName();
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// at this point the BP skeleton might not have been compiled,
|
|
|
|
|
// we should look into the new variables array to find the property
|
|
|
|
|
for (FBPVariableDescription NewVariable : NewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (NewVariable.VarName == PropertyName && NewVariable.VarType.PinCategory == UEdGraphSchema_K2::PC_Struct)
|
|
|
|
|
{
|
|
|
|
|
if (UScriptStruct* Struct = Cast<UScriptStruct>(NewVariable.VarType.PinSubCategoryObject))
|
|
|
|
|
{
|
|
|
|
|
StructPath = Struct->GetPathName();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
URigVMNode* ModelNode = nullptr;
|
|
|
|
|
|
|
|
|
|
UScriptStruct* UnitStruct = URigVMPin::FindObjectFromCPPTypeObjectPath<UScriptStruct>(StructPath);
|
|
|
|
|
if (UnitStruct && UnitStruct->IsChildOf(FRigVMStruct::StaticStruct()))
|
|
|
|
|
{
|
2021-06-09 05:20:36 -04:00
|
|
|
ModelNode = GetOrCreateController()->AddUnitNode(UnitStruct, FRigUnit::GetMethodName(), NodePosition, PropertyName.ToString(), false);
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
else if (PropertyName != NAME_None) // check if this is a variable
|
|
|
|
|
{
|
|
|
|
|
bool bHasInputLinks = false;
|
|
|
|
|
bool bHasOutputLinks = false;
|
|
|
|
|
FString DefaultValue;
|
|
|
|
|
|
|
|
|
|
FEdGraphPinType PinType = RigNode->PinType_DEPRECATED;
|
|
|
|
|
if (RigNode->Pins.Num() > 0)
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
for (UEdGraphPin* Pin : RigNode->Pins)
|
|
|
|
|
{
|
|
|
|
|
if (!Pin->GetName().Contains(TEXT(".")))
|
|
|
|
|
{
|
|
|
|
|
PinType = Pin->PinType;
|
|
|
|
|
|
|
|
|
|
if (Pin->Direction == EGPD_Input)
|
|
|
|
|
{
|
|
|
|
|
bHasInputLinks = Pin->LinkedTo.Num() > 0;
|
|
|
|
|
DefaultValue = Pin->DefaultValue;
|
|
|
|
|
}
|
|
|
|
|
else if (Pin->Direction == EGPD_Output)
|
|
|
|
|
{
|
|
|
|
|
bHasOutputLinks = Pin->LinkedTo.Num() > 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FName DataType = PinType.PinCategory;
|
2022-02-04 11:54:52 -05:00
|
|
|
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
if (PinType.PinCategory == UEdGraphSchema_K2::PC_Real)
|
|
|
|
|
{
|
|
|
|
|
if (PinType.PinSubCategory == UEdGraphSchema_K2::PC_Float)
|
|
|
|
|
{
|
|
|
|
|
DataType = TEXT("float");
|
|
|
|
|
}
|
|
|
|
|
else if (PinType.PinSubCategory == UEdGraphSchema_K2::PC_Double)
|
|
|
|
|
{
|
|
|
|
|
DataType = TEXT("double");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ensure(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-04 11:54:52 -05:00
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
UObject* DataTypeObject = nullptr;
|
2019-05-21 19:25:23 -04:00
|
|
|
if (DataType == NAME_None)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (DataType == UEdGraphSchema_K2::PC_Struct)
|
|
|
|
|
{
|
|
|
|
|
DataType = NAME_None;
|
2020-01-22 17:58:55 -05:00
|
|
|
if (UScriptStruct* DataStruct = Cast<UScriptStruct>(PinType.PinSubCategoryObject))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
DataTypeObject = DataStruct;
|
|
|
|
|
DataType = *DataStruct->GetStructCPPName();
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
if (DataType == TEXT("int"))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
DataType = TEXT("int32");
|
|
|
|
|
}
|
|
|
|
|
else if (DataType == TEXT("name"))
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
DataType = TEXT("FName");
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
else if (DataType == TEXT("string"))
|
|
|
|
|
{
|
|
|
|
|
DataType = TEXT("FString");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FProperty* ParameterProperty = GetControlRigBlueprintGeneratedClass()->FindPropertyByName(PropertyName);
|
|
|
|
|
if(ParameterProperty)
|
|
|
|
|
{
|
|
|
|
|
bool bIsInput = true;
|
|
|
|
|
|
|
|
|
|
if (ParameterProperty->HasMetaData(TEXT("AnimationInput")) || bHasOutputLinks)
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
bIsInput = true;
|
|
|
|
|
}
|
|
|
|
|
else if (ParameterProperty->HasMetaData(TEXT("AnimationOutput")))
|
|
|
|
|
{
|
|
|
|
|
bIsInput = false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 10:20:24 -05:00
|
|
|
ModelNode = GetOrCreateController()->AddVariableNode(PropertyName, DataType.ToString(), DataTypeObject, bIsInput, FString(), NodePosition, PropertyName.ToString(), false);
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
if (ModelNode)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-12-07 07:55:48 -04:00
|
|
|
bool bWasReportingEnabled = GetOrCreateController()->IsReportingEnabled();
|
|
|
|
|
GetOrCreateController()->EnableReporting(false);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
for (UEdGraphPin* Pin : RigNode->Pins)
|
|
|
|
|
{
|
|
|
|
|
FString PinPath = LocalHelpers::FixUpPinPath(Pin->GetName());
|
2019-05-21 19:25:23 -04:00
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
// check the material + mesh pins for deprecated control nodes
|
|
|
|
|
if (URigVMUnitNode* ModelUnitNode = Cast<URigVMUnitNode>(ModelNode))
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2022-06-01 16:30:52 -04:00
|
|
|
const UScriptStruct* ScriptStruct = ModelUnitNode->GetScriptStruct();
|
|
|
|
|
if (ScriptStruct && ScriptStruct->IsChildOf(FRigUnit_Control::StaticStruct()))
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2020-12-07 07:55:48 -04:00
|
|
|
if (Pin->GetName().EndsWith(TEXT(".StaticMesh")) || Pin->GetName().EndsWith(TEXT(".Materials")))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-07 07:55:48 -04:00
|
|
|
|
|
|
|
|
if (Pin->Direction == EGPD_Input && Pin->PinType.ContainerType == EPinContainerType::Array)
|
|
|
|
|
{
|
|
|
|
|
int32 ArraySize = Pin->SubPins.Num();
|
|
|
|
|
GetOrCreateController()->SetArrayPinSize(PinPath, ArraySize, FString(), false);
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RigNode->ExpandedPins_DEPRECATED.Find(Pin->GetName()) != INDEX_NONE)
|
2020-12-07 07:55:48 -04:00
|
|
|
{
|
|
|
|
|
GetOrCreateController()->SetPinExpansion(PinPath, true, false);
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
if (Pin->SubPins.Num() == 0 && !Pin->DefaultValue.IsEmpty() && Pin->Direction == EGPD_Input)
|
2020-12-07 07:55:48 -04:00
|
|
|
{
|
|
|
|
|
GetOrCreateController()->SetPinDefaultValue(PinPath, Pin->DefaultValue, false, false, false);
|
|
|
|
|
}
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
2020-06-23 18:40:00 -04:00
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
GetOrCreateController()->EnableReporting(bWasReportingEnabled);
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
const int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, PropertyName);
|
|
|
|
|
if (VarIndex != INDEX_NONE)
|
|
|
|
|
{
|
2022-05-12 05:52:59 -04:00
|
|
|
// only remove the variable if it was backing up a rig unit
|
|
|
|
|
if(UnitStruct != nullptr)
|
|
|
|
|
{
|
|
|
|
|
NewVariables.RemoveAt(VarIndex);
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
FBlueprintEditorUtils::RemoveVariableNodes(this, PropertyName);
|
|
|
|
|
}
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
2019-05-31 18:25:32 -04:00
|
|
|
else if (const UEdGraphNode_Comment* CommentNode = Cast<UEdGraphNode_Comment>(Node))
|
|
|
|
|
{
|
|
|
|
|
FVector2D NodePosition = FVector2D((float)CommentNode->NodePosX, (float)CommentNode->NodePosY);
|
|
|
|
|
FVector2D NodeSize = FVector2D((float)CommentNode->NodeWidth, (float)CommentNode->NodeHeight);
|
2020-12-07 07:55:48 -04:00
|
|
|
GetOrCreateController()->AddCommentNode(CommentNode->NodeComment, NodePosition, NodeSize, CommentNode->CommentColor, CommentNode->GetName(), false);
|
2019-05-31 18:25:32 -04:00
|
|
|
}
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
SetupPinRedirectorsForBackwardsCompatibility();
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
for (UEdGraphNode* Node : InGraph->Nodes)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (UControlRigGraphNode* RigNode = Cast<UControlRigGraphNode>(Node))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
for (UEdGraphPin* Pin : RigNode->Pins)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
|
|
|
|
if (Pin->Direction == EGPD_Input)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
for (UEdGraphPin* LinkedPin : Pin->LinkedTo)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
UControlRigGraphNode* LinkedRigNode = Cast<UControlRigGraphNode>(LinkedPin->GetOwningNode());
|
2019-05-21 19:25:23 -04:00
|
|
|
if (LinkedRigNode != nullptr)
|
|
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
FString SourcePinPath = LocalHelpers::FixUpPinPath(Pin->GetName());
|
|
|
|
|
FString TargetPinPath = LocalHelpers::FixUpPinPath(LinkedPin->GetName());
|
2020-12-07 07:55:48 -04:00
|
|
|
GetOrCreateController()->AddLink(SourcePinPath, TargetPinPath, false);
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
RebuildGraphFromModel();
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
void UControlRigBlueprint::SetupPinRedirectorsForBackwardsCompatibility()
|
|
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
for (URigVMNode* Node : Model->GetNodes())
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMUnitNode* UnitNode = Cast<URigVMUnitNode>(Node))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
UScriptStruct* Struct = UnitNode->GetScriptStruct();
|
|
|
|
|
if (Struct == FRigUnit_SetBoneTransform::StaticStruct())
|
|
|
|
|
{
|
|
|
|
|
URigVMPin* TransformPin = UnitNode->FindPin(TEXT("Transform"));
|
|
|
|
|
URigVMPin* ResultPin = UnitNode->FindPin(TEXT("Result"));
|
|
|
|
|
GetOrCreateController()->AddPinRedirector(false, true, TransformPin->GetPinPath(), ResultPin->GetPinPath());
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-24 14:09:14 -04:00
|
|
|
void UControlRigBlueprint::RebuildGraphFromModel()
|
|
|
|
|
{
|
2019-07-16 11:49:59 -04:00
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
|
|
|
|
|
2019-05-24 14:09:14 -04:00
|
|
|
TGuardValue<bool> SelfGuard(bSuspendModelNotificationsForSelf, true);
|
2020-12-07 07:55:48 -04:00
|
|
|
check(GetOrCreateController());
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
TArray<UEdGraph*> EdGraphs;
|
|
|
|
|
GetAllGraphs(EdGraphs);
|
|
|
|
|
|
|
|
|
|
for (UEdGraph* Graph : EdGraphs)
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
|
|
|
|
TArray<UEdGraphNode*> Nodes = Graph->Nodes;
|
|
|
|
|
for (UEdGraphNode* Node : Nodes)
|
|
|
|
|
{
|
|
|
|
|
Graph->RemoveNode(Node);
|
|
|
|
|
}
|
2021-01-14 15:00:40 -04:00
|
|
|
|
|
|
|
|
if (UControlRigGraph* RigGraph = Cast<UControlRigGraph>(Graph))
|
|
|
|
|
{
|
|
|
|
|
if (RigGraph->bIsFunctionDefinition)
|
|
|
|
|
{
|
|
|
|
|
FunctionGraphs.Remove(RigGraph);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
TArray<URigVMGraph*> RigGraphs = RigVMClient.GetAllModels(true, true);
|
2020-12-14 08:58:12 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
for (int32 RigGraphIndex = 0; RigGraphIndex < RigGraphs.Num(); RigGraphIndex++)
|
|
|
|
|
{
|
|
|
|
|
GetOrCreateController(RigGraphs[RigGraphIndex])->ResendAllNotifications();
|
|
|
|
|
}
|
2020-12-14 08:58:12 -04:00
|
|
|
|
|
|
|
|
for (int32 RigGraphIndex = 0; RigGraphIndex < RigGraphs.Num(); RigGraphIndex++)
|
|
|
|
|
{
|
|
|
|
|
URigVMGraph* RigGraph = RigGraphs[RigGraphIndex];
|
|
|
|
|
|
|
|
|
|
for (URigVMNode* RigNode : RigGraph->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(RigNode))
|
|
|
|
|
{
|
|
|
|
|
CreateEdGraphForCollapseNodeIfNeeded(CollapseNode, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-14 15:00:40 -04:00
|
|
|
|
|
|
|
|
EdGraphs.Reset();
|
|
|
|
|
GetAllGraphs(EdGraphs);
|
|
|
|
|
|
|
|
|
|
for (UEdGraph* Graph : EdGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* RigGraph = Cast<UControlRigGraph>(Graph))
|
|
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
RigGraph->CacheNameLists(Hierarchy, &DrawContainer);
|
2021-01-14 15:00:40 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::Notify(ERigVMGraphNotifType InNotifType, UObject* InSubject)
|
|
|
|
|
{
|
2020-12-07 07:55:48 -04:00
|
|
|
GetOrCreateController()->Notify(InNotifType, InSubject);
|
2019-05-24 14:09:14 -04:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::HandleModifiedEvent(ERigVMGraphNotifType InNotifType, URigVMGraph* InGraph, UObject* InSubject)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2019-07-16 11:49:59 -04:00
|
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
|
|
|
|
|
|
2019-05-21 19:25:23 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
if (bSuspendAllNotifications)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
// since it's possible that a notification will be already sent / forwarded to the
|
|
|
|
|
// listening objects within the switch statement below - we keep a flag to mark
|
|
|
|
|
// the notify for still pending (or already sent)
|
|
|
|
|
bool bNotifForOthersPending = true;
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
if (!bSuspendModelNotificationsForSelf)
|
|
|
|
|
{
|
|
|
|
|
switch (InNotifType)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
case ERigVMGraphNotifType::InteractionBracketOpened:
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
IncrementVMRecompileBracket();
|
2019-05-21 19:25:23 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
case ERigVMGraphNotifType::InteractionBracketClosed:
|
|
|
|
|
case ERigVMGraphNotifType::InteractionBracketCanceled:
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
DecrementVMRecompileBracket();
|
2019-05-21 19:25:23 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
case ERigVMGraphNotifType::PinDefaultValueChanged:
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (URigVMPin* Pin = Cast<URigVMPin>(InSubject))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
bool bRequiresRecompile = false;
|
2019-05-21 19:25:23 -04:00
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
URigVMPin* RootPin = Pin->GetRootPin();
|
2021-08-03 06:51:00 -04:00
|
|
|
static const FString ConstSuffix = TEXT(":Const");
|
|
|
|
|
const FString PinHash = RootPin->GetPinPath(true) + ConstSuffix;
|
|
|
|
|
|
|
|
|
|
if (const FRigVMOperand* Operand = PinToOperandMap.Find(PinHash))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2021-01-12 06:47:41 -04:00
|
|
|
FRigVMASTProxy RootPinProxy = FRigVMASTProxy::MakeFromUObject(RootPin);
|
|
|
|
|
if(const FRigVMExprAST* Expression = InGraph->GetRuntimeAST()->GetExprForSubject(RootPinProxy))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
bRequiresRecompile = Expression->NumParents() > 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bRequiresRecompile = true;
|
|
|
|
|
}
|
2019-05-21 19:25:23 -04:00
|
|
|
|
2021-03-18 15:20:03 -04:00
|
|
|
// If we are only changing a pin's default value, we need to
|
|
|
|
|
// check if there is a connection to a sub-pin of the root pin
|
|
|
|
|
// that has its value is directly stored in the root pin due to optimization, if so,
|
|
|
|
|
// we want to recompile to make sure the pin's new default value and values from other connections
|
|
|
|
|
// are both applied to the root pin because GetDefaultValue() alone cannot account for values
|
|
|
|
|
// from other connections.
|
|
|
|
|
if(!bRequiresRecompile)
|
|
|
|
|
{
|
|
|
|
|
TArray<URigVMPin*> SourcePins = RootPin->GetLinkedSourcePins(true);
|
|
|
|
|
for (const URigVMPin* SourcePin : SourcePins)
|
|
|
|
|
{
|
|
|
|
|
// check if the source node is optimized out, if so, only a recompile will allows us
|
|
|
|
|
// to re-query its value.
|
|
|
|
|
FRigVMASTProxy SourceNodeProxy = FRigVMASTProxy::MakeFromUObject(SourcePin->GetNode());
|
|
|
|
|
if (InGraph->GetRuntimeAST()->GetExprForSubject(SourceNodeProxy) == nullptr)
|
|
|
|
|
{
|
|
|
|
|
bRequiresRecompile = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
if(!bRequiresRecompile)
|
|
|
|
|
{
|
2021-07-27 14:04:39 -04:00
|
|
|
const FString DefaultValue = RootPin->GetDefaultValue();
|
2020-01-22 17:58:55 -05:00
|
|
|
|
|
|
|
|
UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass();
|
|
|
|
|
UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */));
|
|
|
|
|
if (CDO->VM != nullptr)
|
|
|
|
|
{
|
2021-07-27 14:04:39 -04:00
|
|
|
CDO->VM->SetPropertyValueFromString(*Operand, DefaultValue);
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
CDO->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
UControlRig* InstancedControlRig = Cast<UControlRig>(ArchetypeInstance);
|
|
|
|
|
if (InstancedControlRig)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (InstancedControlRig->VM)
|
|
|
|
|
{
|
2021-07-27 14:04:39 -04:00
|
|
|
InstancedControlRig->VM->SetPropertyValueFromString(*Operand, DefaultValue);
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
if (Pin->IsDefinedAsConstant() || Pin->GetRootPin()->IsDefinedAsConstant())
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
|
|
|
|
// re-init the rigs
|
|
|
|
|
RequestControlRigInit();
|
2020-09-24 00:43:27 -04:00
|
|
|
bRequiresRecompile = true;
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bRequiresRecompile = true;
|
|
|
|
|
}
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
if(bRequiresRecompile)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
RequestAutoVMRecompilation();
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
// check if this pin is part of an injected node, and if it is a visual debug node,
|
|
|
|
|
// we might need to recreate the control pin
|
2019-05-21 19:25:23 -04:00
|
|
|
if (UClass* MyControlRigClass = GeneratedClass)
|
|
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (UControlRig* DefaultObject = Cast<UControlRig>(MyControlRigClass->GetDefaultObject(false)))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
DefaultObject->GetArchetypeInstances(ArchetypeInstances);
|
2022-05-31 04:27:20 -04:00
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(ArchetypeInstance))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
Hierarchy->ForEach<FRigControlElement>([this, InstanceRig, Pin](FRigControlElement* ControlElement) -> bool
|
|
|
|
|
{
|
|
|
|
|
if(!ControlElement->Settings.bIsTransientControl)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMPin* ControlledPin = Model->FindPin(ControlElement->GetName().ToString()))
|
|
|
|
|
{
|
|
|
|
|
URigVMPin* ControlledPinForLink = ControlledPin->GetPinForLink();
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if(ControlledPin->GetRootPin() == Pin->GetRootPin() ||
|
|
|
|
|
ControlledPinForLink->GetRootPin() == Pin->GetRootPin())
|
|
|
|
|
{
|
|
|
|
|
InstanceRig->SetTransientControlValue(ControlledPin->GetPinForLink());
|
|
|
|
|
}
|
|
|
|
|
else if (ControlledPin->GetNode() == Pin->GetNode() ||
|
|
|
|
|
ControlledPinForLink->GetNode() == Pin->GetNode())
|
|
|
|
|
{
|
|
|
|
|
InstanceRig->ClearTransientControls();
|
|
|
|
|
InstanceRig->AddTransientControl(ControlledPin);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-22 13:36:33 -04:00
|
|
|
return true;
|
|
|
|
|
});
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
MarkPackageDirty();
|
2019-05-21 19:25:23 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
case ERigVMGraphNotifType::NodeAdded:
|
|
|
|
|
case ERigVMGraphNotifType::NodeRemoved:
|
2020-12-14 08:58:12 -04:00
|
|
|
{
|
2021-04-21 11:25:07 -04:00
|
|
|
if (InNotifType == ERigVMGraphNotifType::NodeRemoved)
|
|
|
|
|
{
|
|
|
|
|
if (URigVMNode* RigVMNode = Cast<URigVMNode>(InSubject))
|
|
|
|
|
{
|
|
|
|
|
RemoveBreakpoint(RigVMNode);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(InSubject))
|
|
|
|
|
{
|
|
|
|
|
if (InNotifType == ERigVMGraphNotifType::NodeAdded)
|
|
|
|
|
{
|
2022-04-27 12:19:16 -04:00
|
|
|
// If the controller for this graph already exist, make sure it is referencing the correct graph
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMController* Controller = RigVMClient.GetController(CollapseNode->GetContainedGraph()))
|
2022-04-27 12:19:16 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
Controller->SetGraph(CollapseNode->GetContainedGraph());
|
2022-04-27 12:19:16 -04:00
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
CreateEdGraphForCollapseNodeIfNeeded(CollapseNode);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bNotifForOthersPending = !RemoveEdGraphForCollapseNode(CollapseNode, true);
|
2022-04-27 12:19:16 -04:00
|
|
|
|
|
|
|
|
// Cannot remove from the Controllers array because we would lose the action stack on that graph
|
|
|
|
|
// Controllers.Remove(CollapseNode->GetContainedGraph();
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClearTransientControls();
|
|
|
|
|
RequestAutoVMRecompilation();
|
2021-03-03 14:44:58 -04:00
|
|
|
|
|
|
|
|
if(CollapseNode->GetOuter()->IsA<URigVMFunctionLibrary>())
|
|
|
|
|
{
|
|
|
|
|
for(int32 Index = 0; Index < PublicFunctions.Num(); Index++)
|
|
|
|
|
{
|
|
|
|
|
if(PublicFunctions[Index].Name == CollapseNode->GetFName())
|
|
|
|
|
{
|
|
|
|
|
Modify();
|
|
|
|
|
PublicFunctions.RemoveAt(Index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
MarkPackageDirty();
|
|
|
|
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMNode* RigVMNode = Cast<URigVMNode>(InSubject))
|
|
|
|
|
{
|
|
|
|
|
if(RigVMNode->IsEvent() && RigVMNode->GetGraph()->IsRootGraph())
|
|
|
|
|
{
|
|
|
|
|
// let the UI know the title for the graph may have changed.
|
|
|
|
|
RigVMClient.NotifyOuterOfPropertyChange();
|
|
|
|
|
|
|
|
|
|
if(UControlRigGraph* EdGraph = Cast<UControlRigGraph>(GetEdGraph(RigVMNode->GetGraph())))
|
|
|
|
|
{
|
|
|
|
|
// decide if this graph should be renameable
|
|
|
|
|
const int32 NumberOfEvents = Algo::CountIf(RigVMNode->GetGraph()->GetNodes(), [](const URigVMNode* NodeToCount) -> bool
|
|
|
|
|
{
|
2022-06-01 11:28:01 -04:00
|
|
|
return NodeToCount->IsEvent() && NodeToCount->CanOnlyExistOnce();
|
2022-05-31 04:27:20 -04:00
|
|
|
});
|
|
|
|
|
EdGraph->bAllowRenaming = NumberOfEvents != 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-14 08:58:12 -04:00
|
|
|
// fall through to the next case
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
case ERigVMGraphNotifType::LinkAdded:
|
|
|
|
|
case ERigVMGraphNotifType::LinkRemoved:
|
|
|
|
|
case ERigVMGraphNotifType::PinArraySizeChanged:
|
|
|
|
|
case ERigVMGraphNotifType::PinDirectionChanged:
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
ClearTransientControls();
|
|
|
|
|
RequestAutoVMRecompilation();
|
|
|
|
|
MarkPackageDirty();
|
2021-09-21 11:53:26 -04:00
|
|
|
|
|
|
|
|
// we don't need to mark the blueprint as modified since we only
|
|
|
|
|
// need to recompile the VM here - unless we don't auto recompile.
|
|
|
|
|
if(!bAutoRecompileVM)
|
|
|
|
|
{
|
|
|
|
|
FBlueprintEditorUtils::MarkBlueprintAsModified(this);
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ERigVMGraphNotifType::PinWatchedChanged:
|
2021-04-29 05:02:50 -04:00
|
|
|
{
|
|
|
|
|
if (UControlRig* CR = Cast<UControlRig>(GetObjectBeingDebugged()))
|
|
|
|
|
{
|
|
|
|
|
URigVMPin* Pin = CastChecked<URigVMPin>(InSubject)->GetRootPin();
|
|
|
|
|
URigVMCompiler* Compiler = URigVMCompiler::StaticClass()->GetDefaultObject<URigVMCompiler>();
|
|
|
|
|
Compiler->Settings = VMCompileSettings;
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
TSharedPtr<FRigVMParserAST> RuntimeAST = GetDefaultModel()->GetRuntimeAST();
|
2021-04-29 05:02:50 -04:00
|
|
|
|
|
|
|
|
if(Pin->RequiresWatch())
|
|
|
|
|
{
|
2021-05-14 02:36:03 -04:00
|
|
|
// check if the node is optimized out - in that case we need to recompile
|
|
|
|
|
if(CR->GetVM()->GetByteCode().GetFirstInstructionIndexForSubject(Pin->GetNode()) == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
RequestAutoVMRecompilation();
|
|
|
|
|
MarkPackageDirty();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-07-29 14:29:52 -04:00
|
|
|
if(CR->GetVM()->GetDebugMemory()->Num() == 0)
|
|
|
|
|
{
|
|
|
|
|
RequestAutoVMRecompilation();
|
|
|
|
|
MarkPackageDirty();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Compiler->MarkDebugWatch(true, Pin, CR->GetVM(), &PinToOperandMap, RuntimeAST);
|
|
|
|
|
}
|
2021-05-14 02:36:03 -04:00
|
|
|
}
|
2021-04-29 05:02:50 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-08-05 18:37:26 -04:00
|
|
|
Compiler->MarkDebugWatch(false, Pin, CR->GetVM(), &PinToOperandMap, RuntimeAST);
|
2021-04-29 05:02:50 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// break; fall through
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
case ERigVMGraphNotifType::PinTypeChanged:
|
2021-01-21 04:38:23 -04:00
|
|
|
case ERigVMGraphNotifType::PinIndexChanged:
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
|
|
|
|
if (URigVMPin* ModelPin = Cast<URigVMPin>(InSubject))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2021-03-19 12:43:05 -04:00
|
|
|
if (UEdGraph* EdGraph = GetEdGraph(InGraph))
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* Graph = Cast<UControlRigGraph>(EdGraph))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (UEdGraphNode* EdNode = Graph->FindNodeForModelNodeName(ModelPin->GetNode()->GetFName()))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (UEdGraphPin* EdPin = EdNode->FindPin(*ModelPin->GetPinPath()))
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (ModelPin->RequiresWatch())
|
2019-07-16 11:49:59 -04:00
|
|
|
{
|
2021-08-16 23:19:04 -04:00
|
|
|
if (!FKismetDebugUtilities::IsPinBeingWatched(this, EdPin))
|
|
|
|
|
{
|
2021-10-25 20:05:28 -04:00
|
|
|
FKismetDebugUtilities::AddPinWatch(this, FBlueprintWatchedPin(EdPin));
|
2021-08-16 23:19:04 -04:00
|
|
|
}
|
2019-07-16 11:49:59 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-08-16 23:19:04 -04:00
|
|
|
FKismetDebugUtilities::RemovePinWatch(this, EdPin);
|
2019-07-16 11:49:59 -04:00
|
|
|
}
|
2021-04-29 05:02:50 -04:00
|
|
|
|
|
|
|
|
if(InNotifType == ERigVMGraphNotifType::PinWatchedChanged)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
RequestAutoVMRecompilation();
|
2021-03-19 12:43:05 -04:00
|
|
|
MarkPackageDirty();
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
2021-03-19 12:43:05 -04:00
|
|
|
}
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-10-26 06:51:31 -04:00
|
|
|
case ERigVMGraphNotifType::PinBoundVariableChanged:
|
2021-04-27 03:19:42 -04:00
|
|
|
case ERigVMGraphNotifType::VariableRemappingChanged:
|
2019-07-16 11:49:59 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
RequestAutoVMRecompilation();
|
|
|
|
|
MarkPackageDirty();
|
2019-07-16 11:49:59 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2020-12-14 08:58:12 -04:00
|
|
|
case ERigVMGraphNotifType::NodeRenamed:
|
|
|
|
|
{
|
2021-01-14 15:00:40 -04:00
|
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(InSubject))
|
2020-12-14 08:58:12 -04:00
|
|
|
{
|
2022-05-11 07:30:10 -04:00
|
|
|
// Fix the path to the contained graph controller
|
|
|
|
|
{
|
|
|
|
|
FSoftObjectPath ContainedGraphPath = CollapseNode->GetContainedGraph();
|
|
|
|
|
FString SubPathString = ContainedGraphPath.GetSubPathString();
|
|
|
|
|
FString OldSubPathString = SubPathString.Replace(*CollapseNode->GetName(), *CollapseNode->GetPreviousFName().ToString());
|
|
|
|
|
FSoftObjectPath OldContainedGraphPath = ContainedGraphPath;
|
|
|
|
|
OldContainedGraphPath.SetSubPathString(OldSubPathString);
|
2022-05-31 04:27:20 -04:00
|
|
|
RigVMClient.OnSubGraphRenamed(OldContainedGraphPath, ContainedGraphPath);
|
2022-05-11 07:30:10 -04:00
|
|
|
}
|
|
|
|
|
|
2021-01-14 15:00:40 -04:00
|
|
|
FString NewNodePath = CollapseNode->GetNodePath(true /* recursive */);
|
2020-12-14 08:58:12 -04:00
|
|
|
FString Left, Right = NewNodePath;
|
|
|
|
|
URigVMNode::SplitNodePathAtEnd(NewNodePath, Left, Right);
|
2021-01-14 15:00:40 -04:00
|
|
|
FString OldNodePath = CollapseNode->GetPreviousFName().ToString();
|
2020-12-14 08:58:12 -04:00
|
|
|
if (!Left.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
OldNodePath = URigVMNode::JoinNodePath(Left, OldNodePath);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
HandleRigVMGraphRenamed(GetRigVMClient(), OldNodePath, NewNodePath);
|
2020-12-14 08:58:12 -04:00
|
|
|
|
2021-01-14 15:00:40 -04:00
|
|
|
if (UEdGraph* ContainedEdGraph = GetEdGraph(CollapseNode->GetContainedGraph()))
|
|
|
|
|
{
|
|
|
|
|
ContainedEdGraph->Rename(*CollapseNode->GetEditorSubGraphName(), nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 14:44:58 -04:00
|
|
|
if(CollapseNode->GetOuter()->IsA<URigVMFunctionLibrary>())
|
|
|
|
|
{
|
|
|
|
|
for(int32 Index = 0; Index < PublicFunctions.Num(); Index++)
|
|
|
|
|
{
|
|
|
|
|
if(PublicFunctions[Index].Name == CollapseNode->GetPreviousFName())
|
|
|
|
|
{
|
|
|
|
|
Modify();
|
|
|
|
|
PublicFunctions[Index].Name = CollapseNode->GetFName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-01-27 05:06:20 -04:00
|
|
|
case ERigVMGraphNotifType::NodeCategoryChanged:
|
|
|
|
|
case ERigVMGraphNotifType::NodeKeywordsChanged:
|
2021-06-08 12:10:13 -04:00
|
|
|
case ERigVMGraphNotifType::NodeDescriptionChanged:
|
2021-01-27 05:06:20 -04:00
|
|
|
{
|
|
|
|
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-05-21 19:25:23 -04:00
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
// if the notification still has to be sent...
|
|
|
|
|
if (bNotifForOthersPending && !bSuspendModelNotificationsForOthers)
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
if (ModifiedEvent.IsBound())
|
2019-05-21 19:25:23 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
ModifiedEvent.Broadcast(InNotifType, InGraph, InSubject);
|
2019-05-21 19:25:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
void UControlRigBlueprint::SuspendNotifications(bool bSuspendNotifs)
|
|
|
|
|
{
|
|
|
|
|
if (bSuspendAllNotifications == bSuspendNotifs)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bSuspendAllNotifications = bSuspendNotifs;
|
|
|
|
|
if (!bSuspendNotifs)
|
|
|
|
|
{
|
|
|
|
|
RebuildGraphFromModel();
|
|
|
|
|
RefreshEditorEvent.Broadcast(this);
|
|
|
|
|
RequestAutoVMRecompilation();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::CreateMemberVariablesOnLoad()
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
int32 LinkerVersion = GetLinkerCustomVersion(FControlRigObjectVersion::GUID);
|
|
|
|
|
if (LinkerVersion < FControlRigObjectVersion::SwitchedToRigVM)
|
|
|
|
|
{
|
2022-05-19 06:49:41 -04:00
|
|
|
// ignore errors during the first potential compile of the VM
|
|
|
|
|
// since that this point variable nodes may still be ill-formed.
|
|
|
|
|
TGuardValue<FRigVMReportDelegate> SuspendReportDelegate(VMCompileSettings.ASTSettings.ReportDelegate,
|
|
|
|
|
FRigVMReportDelegate::CreateLambda([](EMessageSeverity::Type, UObject*, const FString&)
|
|
|
|
|
{
|
|
|
|
|
// do nothing
|
|
|
|
|
})
|
|
|
|
|
);
|
2020-09-24 00:43:27 -04:00
|
|
|
InitializeModelIfRequired();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AddedMemberVariableMap.Reset();
|
|
|
|
|
|
|
|
|
|
for (int32 VariableIndex = 0; VariableIndex < NewVariables.Num(); VariableIndex++)
|
|
|
|
|
{
|
|
|
|
|
AddedMemberVariableMap.Add(NewVariables[VariableIndex].VarName, VariableIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if (RigVMClient.Num() == 0)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setup variables on the blueprint based on the previous "parameters"
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::BlueprintVariableSupport)
|
|
|
|
|
{
|
|
|
|
|
TSharedPtr<FKismetNameValidator> NameValidator = MakeShareable(new FKismetNameValidator(this, NAME_None, nullptr));
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
TArray<URigVMNode*> Nodes = Model->GetNodes();
|
|
|
|
|
for (URigVMNode* Node : Nodes)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMVariableNode* VariableNode = Cast<URigVMVariableNode>(Node))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMPin* VariablePin = VariableNode->FindPin(TEXT("Variable")))
|
|
|
|
|
{
|
|
|
|
|
if (VariablePin->GetDirection() != ERigVMPinDirection::Visible)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRigVMGraphVariableDescription Description = VariableNode->GetVariableDescription();
|
|
|
|
|
if (AddedMemberVariableMap.Contains(Description.Name))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromExternalVariable(Description.ToExternalVariable());
|
|
|
|
|
if (!PinType.PinCategory.IsValid())
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
FName VarName = FindCRMemberVariableUniqueName(NameValidator, Description.Name.ToString());
|
|
|
|
|
int32 VariableIndex = AddCRMemberVariable(this, VarName, PinType, false, false, FString());
|
|
|
|
|
if (VariableIndex != INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
AddedMemberVariableMap.Add(Description.Name, VariableIndex);
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
// Leaving this for backwards compatibility, even though we don't support parameters anymore
|
|
|
|
|
// When a parameter node is found, we will create a variable
|
|
|
|
|
if (URigVMParameterNode* ParameterNode = Cast<URigVMParameterNode>(Node))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMPin* ParameterPin = ParameterNode->FindPin(TEXT("Parameter")))
|
|
|
|
|
{
|
|
|
|
|
if (ParameterPin->GetDirection() != ERigVMPinDirection::Visible)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
FRigVMGraphParameterDescription Description = ParameterNode->GetParameterDescription();
|
|
|
|
|
if (AddedMemberVariableMap.Contains(Description.Name))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromExternalVariable(Description.ToExternalVariable());
|
|
|
|
|
if (!PinType.PinCategory.IsValid())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FName VarName = FindCRMemberVariableUniqueName(NameValidator, Description.Name.ToString());
|
|
|
|
|
int32 VariableIndex = AddCRMemberVariable(this, VarName, PinType, true, !Description.bIsInput, FString());
|
|
|
|
|
if (VariableIndex != INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
AddedMemberVariableMap.Add(Description.Name, VariableIndex);
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-26 06:51:31 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
FName UControlRigBlueprint::FindCRMemberVariableUniqueName(TSharedPtr<FKismetNameValidator> InNameValidator, const FString& InBaseName)
|
|
|
|
|
{
|
2021-09-08 11:50:14 -04:00
|
|
|
FString BaseName = InBaseName;
|
|
|
|
|
if (InNameValidator->IsValid(BaseName) == EValidatorResult::ContainsInvalidCharacters)
|
2020-10-26 06:51:31 -04:00
|
|
|
{
|
2021-09-08 11:50:14 -04:00
|
|
|
for (TCHAR& TestChar : BaseName)
|
2020-10-26 06:51:31 -04:00
|
|
|
{
|
|
|
|
|
for (TCHAR BadChar : UE_BLUEPRINT_INVALID_NAME_CHARACTERS)
|
|
|
|
|
{
|
|
|
|
|
if (TestChar == BadChar)
|
|
|
|
|
{
|
|
|
|
|
TestChar = TEXT('_');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-08 11:50:14 -04:00
|
|
|
FString KismetName = BaseName;
|
|
|
|
|
|
2020-10-26 06:51:31 -04:00
|
|
|
int32 Suffix = 0;
|
|
|
|
|
while (InNameValidator->IsValid(KismetName) != EValidatorResult::Ok)
|
|
|
|
|
{
|
2021-09-08 11:50:14 -04:00
|
|
|
KismetName = FString::Printf(TEXT("%s_%d"), *BaseName, Suffix);
|
2020-10-26 06:51:31 -04:00
|
|
|
Suffix++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return *KismetName;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-21 10:14:22 -04:00
|
|
|
int32 UControlRigBlueprint::AddCRMemberVariable(UControlRigBlueprint* InBlueprint, const FName& InVarName, FEdGraphPinType InVarType, bool bIsPublic, bool bIsReadOnly, FString InDefaultValue)
|
2020-10-26 06:51:31 -04:00
|
|
|
{
|
|
|
|
|
FBPVariableDescription NewVar;
|
|
|
|
|
|
|
|
|
|
NewVar.VarName = InVarName;
|
|
|
|
|
NewVar.VarGuid = FGuid::NewGuid();
|
|
|
|
|
NewVar.FriendlyName = FName::NameToDisplayString(InVarName.ToString(), (InVarType.PinCategory == UEdGraphSchema_K2::PC_Boolean) ? true : false);
|
|
|
|
|
NewVar.VarType = InVarType;
|
|
|
|
|
|
|
|
|
|
NewVar.PropertyFlags |= (CPF_Edit | CPF_BlueprintVisible | CPF_DisableEditOnInstance);
|
|
|
|
|
|
|
|
|
|
if (bIsPublic)
|
|
|
|
|
{
|
|
|
|
|
NewVar.PropertyFlags &= ~CPF_DisableEditOnInstance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bIsReadOnly)
|
|
|
|
|
{
|
|
|
|
|
NewVar.PropertyFlags |= CPF_BlueprintReadOnly;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NewVar.ReplicationCondition = COND_None;
|
|
|
|
|
|
|
|
|
|
NewVar.Category = UEdGraphSchema_K2::VR_DefaultCategory;
|
|
|
|
|
|
|
|
|
|
// user created variables should be none of these things
|
|
|
|
|
NewVar.VarType.bIsConst = false;
|
|
|
|
|
NewVar.VarType.bIsWeakPointer = false;
|
|
|
|
|
NewVar.VarType.bIsReference = false;
|
|
|
|
|
|
|
|
|
|
// Text variables, etc. should default to multiline
|
|
|
|
|
NewVar.SetMetaData(TEXT("MultiLine"), TEXT("true"));
|
|
|
|
|
|
2021-01-21 10:14:22 -04:00
|
|
|
NewVar.DefaultValue = InDefaultValue;
|
|
|
|
|
|
2020-10-26 06:51:31 -04:00
|
|
|
return InBlueprint->NewVariables.Add(NewVar);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-21 10:14:22 -04:00
|
|
|
FName UControlRigBlueprint::AddCRMemberVariableFromExternal(FRigVMExternalVariable InVariableToCreate, FString InDefaultValue)
|
2020-10-26 06:51:31 -04:00
|
|
|
{
|
2021-11-18 08:00:07 -05:00
|
|
|
FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromExternalVariable(InVariableToCreate);
|
2020-10-26 06:51:31 -04:00
|
|
|
if (!PinType.PinCategory.IsValid())
|
|
|
|
|
{
|
|
|
|
|
return NAME_None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Modify();
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FKismetNameValidator> NameValidator = MakeShareable(new FKismetNameValidator(this, NAME_None, nullptr));
|
|
|
|
|
FName VarName = FindCRMemberVariableUniqueName(NameValidator, InVariableToCreate.Name.ToString());
|
2021-01-21 10:14:22 -04:00
|
|
|
int32 VariableIndex = AddCRMemberVariable(this, VarName, PinType, InVariableToCreate.bIsPublic, InVariableToCreate.bIsReadOnly, InDefaultValue);
|
2020-10-26 06:51:31 -04:00
|
|
|
if (VariableIndex != INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
|
|
|
|
|
return VarName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NAME_None;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-19 06:29:19 -04:00
|
|
|
void UControlRigBlueprint::PatchFunctionReferencesOnLoad()
|
|
|
|
|
{
|
|
|
|
|
// If the asset was copied from one project to another, the function referenced might have a different
|
|
|
|
|
// path, even if the function is internal to the contorl rig. In that case, let's try to find the function
|
|
|
|
|
// in the local function library.
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2021-10-19 06:29:19 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
TArray<URigVMNode*> Nodes = Model->GetNodes();
|
|
|
|
|
for (URigVMLibraryNode* Library : RigVMClient.GetFunctionLibrary()->GetFunctions())
|
2021-10-19 06:29:19 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
Nodes.Append(Library->GetContainedNodes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (URigVMNode* Node : Nodes)
|
|
|
|
|
{
|
|
|
|
|
if (URigVMFunctionReferenceNode* FunctionReferenceNode = Cast<URigVMFunctionReferenceNode>(Node))
|
2021-10-19 06:29:19 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (!FunctionReferenceNode->GetReferencedNode())
|
2021-10-19 06:29:19 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if(URigVMFunctionLibrary* FunctionLibrary = RigVMClient.GetFunctionLibrary())
|
2021-10-19 06:29:19 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
FString FunctionPath = FunctionReferenceNode->ReferencedNodePtr.ToSoftObjectPath().GetSubPathString();
|
|
|
|
|
|
|
|
|
|
FString Left, Right;
|
|
|
|
|
if(FunctionPath.Split(TEXT("."), &Left, &Right))
|
2021-10-19 06:29:19 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
FString LibraryNodePath = FunctionLibrary->GetNodePath();
|
|
|
|
|
if(Left == FunctionLibrary->GetName())
|
2021-10-19 06:29:19 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMLibraryNode* LibraryNode = Cast<URigVMLibraryNode>(FunctionLibrary->FindNode(Right)))
|
|
|
|
|
{
|
|
|
|
|
FunctionReferenceNode->SetReferencedNode(LibraryNode);
|
|
|
|
|
}
|
2021-10-19 06:29:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-19 06:29:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-10 07:13:27 -05:00
|
|
|
FunctionReferenceNodeData = GetReferenceNodeData();
|
2021-10-19 06:29:19 -04:00
|
|
|
}
|
|
|
|
|
|
2020-10-26 06:51:31 -04:00
|
|
|
#endif
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
void UControlRigBlueprint::PatchVariableNodesOnLoad()
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
// setup variables on the blueprint based on the previous "parameters"
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::BlueprintVariableSupport)
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> GuardNotifsSelf(bSuspendModelNotificationsForSelf, true);
|
|
|
|
|
|
2020-12-07 07:55:48 -04:00
|
|
|
GetOrCreateController()->ReattachLinksToPinObjects();
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
check(GetDefaultModel());
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
TArray<URigVMNode*> Nodes = Model->GetNodes();
|
|
|
|
|
for (URigVMNode* Node : Nodes)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMVariableNode* VariableNode = Cast<URigVMVariableNode>(Node))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
FRigVMGraphVariableDescription Description = VariableNode->GetVariableDescription();
|
|
|
|
|
if (!AddedMemberVariableMap.Contains(Description.Name))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32 VariableIndex = AddedMemberVariableMap.FindChecked(Description.Name);
|
|
|
|
|
FName VarName = NewVariables[VariableIndex].VarName;
|
|
|
|
|
GetOrCreateController()->RefreshVariableNode(VariableNode->GetFName(), VarName, Description.CPPType, Description.CPPTypeObject, false);
|
|
|
|
|
bDirtyDuringLoad = true;
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMParameterNode* ParameterNode = Cast<URigVMParameterNode>(Node))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
FRigVMGraphParameterDescription Description = ParameterNode->GetParameterDescription();
|
|
|
|
|
if (!AddedMemberVariableMap.Contains(Description.Name))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
int32 VariableIndex = AddedMemberVariableMap.FindChecked(Description.Name);
|
|
|
|
|
FName VarName = NewVariables[VariableIndex].VarName;
|
|
|
|
|
GetOrCreateController()->ReplaceParameterNodeWithVariable(ParameterNode->GetFName(), VarName, Description.CPPType, Description.CPPTypeObject, false);
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AddedMemberVariableMap.Reset();
|
|
|
|
|
LastNewVariables = NewVariables;
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-24 05:32:05 -05:00
|
|
|
void UControlRigBlueprint::PatchRigElementKeyCacheOnLoad()
|
|
|
|
|
{
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::RigElementKeyCache)
|
|
|
|
|
{
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
|
|
|
|
URigVMController* Controller = GetOrCreateController(Graph);
|
|
|
|
|
TGuardValue<bool> DisablePinDefaultValueValidation(Controller->bValidatePinDefaults, false);
|
|
|
|
|
Controller->SuspendNotifications(true);
|
|
|
|
|
for (URigVMNode* Node : Graph->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMUnitNode* UnitNode = Cast<URigVMUnitNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
UScriptStruct* ScriptStruct = UnitNode->GetScriptStruct();
|
2022-03-01 04:23:55 -05:00
|
|
|
FString FunctionName = FString::Printf(TEXT("%s::%s"), *ScriptStruct->GetStructCPPName(), *UnitNode->GetMethodName().ToString());
|
|
|
|
|
const FRigVMFunction* Function = FRigVMRegistry::Get().FindFunction(*FunctionName);
|
|
|
|
|
check(Function);
|
|
|
|
|
for (TFieldIterator<FProperty> It(Function->Struct); It; ++It)
|
2021-11-24 05:32:05 -05:00
|
|
|
{
|
|
|
|
|
if (It->GetCPPType() == TEXT("FCachedRigElement"))
|
|
|
|
|
{
|
|
|
|
|
if (URigVMPin* Pin = Node->FindPin(It->GetName()))
|
|
|
|
|
{
|
|
|
|
|
int32 BoneIndex = FCString::Atoi(*Pin->GetDefaultValue());
|
|
|
|
|
FRigElementKey Key = Hierarchy->GetKey(BoneIndex);
|
|
|
|
|
FCachedRigElement DefaultValueElement(Key, Hierarchy);
|
|
|
|
|
FString Result;
|
|
|
|
|
TBaseStructure<FCachedRigElement>::Get()->ExportText(Result, &DefaultValueElement, nullptr, nullptr, PPF_None, nullptr);
|
|
|
|
|
Controller->SetPinDefaultValue(Pin->GetPinPath(), Result, true, false, false);
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Controller->SuspendNotifications(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-29 11:26:01 -05:00
|
|
|
void UControlRigBlueprint::PatchBoundVariables()
|
|
|
|
|
{
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::BoundVariableWithInjectionNode)
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> GuardNotifsSelf(bSuspendModelNotificationsForSelf, true);
|
|
|
|
|
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
|
|
|
|
URigVMController* Controller = GetOrCreateController(Graph);
|
|
|
|
|
TArray<URigVMNode*> Nodes = Graph->GetNodes();
|
|
|
|
|
for (URigVMNode* Node : Nodes)
|
|
|
|
|
{
|
|
|
|
|
for (URigVMPin* Pin : Node->GetPins())
|
|
|
|
|
{
|
|
|
|
|
for (URigVMInjectionInfo* Info : Pin->GetInjectedNodes())
|
|
|
|
|
{
|
|
|
|
|
Info->Node = Info->UnitNode_DEPRECATED;
|
|
|
|
|
Info->UnitNode_DEPRECATED = nullptr;
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Pin->BoundVariablePath_DEPRECATED.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
Controller->BindPinToVariable(Pin->GetPinPath(), Pin->BoundVariablePath_DEPRECATED, false);
|
|
|
|
|
Pin->BoundVariablePath_DEPRECATED = FString();
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
void UControlRigBlueprint::PatchVariableNodesWithIncorrectType()
|
|
|
|
|
{
|
|
|
|
|
TGuardValue<bool> GuardNotifsSelf(bSuspendModelNotificationsForSelf, true);
|
|
|
|
|
|
|
|
|
|
struct Local
|
|
|
|
|
{
|
|
|
|
|
static bool RefreshIfNeeded(URigVMController* Controller, URigVMVariableNode* VariableNode, const FString& CPPType, UObject* CPPTypeObject)
|
|
|
|
|
{
|
|
|
|
|
if (URigVMPin* ValuePin = VariableNode->GetValuePin())
|
|
|
|
|
{
|
|
|
|
|
if (ValuePin->GetCPPType() != CPPType || ValuePin->GetCPPTypeObject() != CPPTypeObject)
|
|
|
|
|
{
|
|
|
|
|
Controller->RefreshVariableNode(VariableNode->GetFName(), VariableNode->GetVariableName(), CPPType, CPPTypeObject, false);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
|
|
|
|
URigVMController* Controller = GetOrCreateController(Graph);
|
|
|
|
|
TArray<URigVMNode*> Nodes = Graph->GetNodes();
|
|
|
|
|
for (URigVMNode* Node : Nodes)
|
|
|
|
|
{
|
|
|
|
|
if (URigVMVariableNode* VariableNode = Cast<URigVMVariableNode>(Node))
|
|
|
|
|
{
|
2022-02-14 05:26:33 -05:00
|
|
|
if (VariableNode->IsInputArgument())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
FRigVMGraphVariableDescription Description = VariableNode->GetVariableDescription();
|
|
|
|
|
|
2022-02-14 05:26:33 -05:00
|
|
|
// Check for local variables
|
|
|
|
|
if (VariableNode->IsLocalVariable())
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
{
|
2022-02-14 05:26:33 -05:00
|
|
|
TArray<FRigVMGraphVariableDescription> LocalVariables = Graph->GetLocalVariables(false);
|
|
|
|
|
for (FRigVMGraphVariableDescription Variable : LocalVariables)
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
{
|
2022-02-14 05:26:33 -05:00
|
|
|
if (Variable.Name == Description.Name)
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
{
|
2022-02-14 05:26:33 -05:00
|
|
|
if (Local::RefreshIfNeeded(Controller, VariableNode, Variable.CPPType, Variable.CPPTypeObject))
|
|
|
|
|
{
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-14 05:26:33 -05:00
|
|
|
else
|
Merging //UE5/Dev-LargeWorldCoordinates [at] 18802167 to //UE5/Release-5.0
Blueprint real number support.
This change deprecates the use the of "float" and "double" types in Blueprints in favor of a new "real". By default, "real" is back by a double precision floating point number. However, it can be single precision if the number is a native float property or function parameter. This distinction won't be visible to the Blueprint user: in both instances, they'll be represented by "real" pin types. During deserialization, we'll automatically convert Blueprint pin types to use real/doubles, unless they're used to represent native code (including delegate signatures).
One consequence of this change is that we need to perform implicit casts between single and double precision real numbers. During Blueprint compilation, the compiler will detect points in the graph for when either a widening or narrowing conversion needs to occur. Subsequently, the script bytecode will contain a new cast instruction that performs the conversion. This also works on container types, but each entry in the container will have to be converted. This can introduce unwanted overhead for large containers that are frequently passed between Blueprint and native code.
The scope of this change affects Blueprints used by Gameplay, Animation, Control Rig, and UMG.
#rb marc.audy (serialization changes)
#jira UE-116484
#preflight 61f8bdd5a2514ba12ff7bdfc
#ROBOMERGE-AUTHOR: dave.jones2
#ROBOMERGE-SOURCE: CL 18809077 in //UE5/Release-5.0/... via CL 18809455 via CL 18822548
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v908-18788545)
[CL 18823569 by dave jones2 in ue5-main branch]
2022-02-02 05:50:50 -05:00
|
|
|
{
|
|
|
|
|
for (struct FBPVariableDescription& Variable : NewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (Variable.VarName == Description.Name)
|
|
|
|
|
{
|
|
|
|
|
FString CPPType;
|
|
|
|
|
UObject* CPPTypeObject = nullptr;
|
|
|
|
|
RigVMTypeUtils::CPPTypeFromPinType(Variable.VarType, CPPType, &CPPTypeObject);
|
|
|
|
|
if (Local::RefreshIfNeeded(Controller, VariableNode, CPPType, CPPTypeObject))
|
|
|
|
|
{
|
|
|
|
|
bDirtyDuringLoad = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 19:02:15 -05:00
|
|
|
// change the default value form False to True for transform nodes
|
|
|
|
|
void UControlRigBlueprint::PatchPropagateToChildren()
|
|
|
|
|
{
|
|
|
|
|
// no need to update default value past this version
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) >= FControlRigObjectVersion::RenameGizmoToShape)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto IsNullOrControl = [](const URigVMPin* InPin)
|
|
|
|
|
{
|
|
|
|
|
const bool bHasItem = InPin->GetCPPTypeObject() == FRigElementKey::StaticStruct() && InPin->GetName() == "Item";
|
|
|
|
|
if (!bHasItem)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (const URigVMPin* TypePin = InPin->FindSubPin(TEXT("Type")))
|
|
|
|
|
{
|
|
|
|
|
const FString& TypeValue = TypePin->GetDefaultValue();
|
2022-06-15 16:00:03 -04:00
|
|
|
return TypeValue == TEXT("Null") || TypeValue == TEXT("Space") || TypeValue == TEXT("Control");
|
2022-03-11 19:02:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto IsPropagateChildren = [](const URigVMPin* InPin)
|
|
|
|
|
{
|
|
|
|
|
return InPin->GetCPPType() == TEXT("bool") && InPin->GetName() == TEXT("bPropagateToChildren");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto FindPropagatePin = [IsNullOrControl, IsPropagateChildren](const URigVMNode* InNode)-> URigVMPin*
|
|
|
|
|
{
|
|
|
|
|
URigVMPin* PropagatePin = nullptr;
|
|
|
|
|
URigVMPin* ItemPin = nullptr;
|
|
|
|
|
for (URigVMPin* Pin: InNode->GetPins())
|
|
|
|
|
{
|
|
|
|
|
// look for Item pin
|
|
|
|
|
if (!ItemPin && IsNullOrControl(Pin))
|
|
|
|
|
{
|
|
|
|
|
ItemPin = Pin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// look for bPropagateToChildren pin
|
|
|
|
|
if (!PropagatePin && IsPropagateChildren(Pin))
|
|
|
|
|
{
|
|
|
|
|
PropagatePin = Pin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return propagation pin if both found
|
|
|
|
|
if (ItemPin && PropagatePin)
|
|
|
|
|
{
|
|
|
|
|
return PropagatePin;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
|
|
|
|
TArray< const URigVMPin* > PinsToUpdate;
|
|
|
|
|
for (const URigVMNode* Node : Graph->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if (const URigVMPin* PropagatePin = FindPropagatePin(Node))
|
|
|
|
|
{
|
|
|
|
|
PinsToUpdate.Add(PropagatePin);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (URigVMController* Controller = GetOrCreateController(Graph))
|
|
|
|
|
{
|
|
|
|
|
Controller->SuspendNotifications(true);
|
|
|
|
|
for (const URigVMPin* Pin: PinsToUpdate)
|
|
|
|
|
{
|
|
|
|
|
Controller->SetPinDefaultValue(Pin->GetPinPath(), TEXT("True"), false, false, false);
|
|
|
|
|
}
|
|
|
|
|
Controller->SuspendNotifications(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 10:20:24 -05:00
|
|
|
void UControlRigBlueprint::PatchParameterNodesOnLoad()
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
// setup variables on the blueprint based on the previous "parameters"
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::RemoveParameters)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
TGuardValue<bool> GuardNotifsSelf(bSuspendModelNotificationsForSelf, true);
|
|
|
|
|
|
|
|
|
|
GetOrCreateController()->ReattachLinksToPinObjects();
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
check(GetDefaultModel());
|
2022-03-07 10:20:24 -05:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
for(URigVMGraph* Model : RigVMClient)
|
2022-03-07 10:20:24 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
TArray<URigVMNode*> Nodes = Model->GetNodes();
|
|
|
|
|
for (URigVMNode* Node : Nodes)
|
2022-03-07 10:20:24 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (URigVMParameterNode* ParameterNode = Cast<URigVMParameterNode>(Node))
|
2022-03-07 10:20:24 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
FRigVMGraphParameterDescription Description = ParameterNode->GetParameterDescription();
|
2022-03-07 10:20:24 -05:00
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
const FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromCPPType(Description.CPPType, Description.CPPTypeObject);
|
|
|
|
|
|
|
|
|
|
int32 VariableIndex = INDEX_NONE;
|
|
|
|
|
bool bFoundName = false;
|
|
|
|
|
for (int32 i=0; i<NewVariables.Num(); ++i)
|
2022-03-07 10:20:24 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (NewVariables[i].VarName == Description.Name)
|
2022-03-07 10:20:24 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (NewVariables[i].VarType == PinType &&
|
|
|
|
|
NewVariables[i].DefaultValue == Description.DefaultValue)
|
2022-03-07 10:20:24 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
VariableIndex = i;
|
|
|
|
|
}
|
|
|
|
|
bFoundName = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (VariableIndex == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
FName NewVariableName = Description.Name;
|
|
|
|
|
if (bFoundName)
|
|
|
|
|
{
|
|
|
|
|
bool bFound = true;
|
|
|
|
|
int32 Count = 0;
|
|
|
|
|
while (bFound)
|
|
|
|
|
{
|
|
|
|
|
bFound = false;
|
|
|
|
|
for (int32 i=0; i<NewVariables.Num(); ++i)
|
2022-03-07 10:20:24 -05:00
|
|
|
{
|
2022-05-31 04:27:20 -04:00
|
|
|
if (NewVariables[i].VarName == NewVariableName)
|
|
|
|
|
{
|
|
|
|
|
bFound = true;
|
|
|
|
|
NewVariableName = *FString::Printf(TEXT("%s_%d"), *Description.Name.ToString(), ++Count);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-07 10:20:24 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
|
|
|
|
|
VariableIndex = AddCRMemberVariable(this, NewVariableName, PinType, false, false, Description.DefaultValue);
|
2022-03-07 10:20:24 -05:00
|
|
|
}
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
FName VarName = NewVariables[VariableIndex].VarName;
|
|
|
|
|
GetOrCreateController()->ReplaceParameterNodeWithVariable(ParameterNode->GetFName(), VarName, Description.CPPType, Description.CPPTypeObject, false);
|
|
|
|
|
bDirtyDuringLoad = true;
|
2022-03-07 10:20:24 -05:00
|
|
|
}
|
|
|
|
|
}
|
2022-05-31 04:27:20 -04:00
|
|
|
}
|
2022-03-07 10:20:24 -05:00
|
|
|
LastNewVariables = NewVariables;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-18 06:43:26 -04:00
|
|
|
void UControlRigBlueprint::PatchTemplateNodesWithPreferredPermutation()
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
if (GetLinkerCustomVersion(FControlRigObjectVersion::GUID) < FControlRigObjectVersion::TemplatesPreferredPermutatation)
|
|
|
|
|
{
|
|
|
|
|
for (URigVMGraph* Graph : GetAllModels())
|
|
|
|
|
{
|
|
|
|
|
for(URigVMNode* ModelNode : Graph->GetNodes())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMTemplateNode* TemplateNode = Cast<URigVMTemplateNode>(ModelNode))
|
|
|
|
|
{
|
|
|
|
|
TemplateNode->InvalidateCache();
|
2022-05-20 09:28:06 -04:00
|
|
|
TemplateNode->PostLoad();
|
2022-05-18 06:43:26 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GetController(Graph)->InitializeFilteredPermutationsFromTemplateTypes();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::PropagatePoseFromInstanceToBP(UControlRig* InControlRig)
|
2019-09-17 19:12:19 -04:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
check(InControlRig);
|
2021-11-08 09:59:36 -05:00
|
|
|
// current transforms in BP and CDO are meaningless, no need to copy them
|
|
|
|
|
// we use BP hierarchy to initialize CDO and instances' hierarchy,
|
|
|
|
|
// so it should always be in the initial state.
|
2022-02-18 10:27:44 -05:00
|
|
|
Hierarchy->CopyPose(InControlRig->GetHierarchy(), false, true, false, true);
|
2019-09-17 19:12:19 -04:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::PropagatePoseFromBPToInstances()
|
2019-09-17 19:12:19 -04:00
|
|
|
{
|
|
|
|
|
if (UClass* MyControlRigClass = GeneratedClass)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* DefaultObject = Cast<UControlRig>(MyControlRigClass->GetDefaultObject(false)))
|
|
|
|
|
{
|
2021-09-21 05:06:09 -04:00
|
|
|
DefaultObject->PostInitInstanceIfRequired();
|
2022-02-18 10:27:44 -05:00
|
|
|
DefaultObject->GetHierarchy()->CopyPose(Hierarchy, true, true, true);
|
2021-06-09 17:27:12 -04:00
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
DefaultObject->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(ArchetypeInstance))
|
2021-02-22 13:36:33 -04:00
|
|
|
{
|
2021-09-21 05:06:09 -04:00
|
|
|
InstanceRig->PostInitInstanceIfRequired();
|
2022-02-18 10:27:44 -05:00
|
|
|
InstanceRig->GetHierarchy()->CopyPose(Hierarchy, true, true, true);
|
2021-02-22 13:36:33 -04:00
|
|
|
}
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
void UControlRigBlueprint::PropagateHierarchyFromBPToInstances()
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
|
|
|
|
if (UClass* MyControlRigClass = GeneratedClass)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* DefaultObject = Cast<UControlRig>(MyControlRigClass->GetDefaultObject(false)))
|
|
|
|
|
{
|
2021-09-21 05:06:09 -04:00
|
|
|
DefaultObject->PostInitInstanceIfRequired();
|
2021-02-22 13:36:33 -04:00
|
|
|
DefaultObject->GetHierarchy()->CopyHierarchy(Hierarchy);
|
|
|
|
|
DefaultObject->Initialize(true);
|
2019-09-17 19:12:19 -04:00
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
DefaultObject->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2019-09-17 19:12:19 -04:00
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(ArchetypeInstance))
|
|
|
|
|
{
|
2021-09-21 05:06:09 -04:00
|
|
|
InstanceRig->PostInitInstanceIfRequired();
|
2021-02-22 13:36:33 -04:00
|
|
|
InstanceRig->GetHierarchy()->CopyHierarchy(Hierarchy);
|
|
|
|
|
InstanceRig->Initialize(true);
|
2019-09-17 19:12:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::PropagateDrawInstructionsFromBPToInstances()
|
|
|
|
|
{
|
|
|
|
|
if (UClass* MyControlRigClass = GeneratedClass)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* DefaultObject = Cast<UControlRig>(MyControlRigClass->GetDefaultObject(false)))
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
DefaultObject->DrawContainer = DrawContainer;
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
DefaultObject->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(ArchetypeInstance))
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
{
|
2020-01-22 17:58:55 -05:00
|
|
|
InstanceRig->DrawContainer = DrawContainer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// make sure the bone name list is up 2 date for the editor graph
|
|
|
|
|
for (UEdGraph* Graph : UbergraphPages)
|
|
|
|
|
{
|
|
|
|
|
UControlRigGraph* RigGraph = Cast<UControlRigGraph>(Graph);
|
|
|
|
|
if (RigGraph == nullptr)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-02-22 13:36:33 -04:00
|
|
|
RigGraph->CacheNameLists(Hierarchy, &DrawContainer);
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-20 12:55:39 -04:00
|
|
|
void UControlRigBlueprint::PropagateRuntimeSettingsFromBPToInstances()
|
|
|
|
|
{
|
|
|
|
|
if (UClass* MyControlRigClass = GeneratedClass)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* DefaultObject = Cast<UControlRig>(MyControlRigClass->GetDefaultObject(false)))
|
|
|
|
|
{
|
|
|
|
|
DefaultObject->VMRuntimeSettings = VMRuntimeSettings;
|
|
|
|
|
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
DefaultObject->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(ArchetypeInstance))
|
|
|
|
|
{
|
|
|
|
|
InstanceRig->VMRuntimeSettings = VMRuntimeSettings;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<UEdGraph*> EdGraphs;
|
|
|
|
|
GetAllGraphs(EdGraphs);
|
|
|
|
|
|
|
|
|
|
for (UEdGraph* Graph : EdGraphs)
|
|
|
|
|
{
|
|
|
|
|
TArray<UEdGraphNode*> Nodes = Graph->Nodes;
|
|
|
|
|
for (UEdGraphNode* Node : Nodes)
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigGraphNode* RigNode = Cast<UControlRigGraphNode>(Node))
|
|
|
|
|
{
|
|
|
|
|
RigNode->ReconstructNode_Internal(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:58:55 -05:00
|
|
|
void UControlRigBlueprint::PropagatePropertyFromBPToInstances(FRigElementKey InRigElement, const FProperty* InProperty)
|
|
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
int32 ElementIndex = Hierarchy->GetIndex(InRigElement);
|
2020-01-22 17:58:55 -05:00
|
|
|
ensure(ElementIndex != INDEX_NONE);
|
|
|
|
|
check(InProperty);
|
|
|
|
|
|
|
|
|
|
if (UClass* MyControlRigClass = GeneratedClass)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* DefaultObject = Cast<UControlRig>(MyControlRigClass->GetDefaultObject(false)))
|
|
|
|
|
{
|
|
|
|
|
TArray<UObject*> ArchetypeInstances;
|
|
|
|
|
DefaultObject->GetArchetypeInstances(ArchetypeInstances);
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
const int32 PropertyOffset = InProperty->GetOffset_ReplaceWith_ContainerPtrToValuePtr();
|
|
|
|
|
const int32 PropertySize = InProperty->GetSize();
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
uint8* Source = ((uint8*)Hierarchy->Get(ElementIndex)) + PropertyOffset;
|
|
|
|
|
for (UObject* ArchetypeInstance : ArchetypeInstances)
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
if (UControlRig* InstanceRig = Cast<UControlRig>(ArchetypeInstance))
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2021-09-21 05:06:09 -04:00
|
|
|
InstanceRig->PostInitInstanceIfRequired();
|
2021-02-22 13:36:33 -04:00
|
|
|
uint8* Dest = ((uint8*)InstanceRig->GetHierarchy()->Get(ElementIndex)) + PropertyOffset;
|
|
|
|
|
FMemory::Memcpy(Dest, Source, PropertySize);
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-22 13:36:33 -04:00
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::PropagatePropertyFromInstanceToBP(FRigElementKey InRigElement, const FProperty* InProperty, UControlRig* InInstance)
|
|
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
const int32 ElementIndex = Hierarchy->GetIndex(InRigElement);
|
2020-01-22 17:58:55 -05:00
|
|
|
ensure(ElementIndex != INDEX_NONE);
|
|
|
|
|
check(InProperty);
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
const int32 PropertyOffset = InProperty->GetOffset_ReplaceWith_ContainerPtrToValuePtr();
|
|
|
|
|
const int32 PropertySize = InProperty->GetSize();
|
|
|
|
|
uint8* Source = ((uint8*)InInstance->GetHierarchy()->Get(ElementIndex)) + PropertyOffset;
|
|
|
|
|
uint8* Dest = ((uint8*)Hierarchy->Get(ElementIndex)) + PropertyOffset;
|
|
|
|
|
FMemory::Memcpy(Dest, Source, PropertySize);
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
|
|
|
|
|
void UControlRigBlueprint::HandleHierarchyModified(ERigHierarchyNotification InNotification, URigHierarchy* InHierarchy, const FRigBaseElement* InElement)
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
if(bSuspendAllNotifications)
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(InNotification)
|
|
|
|
|
{
|
|
|
|
|
case ERigHierarchyNotification::ElementRemoved:
|
2020-01-22 17:58:55 -05:00
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
Modify();
|
|
|
|
|
Influences.OnKeyRemoved(InElement->GetKey());
|
|
|
|
|
PropagateHierarchyFromBPToInstances();
|
2020-01-22 17:58:55 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2021-02-22 13:36:33 -04:00
|
|
|
case ERigHierarchyNotification::ElementRenamed:
|
|
|
|
|
{
|
|
|
|
|
Modify();
|
|
|
|
|
Influences.OnKeyRenamed(FRigElementKey(InHierarchy->GetPreviousName(InElement->GetKey()), InElement->GetType()), InElement->GetKey());
|
|
|
|
|
PropagateHierarchyFromBPToInstances();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ERigHierarchyNotification::ElementAdded:
|
|
|
|
|
case ERigHierarchyNotification::ParentChanged:
|
|
|
|
|
case ERigHierarchyNotification::HierarchyReset:
|
|
|
|
|
{
|
|
|
|
|
Modify();
|
|
|
|
|
PropagateHierarchyFromBPToInstances();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ERigHierarchyNotification::ElementSelected:
|
|
|
|
|
{
|
|
|
|
|
bool bClearTransientControls = true;
|
|
|
|
|
if (const FRigControlElement* ControlElement = Cast<FRigControlElement>(InElement))
|
Reimplementing FProperty changes from //UE4/Main
+ Reimplemented FProperty related fixed from //UE4/Main:
CL#10791312, 10804850, 10851666, 10855122, 10855198, 10942138, 11030611, 11030639, 11032261, 11061515, 11136964,11138881, 11214238, 11214865
#rb none (previously reviewed in Dev-Core)
[FYI] Chris.Bunnner, Daniel.Lamb
#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 11302985 via CL 11303011 via CL 11303019
#ROBOMERGE-BOT: (v0-11244347)
[CL 11303183 by robert manuszewski in Main branch]
2020-02-10 08:06:56 -05:00
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
if (ControlElement->Settings.bIsTransientControl)
|
|
|
|
|
{
|
|
|
|
|
bClearTransientControls = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-09 09:19:35 -04:00
|
|
|
if(bClearTransientControls)
|
|
|
|
|
{
|
|
|
|
|
if(UControlRig* RigBeingDebugged = Cast<UControlRig>(GetObjectBeingDebugged()))
|
|
|
|
|
{
|
|
|
|
|
const FName TransientControlName = UControlRig::GetNameForTransientControl(InElement->GetKey());
|
|
|
|
|
const FRigElementKey TransientControlKey(TransientControlName, ERigElementType::Control);
|
|
|
|
|
if (const FRigControlElement* ControlElement = RigBeingDebugged->GetHierarchy()->Find<FRigControlElement>(TransientControlKey))
|
|
|
|
|
{
|
|
|
|
|
if (ControlElement->Settings.bIsTransientControl)
|
|
|
|
|
{
|
|
|
|
|
bClearTransientControls = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
if(bClearTransientControls)
|
|
|
|
|
{
|
|
|
|
|
ClearTransientControls();
|
|
|
|
|
}
|
2020-01-22 17:58:55 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-21 08:03:43 -04:00
|
|
|
|
|
|
|
|
HierarchyModifiedEvent.Broadcast(InNotification, InHierarchy, InElement);
|
2021-02-22 13:36:33 -04:00
|
|
|
|
2019-09-17 19:12:19 -04:00
|
|
|
#endif
|
2021-02-22 13:36:33 -04:00
|
|
|
}
|
2019-09-17 19:12:19 -04:00
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
UControlRigBlueprint::FControlValueScope::FControlValueScope(UControlRigBlueprint* InBlueprint)
|
|
|
|
|
: Blueprint(InBlueprint)
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
check(Blueprint);
|
|
|
|
|
|
|
|
|
|
if (UControlRig* CR = Cast<UControlRig>(Blueprint->GetObjectBeingDebugged()))
|
|
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
TArray<FRigControlElement*> Controls = CR->AvailableControls();
|
|
|
|
|
for (FRigControlElement* ControlElement : Controls)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2021-02-22 13:36:33 -04:00
|
|
|
ControlValues.Add(ControlElement->GetName(), CR->GetControlValue(ControlElement->GetName()));
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UControlRigBlueprint::FControlValueScope::~FControlValueScope()
|
|
|
|
|
{
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
check(Blueprint);
|
|
|
|
|
|
|
|
|
|
if (UControlRig* CR = Cast<UControlRig>(Blueprint->GetObjectBeingDebugged()))
|
|
|
|
|
{
|
|
|
|
|
for (const TPair<FName, FRigControlValue>& Pair : ControlValues)
|
|
|
|
|
{
|
|
|
|
|
if (CR->FindControl(Pair.Key))
|
|
|
|
|
{
|
|
|
|
|
CR->SetControlValue(Pair.Key, Pair.Value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::OnPreVariableChange(UObject* InObject)
|
|
|
|
|
{
|
|
|
|
|
if (InObject != this)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
LastNewVariables = NewVariables;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::OnPostVariableChange(UBlueprint* InBlueprint)
|
|
|
|
|
{
|
|
|
|
|
if (InBlueprint != this)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TMap<FGuid, int32> NewVariablesByGuid;
|
|
|
|
|
for (int32 VarIndex = 0; VarIndex < NewVariables.Num(); VarIndex++)
|
|
|
|
|
{
|
|
|
|
|
NewVariablesByGuid.Add(NewVariables[VarIndex].VarGuid, VarIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TMap<FGuid, int32> OldVariablesByGuid;
|
|
|
|
|
for (int32 VarIndex = 0; VarIndex < LastNewVariables.Num(); VarIndex++)
|
|
|
|
|
{
|
|
|
|
|
OldVariablesByGuid.Add(LastNewVariables[VarIndex].VarGuid, VarIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const FBPVariableDescription& OldVariable : LastNewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (!NewVariablesByGuid.Contains(OldVariable.VarGuid))
|
|
|
|
|
{
|
|
|
|
|
OnVariableRemoved(OldVariable.VarName);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const FBPVariableDescription& NewVariable : NewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (!OldVariablesByGuid.Contains(NewVariable.VarGuid))
|
|
|
|
|
{
|
|
|
|
|
OnVariableAdded(NewVariable.VarName);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32 OldVarIndex = OldVariablesByGuid.FindChecked(NewVariable.VarGuid);
|
|
|
|
|
const FBPVariableDescription& OldVariable = LastNewVariables[OldVarIndex];
|
|
|
|
|
if (OldVariable.VarName != NewVariable.VarName)
|
|
|
|
|
{
|
|
|
|
|
OnVariableRenamed(OldVariable.VarName, NewVariable.VarName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (OldVariable.VarType != NewVariable.VarType)
|
|
|
|
|
{
|
|
|
|
|
OnVariableTypeChanged(NewVariable.VarName, OldVariable.VarType, NewVariable.VarType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LastNewVariables = NewVariables;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::OnVariableAdded(const FName& InVarName)
|
|
|
|
|
{
|
2021-07-22 04:23:56 -04:00
|
|
|
FBPVariableDescription Variable;
|
|
|
|
|
for (FBPVariableDescription& NewVariable : NewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (NewVariable.VarName == InVarName)
|
|
|
|
|
{
|
|
|
|
|
Variable = NewVariable;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 08:00:07 -05:00
|
|
|
const FRigVMExternalVariable ExternalVariable = RigVMTypeUtils::ExternalVariableFromBPVariableDescription(Variable);
|
|
|
|
|
FString CPPType;
|
|
|
|
|
UObject* CPPTypeObject = nullptr;
|
|
|
|
|
RigVMTypeUtils::CPPTypeFromExternalVariable(ExternalVariable, CPPType, &CPPTypeObject);
|
|
|
|
|
if (CPPTypeObject)
|
|
|
|
|
{
|
|
|
|
|
if (ExternalVariable.bIsArray)
|
|
|
|
|
{
|
|
|
|
|
CPPType = RigVMTypeUtils::ArrayTypeFromBaseType(CPPTypeObject->GetPathName());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CPPType = CPPTypeObject->GetPathName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RigVMPythonUtils::Print(GetFName().ToString(),
|
2021-07-27 09:59:13 -04:00
|
|
|
FString::Printf(TEXT("blueprint.add_member_variable('%s', '%s', %s, %s, '%s')"),
|
2021-07-22 04:23:56 -04:00
|
|
|
*InVarName.ToString(),
|
2021-11-18 08:00:07 -05:00
|
|
|
*CPPType,
|
2021-07-22 04:23:56 -04:00
|
|
|
(ExternalVariable.bIsPublic) ? TEXT("False") : TEXT("True"),
|
|
|
|
|
(ExternalVariable.bIsReadOnly) ? TEXT("True") : TEXT("False"),
|
|
|
|
|
*Variable.DefaultValue));
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
BroadcastExternalVariablesChangedEvent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::OnVariableRemoved(const FName& InVarName)
|
|
|
|
|
{
|
2020-12-14 08:58:12 -04:00
|
|
|
TArray<URigVMGraph*> AllGraphs = GetAllModels();
|
|
|
|
|
for (URigVMGraph* Graph : AllGraphs)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2020-12-14 08:58:12 -04:00
|
|
|
if (URigVMController* Controller = GetOrCreateController(Graph))
|
|
|
|
|
{
|
2021-09-30 09:27:41 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
const bool bSetupUndoRedo = !GIsTransacting;
|
|
|
|
|
#else
|
|
|
|
|
const bool bSetupUndoRedo = false;
|
|
|
|
|
#endif
|
|
|
|
|
Controller->OnExternalVariableRemoved(InVarName, bSetupUndoRedo);
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
2021-07-22 04:23:56 -04:00
|
|
|
|
2021-07-27 09:59:13 -04:00
|
|
|
RigVMPythonUtils::Print(GetFName().ToString(),
|
|
|
|
|
FString::Printf(TEXT("blueprint.remove_member_variable('%s')"),
|
2021-07-22 04:23:56 -04:00
|
|
|
*InVarName.ToString()));
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
BroadcastExternalVariablesChangedEvent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::OnVariableRenamed(const FName& InOldVarName, const FName& InNewVarName)
|
|
|
|
|
{
|
2020-12-14 08:58:12 -04:00
|
|
|
TArray<URigVMGraph*> AllGraphs = GetAllModels();
|
|
|
|
|
for (URigVMGraph* Graph : AllGraphs)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2020-12-14 08:58:12 -04:00
|
|
|
if (URigVMController* Controller = GetOrCreateController(Graph))
|
|
|
|
|
{
|
2021-09-30 09:27:41 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
const bool bSetupUndoRedo = !GIsTransacting;
|
|
|
|
|
#else
|
|
|
|
|
const bool bSetupUndoRedo = false;
|
|
|
|
|
#endif
|
|
|
|
|
Controller->OnExternalVariableRenamed(InOldVarName, InNewVarName, bSetupUndoRedo);
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
2021-07-22 04:23:56 -04:00
|
|
|
|
2021-07-27 09:59:13 -04:00
|
|
|
RigVMPythonUtils::Print(GetFName().ToString(),
|
|
|
|
|
FString::Printf(TEXT("blueprint.rename_member_variable('%s', '%s')"),
|
2021-07-22 04:23:56 -04:00
|
|
|
*InOldVarName.ToString(),
|
|
|
|
|
*InNewVarName.ToString()));
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
BroadcastExternalVariablesChangedEvent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::OnVariableTypeChanged(const FName& InVarName, FEdGraphPinType InOldPinType, FEdGraphPinType InNewPinType)
|
|
|
|
|
{
|
2021-10-28 10:08:41 -04:00
|
|
|
FString CPPType;
|
2021-11-18 08:00:07 -05:00
|
|
|
UObject* CPPTypeObject = nullptr;
|
|
|
|
|
RigVMTypeUtils::CPPTypeFromPinType(InNewPinType, CPPType, &CPPTypeObject);
|
2021-10-28 10:08:41 -04:00
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
TArray<URigVMGraph*> AllGraphs = GetAllModels();
|
|
|
|
|
for (URigVMGraph* Graph : AllGraphs)
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2020-12-14 08:58:12 -04:00
|
|
|
if (URigVMController* Controller = GetOrCreateController(Graph))
|
2020-09-24 00:43:27 -04:00
|
|
|
{
|
2021-06-24 16:28:30 -04:00
|
|
|
#if WITH_EDITOR
|
|
|
|
|
const bool bSetupUndoRedo = !GIsTransacting;
|
|
|
|
|
#else
|
|
|
|
|
const bool bSetupUndoRedo = false;
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-10-28 10:08:41 -04:00
|
|
|
if (!CPPType.IsEmpty())
|
2020-12-14 08:58:12 -04:00
|
|
|
{
|
2021-10-28 10:08:41 -04:00
|
|
|
Controller->OnExternalVariableTypeChanged(InVarName, CPPType, CPPTypeObject, bSetupUndoRedo);
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-07-22 04:23:56 -04:00
|
|
|
Controller->OnExternalVariableRemoved(InVarName, bSetupUndoRedo);
|
2020-12-14 08:58:12 -04:00
|
|
|
}
|
2020-09-24 00:43:27 -04:00
|
|
|
}
|
|
|
|
|
}
|
2021-07-22 04:23:56 -04:00
|
|
|
|
2021-10-28 10:08:41 -04:00
|
|
|
if(UScriptStruct* ScriptStruct = Cast<UScriptStruct>(CPPTypeObject))
|
2021-07-22 04:23:56 -04:00
|
|
|
{
|
|
|
|
|
for (auto Var : NewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (Var.VarName == InVarName)
|
|
|
|
|
{
|
2021-10-28 10:08:41 -04:00
|
|
|
CPPType = ScriptStruct->GetName();
|
2021-07-22 04:23:56 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-28 10:08:41 -04:00
|
|
|
else if (UEnum* Enum = Cast<UEnum>(CPPTypeObject))
|
2021-07-22 04:23:56 -04:00
|
|
|
{
|
|
|
|
|
for (auto Var : NewVariables)
|
|
|
|
|
{
|
|
|
|
|
if (Var.VarName == InVarName)
|
|
|
|
|
{
|
2021-10-28 10:08:41 -04:00
|
|
|
CPPType = Enum->GetName();
|
2021-07-22 04:23:56 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 09:59:13 -04:00
|
|
|
RigVMPythonUtils::Print(GetFName().ToString(),
|
|
|
|
|
FString::Printf(TEXT("blueprint.change_member_variable_type('%s', '%s')"),
|
2021-07-22 04:23:56 -04:00
|
|
|
*InVarName.ToString(),
|
2021-10-28 10:08:41 -04:00
|
|
|
*CPPType));
|
2021-07-22 04:23:56 -04:00
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
BroadcastExternalVariablesChangedEvent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::BroadcastExternalVariablesChangedEvent()
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigBlueprintGeneratedClass* RigClass = GetControlRigBlueprintGeneratedClass())
|
|
|
|
|
{
|
|
|
|
|
if (UControlRig* CDO = Cast<UControlRig>(RigClass->GetDefaultObject(true /* create if needed */)))
|
|
|
|
|
{
|
|
|
|
|
ExternalVariablesChangedEvent.Broadcast(CDO->GetExternalVariables());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
void UControlRigBlueprint::BroadcastNodeDoubleClicked(URigVMNode* InNode)
|
|
|
|
|
{
|
|
|
|
|
NodeDoubleClickedEvent.Broadcast(this, InNode);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 13:22:54 -04:00
|
|
|
void UControlRigBlueprint::BroadcastGraphImported(UEdGraph* InGraph)
|
|
|
|
|
{
|
|
|
|
|
GraphImportedEvent.Broadcast(InGraph);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-22 13:36:33 -04:00
|
|
|
void UControlRigBlueprint::BroadcastPostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedChainEvent)
|
|
|
|
|
{
|
|
|
|
|
PostEditChangeChainPropertyEvent.Broadcast(PropertyChangedChainEvent);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-10 05:52:25 -04:00
|
|
|
void UControlRigBlueprint::BroadcastRequestLocalizeFunctionDialog(URigVMLibraryNode* InFunction, bool bForce)
|
|
|
|
|
{
|
|
|
|
|
RequestLocalizeFunctionDialog.Broadcast(InFunction, this, bForce);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-07 13:09:20 -04:00
|
|
|
void UControlRigBlueprint::BroadCastReportCompilerMessage(EMessageSeverity::Type InSeverity, UObject* InSubject, const FString& InMessage)
|
|
|
|
|
{
|
|
|
|
|
ReportCompilerMessageEvent.Broadcast(InSeverity, InSubject, InMessage);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
#endif
|
|
|
|
|
|
2022-05-31 04:27:20 -04:00
|
|
|
UEdGraph* UControlRigBlueprint::CreateEdGraph(URigVMGraph* InModel, bool bForce)
|
|
|
|
|
{
|
|
|
|
|
check(InModel);
|
|
|
|
|
|
|
|
|
|
if(InModel->IsA<URigVMFunctionLibrary>())
|
|
|
|
|
{
|
|
|
|
|
return FunctionLibraryEdGraph;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(bForce)
|
|
|
|
|
{
|
|
|
|
|
RemoveEdGraph(InModel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FString GraphName = InModel->GetName();
|
|
|
|
|
GraphName.RemoveFromStart(RigVMModelPrefix);
|
|
|
|
|
GraphName.TrimStartAndEndInline();
|
|
|
|
|
|
|
|
|
|
if(GraphName.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
GraphName = UControlRigGraphSchema::GraphName_ControlRig.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GraphName = RigVMClient.GetUniqueName(*GraphName).ToString();
|
|
|
|
|
|
|
|
|
|
UControlRigGraph* ControlRigGraph = NewObject<UControlRigGraph>(this, *GraphName, RF_Transactional);
|
|
|
|
|
ControlRigGraph->Schema = UControlRigGraphSchema::StaticClass();
|
|
|
|
|
ControlRigGraph->bAllowDeletion = true;
|
|
|
|
|
|
|
|
|
|
FBlueprintEditorUtils::AddUbergraphPage(this, ControlRigGraph);
|
|
|
|
|
LastEditedDocuments.AddUnique(ControlRigGraph);
|
|
|
|
|
|
|
|
|
|
ControlRigGraph->Initialize(this);
|
|
|
|
|
ControlRigGraph->ModelNodePath = InModel->GetNodePath();
|
|
|
|
|
|
|
|
|
|
return ControlRigGraph;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::RemoveEdGraph(URigVMGraph* InModel)
|
|
|
|
|
{
|
|
|
|
|
if(UControlRigGraph* RigGraph = Cast<UControlRigGraph>(GetEdGraph(InModel)))
|
|
|
|
|
{
|
|
|
|
|
if(UbergraphPages.Contains(RigGraph))
|
|
|
|
|
{
|
|
|
|
|
Modify();
|
|
|
|
|
UbergraphPages.Remove(RigGraph);
|
|
|
|
|
}
|
|
|
|
|
DestroyObject(RigGraph);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::DestroyObject(UObject* InObject)
|
|
|
|
|
{
|
|
|
|
|
RigVMClient.DestroyObject(InObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UControlRigBlueprint::RenameGraph(const FString& InNodePath, const FName& InNewName)
|
|
|
|
|
{
|
|
|
|
|
FName OldName = NAME_None;
|
|
|
|
|
UEdGraph* EdGraph = GetEdGraph(InNodePath);
|
|
|
|
|
if(EdGraph)
|
|
|
|
|
{
|
|
|
|
|
OldName = EdGraph->GetFName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RigVMClient.RenameModel(InNodePath, InNewName, true);
|
|
|
|
|
|
|
|
|
|
if(EdGraph)
|
|
|
|
|
{
|
|
|
|
|
NotifyGraphRenamed(EdGraph, OldName, EdGraph->GetFName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
void UControlRigBlueprint::CreateEdGraphForCollapseNodeIfNeeded(URigVMCollapseNode* InNode, bool bForce)
|
|
|
|
|
{
|
|
|
|
|
check(InNode);
|
|
|
|
|
|
|
|
|
|
if (bForce)
|
|
|
|
|
{
|
|
|
|
|
RemoveEdGraphForCollapseNode(InNode, false);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 15:00:40 -04:00
|
|
|
if (InNode->GetGraph()->IsA<URigVMFunctionLibrary>())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMGraph* ContainedGraph = InNode->GetContainedGraph())
|
|
|
|
|
{
|
|
|
|
|
bool bFunctionGraphExists = false;
|
|
|
|
|
for (UEdGraph* FunctionGraph : FunctionGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* RigFunctionGraph = Cast<UControlRigGraph>(FunctionGraph))
|
|
|
|
|
{
|
|
|
|
|
if (RigFunctionGraph->ModelNodePath == ContainedGraph->GetNodePath())
|
|
|
|
|
{
|
|
|
|
|
bFunctionGraphExists = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!bFunctionGraphExists)
|
|
|
|
|
{
|
|
|
|
|
// create a sub graph
|
|
|
|
|
UControlRigGraph* RigFunctionGraph = NewObject<UControlRigGraph>(this, *InNode->GetName(), RF_Transactional);
|
|
|
|
|
RigFunctionGraph->Schema = UControlRigGraphSchema::StaticClass();
|
|
|
|
|
RigFunctionGraph->bAllowRenaming = 1;
|
|
|
|
|
RigFunctionGraph->bEditable = 1;
|
|
|
|
|
RigFunctionGraph->bAllowDeletion = 1;
|
|
|
|
|
RigFunctionGraph->ModelNodePath = ContainedGraph->GetNodePath();
|
|
|
|
|
RigFunctionGraph->bIsFunctionDefinition = true;
|
|
|
|
|
|
|
|
|
|
FunctionGraphs.Add(RigFunctionGraph);
|
|
|
|
|
|
|
|
|
|
RigFunctionGraph->Initialize(this);
|
|
|
|
|
|
|
|
|
|
GetOrCreateController(ContainedGraph)->ResendAllNotifications();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (UControlRigGraph* RigGraph = Cast<UControlRigGraph>(GetEdGraph(InNode->GetGraph())))
|
2020-12-14 08:58:12 -04:00
|
|
|
{
|
|
|
|
|
if (URigVMGraph* ContainedGraph = InNode->GetContainedGraph())
|
|
|
|
|
{
|
|
|
|
|
bool bSubGraphExists = false;
|
|
|
|
|
for (UEdGraph* SubGraph : RigGraph->SubGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* SubRigGraph = Cast<UControlRigGraph>(SubGraph))
|
|
|
|
|
{
|
|
|
|
|
if (SubRigGraph->ModelNodePath == ContainedGraph->GetNodePath())
|
|
|
|
|
{
|
|
|
|
|
bSubGraphExists = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!bSubGraphExists)
|
|
|
|
|
{
|
2022-03-30 05:21:45 -04:00
|
|
|
bool bEditable = true;
|
|
|
|
|
if (InNode->IsA<URigVMAggregateNode>())
|
|
|
|
|
{
|
|
|
|
|
bEditable = false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 08:58:12 -04:00
|
|
|
// create a sub graph
|
|
|
|
|
UControlRigGraph* SubRigGraph = NewObject<UControlRigGraph>(RigGraph, *InNode->GetEditorSubGraphName(), RF_Transactional);
|
|
|
|
|
SubRigGraph->Schema = UControlRigGraphSchema::StaticClass();
|
|
|
|
|
SubRigGraph->bAllowRenaming = 1;
|
2022-03-30 05:21:45 -04:00
|
|
|
SubRigGraph->bEditable = bEditable;
|
2020-12-14 08:58:12 -04:00
|
|
|
SubRigGraph->bAllowDeletion = 1;
|
2021-01-14 15:00:40 -04:00
|
|
|
SubRigGraph->ModelNodePath = ContainedGraph->GetNodePath();
|
|
|
|
|
SubRigGraph->bIsFunctionDefinition = false;
|
2020-12-14 08:58:12 -04:00
|
|
|
|
|
|
|
|
RigGraph->SubGraphs.Add(SubRigGraph);
|
|
|
|
|
|
|
|
|
|
SubRigGraph->Initialize(this);
|
|
|
|
|
|
|
|
|
|
GetOrCreateController(ContainedGraph)->ResendAllNotifications();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UControlRigBlueprint::RemoveEdGraphForCollapseNode(URigVMCollapseNode* InNode, bool bNotify)
|
|
|
|
|
{
|
|
|
|
|
check(InNode);
|
|
|
|
|
|
2021-01-14 15:00:40 -04:00
|
|
|
if (InNode->GetGraph()->IsA<URigVMFunctionLibrary>())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMGraph* ContainedGraph = InNode->GetContainedGraph())
|
|
|
|
|
{
|
|
|
|
|
for (UEdGraph* FunctionGraph : FunctionGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* RigFunctionGraph = Cast<UControlRigGraph>(FunctionGraph))
|
|
|
|
|
{
|
|
|
|
|
if (RigFunctionGraph->ModelNodePath == ContainedGraph->GetNodePath())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMController* SubController = GetController(ContainedGraph))
|
|
|
|
|
{
|
|
|
|
|
SubController->OnModified().RemoveAll(RigFunctionGraph);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ModifiedEvent.IsBound() && bNotify)
|
|
|
|
|
{
|
|
|
|
|
ModifiedEvent.Broadcast(ERigVMGraphNotifType::NodeRemoved, InNode->GetGraph(), InNode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FunctionGraphs.Remove(RigFunctionGraph);
|
2022-05-31 04:27:20 -04:00
|
|
|
RigFunctionGraph->Rename(nullptr, GetTransientPackage(), REN_ForceNoResetLoaders | REN_DontCreateRedirectors);
|
2021-11-18 14:37:34 -05:00
|
|
|
RigFunctionGraph->MarkAsGarbage();
|
2021-01-14 15:00:40 -04:00
|
|
|
return bNotify;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (UControlRigGraph* RigGraph = Cast<UControlRigGraph>(GetEdGraph(InNode->GetGraph())))
|
2020-12-14 08:58:12 -04:00
|
|
|
{
|
|
|
|
|
if (URigVMGraph* ContainedGraph = InNode->GetContainedGraph())
|
|
|
|
|
{
|
|
|
|
|
for (UEdGraph* SubGraph : RigGraph->SubGraphs)
|
|
|
|
|
{
|
|
|
|
|
if (UControlRigGraph* SubRigGraph = Cast<UControlRigGraph>(SubGraph))
|
|
|
|
|
{
|
|
|
|
|
if (SubRigGraph->ModelNodePath == ContainedGraph->GetNodePath())
|
|
|
|
|
{
|
|
|
|
|
if (URigVMController* SubController = GetController(ContainedGraph))
|
|
|
|
|
{
|
|
|
|
|
SubController->OnModified().RemoveAll(SubRigGraph);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ModifiedEvent.IsBound() && bNotify)
|
|
|
|
|
{
|
|
|
|
|
ModifiedEvent.Broadcast(ERigVMGraphNotifType::NodeRemoved, InNode->GetGraph(), InNode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RigGraph->SubGraphs.Remove(SubRigGraph);
|
2022-05-31 04:27:20 -04:00
|
|
|
SubRigGraph->Rename(nullptr, GetTransientPackage(), REN_ForceNoResetLoaders | REN_DontCreateRedirectors);
|
2021-11-18 14:37:34 -05:00
|
|
|
SubRigGraph->MarkAsGarbage();
|
2020-12-14 08:58:12 -04:00
|
|
|
return bNotify;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 11:38:48 -05:00
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|
|
|
|