You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Avoid rebuilding graphs if we don't need to. hashes contain the structure of each node, the structure of any used data type and the structure of each used template. #rb sara.schvartzman #preflight https://horde.devtools.epicgames.com/job/63ee1c6fc9692d7c04423941 [CL 24280391 by helge mathee in ue5-main branch]
1070 lines
30 KiB
C++
1070 lines
30 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "RigVMModel/RigVMClient.h"
|
|
#include "Misc/TransactionObjectEvent.h"
|
|
#include "Exporters/Exporter.h"
|
|
#include "UnrealExporter.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(RigVMClient)
|
|
|
|
#if WITH_EDITOR
|
|
#include "ScopedTransaction.h"
|
|
#endif
|
|
|
|
void FRigVMClient::SetOuterClientHost(UObject* InOuterClientHost, const FName& InOuterClientHostPropertyName)
|
|
{
|
|
OuterClientHost = InOuterClientHost;
|
|
OuterClientPropertyName = InOuterClientHostPropertyName;
|
|
|
|
check(OuterClientHost->Implements<URigVMClientHost>());
|
|
check(GetOuterClientProperty() != nullptr);
|
|
}
|
|
|
|
void FRigVMClient::SetFromDeprecatedData(URigVMGraph* InDefaultGraph, URigVMFunctionLibrary* InFunctionLibrary)
|
|
{
|
|
if(GetDefaultModel() != InDefaultGraph ||
|
|
GetFunctionLibrary() != InFunctionLibrary)
|
|
{
|
|
if(GetDefaultModel() == InDefaultGraph)
|
|
{
|
|
Models.Reset();
|
|
}
|
|
|
|
if(InFunctionLibrary == nullptr)
|
|
{
|
|
Swap(FunctionLibrary, InFunctionLibrary);
|
|
}
|
|
|
|
Reset();
|
|
if(InDefaultGraph)
|
|
{
|
|
AddModel(InDefaultGraph, false);
|
|
}
|
|
if(InFunctionLibrary)
|
|
{
|
|
AddModel(InFunctionLibrary, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FRigVMClient::Reset()
|
|
{
|
|
for(URigVMGraph* Model : Models)
|
|
{
|
|
DestroyObject(Model);
|
|
}
|
|
for(auto Pair : Controllers)
|
|
{
|
|
DestroyObject(Pair.Value);
|
|
}
|
|
DestroyObject(FunctionLibrary);
|
|
|
|
Models.Reset();
|
|
Controllers.Reset();
|
|
FunctionLibrary = nullptr;
|
|
}
|
|
|
|
URigVMGraph* FRigVMClient::GetDefaultModel() const
|
|
{
|
|
if(Models.IsEmpty())
|
|
{
|
|
return nullptr;
|
|
}
|
|
return GetModel(0);
|
|
}
|
|
|
|
URigVMGraph* FRigVMClient::GetModel(const FString& InNodePathOrName) const
|
|
{
|
|
if(InNodePathOrName.IsEmpty())
|
|
{
|
|
return GetDefaultModel();
|
|
}
|
|
|
|
TArray<URigVMGraph*> ModelsAndFunctionLibrary = GetAllModels(true, false);
|
|
for(URigVMGraph* Model : ModelsAndFunctionLibrary)
|
|
{
|
|
if(Model->GetNodePath() == InNodePathOrName || Model->GetName() == InNodePathOrName)
|
|
{
|
|
return Model;
|
|
}
|
|
|
|
static constexpr TCHAR NodePathPrefixFormat[] = TEXT("%s|");
|
|
const FString NodePathPrefix = FString::Printf(NodePathPrefixFormat, *Model->GetNodePath());
|
|
if(InNodePathOrName.StartsWith(NodePathPrefix))
|
|
{
|
|
const FString RemainingNodePath = InNodePathOrName.Mid(NodePathPrefix.Len());
|
|
if(const URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(Model->FindNode(RemainingNodePath)))
|
|
{
|
|
return CollapseNode->GetContainedGraph();
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
URigVMGraph* FRigVMClient::GetModel(const UObject* InEditorSideObject) const
|
|
{
|
|
check(InEditorSideObject);
|
|
|
|
if (InEditorSideObject->Implements<URigVMEditorSideObject>())
|
|
{
|
|
const IRigVMEditorSideObject* UserInterfaceGraph = Cast<IRigVMEditorSideObject>(InEditorSideObject);
|
|
return GetModel(UserInterfaceGraph->GetRigVMNodePath());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
TArray<URigVMGraph*> FRigVMClient::GetAllModels(bool bIncludeFunctionLibrary, bool bRecursive) const
|
|
{
|
|
TArray<URigVMGraph*> AllModels = Models;
|
|
if(bRecursive)
|
|
{
|
|
for(URigVMGraph* Model : Models)
|
|
{
|
|
AllModels.Append(Model->GetContainedGraphs(true /* recursive */));
|
|
}
|
|
}
|
|
if(bIncludeFunctionLibrary && FunctionLibrary)
|
|
{
|
|
AllModels.Add(FunctionLibrary);
|
|
if(bRecursive)
|
|
{
|
|
AllModels.Append(FunctionLibrary->GetContainedGraphs(true /* recursive */));
|
|
}
|
|
}
|
|
return AllModels;
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetController(int32 InIndex) const
|
|
{
|
|
return GetController(GetModel(InIndex));
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetController(const FString& InNodePathOrName) const
|
|
{
|
|
return GetController(GetModel(InNodePathOrName));
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetController(const URigVMGraph* InModel) const
|
|
{
|
|
if(InModel == nullptr)
|
|
{
|
|
InModel = GetDefaultModel();
|
|
}
|
|
|
|
if(InModel)
|
|
{
|
|
const FSoftObjectPath Key(InModel);
|
|
if(const TObjectPtr<URigVMController>* Controller = Controllers.Find(Key))
|
|
{
|
|
return Controller->Get();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetController(const UObject* InEditorSideObject) const
|
|
{
|
|
check(InEditorSideObject);
|
|
|
|
if (InEditorSideObject->Implements<URigVMEditorSideObject>())
|
|
{
|
|
const IRigVMEditorSideObject* UserInterfaceGraph = Cast<IRigVMEditorSideObject>(InEditorSideObject);
|
|
return GetController(UserInterfaceGraph->GetRigVMNodePath());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetOrCreateController(int32 InIndex)
|
|
{
|
|
return GetOrCreateController(GetModel(InIndex));
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetOrCreateController(const FString& InNodePathOrName)
|
|
{
|
|
return GetOrCreateController(GetModel(InNodePathOrName));
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetOrCreateController(const URigVMGraph* InModel)
|
|
{
|
|
if(InModel == nullptr)
|
|
{
|
|
InModel = GetDefaultModel();
|
|
}
|
|
|
|
if(InModel)
|
|
{
|
|
if(URigVMController* Controller = GetController(InModel))
|
|
{
|
|
return Controller;
|
|
}
|
|
return CreateController(InModel);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
URigVMController* FRigVMClient::GetOrCreateController(const UObject* InEditorSideObject)
|
|
{
|
|
check(InEditorSideObject);
|
|
|
|
if (InEditorSideObject->Implements<URigVMEditorSideObject>())
|
|
{
|
|
const IRigVMEditorSideObject* UserInterfaceGraph = Cast<IRigVMEditorSideObject>(InEditorSideObject);
|
|
return GetOrCreateController(UserInterfaceGraph->GetRigVMNodePath());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
URigVMGraph* FRigVMClient::AddModel(const FName& InName, bool bSetupUndoRedo, const FObjectInitializer* ObjectInitializer, bool bCreateController)
|
|
{
|
|
#if WITH_EDITOR
|
|
TSharedPtr<FScopedTransaction> Transaction;
|
|
if(bSetupUndoRedo)
|
|
{
|
|
Transaction = MakeShared<FScopedTransaction>(NSLOCTEXT("RigVMClient", "AddModel", "Add new root graph"));
|
|
GetOuter()->Modify();
|
|
}
|
|
#endif
|
|
|
|
const FName SafeGraphName = GetUniqueName(InName);
|
|
URigVMGraph* Model = nullptr;
|
|
if(ObjectInitializer)
|
|
{
|
|
Model = ObjectInitializer->CreateDefaultSubobject<URigVMGraph>(GetOuter(), SafeGraphName);
|
|
}
|
|
else
|
|
{
|
|
Model = NewObject<URigVMGraph>(GetOuter(), SafeGraphName);
|
|
}
|
|
AddModel(Model, bCreateController);
|
|
|
|
if(bSetupUndoRedo)
|
|
{
|
|
GetOuter()->Modify();
|
|
UndoRedoIndex++;
|
|
|
|
FRigVMClientAction Action;
|
|
Action.Type = ERigVMClientAction::ERigVMClientAction_AddModel;
|
|
Action.NodePath = Model->GetNodePath();
|
|
UndoStack.Push(Action);
|
|
RedoStack.Reset();
|
|
}
|
|
return Model;
|
|
}
|
|
|
|
void FRigVMClient::AddModel(URigVMGraph* InModel, bool bCreateController)
|
|
{
|
|
check(InModel);
|
|
|
|
if(InModel->IsA<URigVMFunctionLibrary>())
|
|
{
|
|
check(FunctionLibrary == nullptr);
|
|
FunctionLibrary = Cast<URigVMFunctionLibrary>(InModel);
|
|
}
|
|
else
|
|
{
|
|
Models.Add(InModel);
|
|
}
|
|
|
|
InModel->SetExecuteContextStruct(GetExecuteContextStruct());
|
|
|
|
if(bCreateController)
|
|
{
|
|
CreateController(InModel);
|
|
}
|
|
|
|
if(InModel->IsA<URigVMFunctionLibrary>())
|
|
{
|
|
for(URigVMGraph* Model : Models)
|
|
{
|
|
Model->SetDefaultFunctionLibrary(FunctionLibrary);
|
|
}
|
|
InModel->SetDefaultFunctionLibrary(FunctionLibrary);
|
|
}
|
|
else if(FunctionLibrary)
|
|
{
|
|
InModel->SetDefaultFunctionLibrary(FunctionLibrary);
|
|
}
|
|
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
IRigVMClientHost* ClientHost = Cast<IRigVMClientHost>(GetOuter());
|
|
ClientHost->HandleRigVMGraphAdded(this, InModel->GetNodePath());
|
|
}
|
|
|
|
NotifyOuterOfPropertyChange();
|
|
|
|
}
|
|
|
|
URigVMFunctionLibrary* FRigVMClient::GetOrCreateFunctionLibrary(bool bSetupUndoRedo, const FObjectInitializer* ObjectInitializer, bool bCreateController)
|
|
{
|
|
if(FunctionLibrary)
|
|
{
|
|
return FunctionLibrary;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
TSharedPtr<FScopedTransaction> Transaction;
|
|
if(bSetupUndoRedo)
|
|
{
|
|
Transaction = MakeShared<FScopedTransaction>(NSLOCTEXT("RigVMClient", "AddModel", "Add new root graph"));
|
|
GetOuter()->Modify();
|
|
}
|
|
#endif
|
|
|
|
static constexpr TCHAR FunctionLibraryName[] = TEXT("RigVMFunctionLibrary");
|
|
const FName SafeGraphName = GetUniqueName(FunctionLibraryName);
|
|
URigVMFunctionLibrary* NewFunctionLibrary = nullptr;
|
|
if(ObjectInitializer)
|
|
{
|
|
NewFunctionLibrary = ObjectInitializer->CreateDefaultSubobject<URigVMFunctionLibrary>(GetOuter(), SafeGraphName);
|
|
}
|
|
else
|
|
{
|
|
NewFunctionLibrary = NewObject<URigVMFunctionLibrary>(GetOuter(), SafeGraphName);
|
|
}
|
|
|
|
NewFunctionLibrary->GetFunctionHostObjectPathDelegate.BindLambda([this]() -> const FSoftObjectPath
|
|
{
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
IRigVMClientHost* ClientHost = Cast<IRigVMClientHost>(GetOuter());
|
|
return Cast<UObject>(ClientHost->GetRigVMGraphFunctionHost());
|
|
}
|
|
return nullptr;
|
|
});
|
|
|
|
AddModel(NewFunctionLibrary, bCreateController);
|
|
return NewFunctionLibrary;
|
|
}
|
|
|
|
TArray<FName> FRigVMClient::GetEntryNames() const
|
|
{
|
|
TArray<FName> EntryNames;
|
|
for(const URigVMGraph* Model : Models)
|
|
{
|
|
for(const URigVMNode* Node : Model->GetNodes())
|
|
{
|
|
const FName EntryName = Node->GetEventName();
|
|
if(!EntryName.IsNone())
|
|
{
|
|
EntryNames.Add(EntryName);
|
|
}
|
|
}
|
|
}
|
|
return EntryNames;
|
|
}
|
|
|
|
bool FRigVMClient::RemoveModel(const FString& InNodePathOrName, bool bSetupUndoRedo)
|
|
{
|
|
if(URigVMGraph* Model = GetModel(InNodePathOrName))
|
|
{
|
|
if(Model == GetDefaultModel())
|
|
{
|
|
#if WITH_EDITOR
|
|
static constexpr TCHAR Message[] = TEXT("Cannot remove the default model.");
|
|
FScriptExceptionHandler::Get().HandleException(ELogVerbosity::Error, Message, *FString());
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
if(Model == FunctionLibrary)
|
|
{
|
|
#if WITH_EDITOR
|
|
static constexpr TCHAR Message[] = TEXT("Cannot remove the function library.");
|
|
FScriptExceptionHandler::Get().HandleException(ELogVerbosity::Error, Message, *FString());
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
TSharedPtr<FScopedTransaction> Transaction;
|
|
if(bSetupUndoRedo)
|
|
{
|
|
Transaction = MakeShared<FScopedTransaction>(NSLOCTEXT("RigVMClient", "RemoveModel", "Remove a root graph"));
|
|
GetOuter()->Modify();
|
|
}
|
|
#endif
|
|
|
|
// remove the controller
|
|
if(URigVMController* Controller = GetController(Model))
|
|
{
|
|
verify(Controller == Controllers.FindAndRemoveChecked(Model));
|
|
}
|
|
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
IRigVMClientHost* ClientHost = Cast<IRigVMClientHost>(GetOuter());
|
|
ClientHost->HandleRigVMGraphRemoved(this, InNodePathOrName);
|
|
}
|
|
|
|
if(bSetupUndoRedo)
|
|
{
|
|
GetOuter()->Modify();
|
|
UndoRedoIndex++;
|
|
|
|
FRigVMClientAction Action;
|
|
Action.Type = ERigVMClientAction_RemoveModel;
|
|
Action.NodePath = Model->GetNodePath();
|
|
UndoStack.Push(Action);
|
|
RedoStack.Reset();
|
|
}
|
|
|
|
// clean up the model
|
|
Models.Remove(Model);
|
|
|
|
NotifyOuterOfPropertyChange();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FName FRigVMClient::RenameModel(const FString& InNodePathOrName, const FName& InNewName, bool bSetupUndoRedo)
|
|
{
|
|
if(URigVMGraph* Model = GetModel(InNodePathOrName))
|
|
{
|
|
if(Model == FunctionLibrary)
|
|
{
|
|
#if WITH_EDITOR
|
|
static constexpr TCHAR Message[] = TEXT("Cannot rename the function library.");
|
|
FScriptExceptionHandler::Get().HandleException(ELogVerbosity::Error, Message, *FString());
|
|
#endif
|
|
return NAME_None;
|
|
}
|
|
|
|
if(Model->GetFName() == InNewName)
|
|
{
|
|
return InNewName;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
TSharedPtr<FScopedTransaction> Transaction;
|
|
if(bSetupUndoRedo)
|
|
{
|
|
Transaction = MakeShared<FScopedTransaction>(NSLOCTEXT("RigVMClient", "RenameModel", "Rename a root graph"));
|
|
}
|
|
#endif
|
|
|
|
const FString OldNodePath = Model->GetNodePath();
|
|
const FName SafeNewName = GetUniqueName(InNewName);
|
|
Model->Rename(*SafeNewName.ToString(), nullptr, REN_ForceNoResetLoaders | REN_DontCreateRedirectors);
|
|
const FString NewNodePath = Model->GetNodePath();
|
|
|
|
if(bSetupUndoRedo)
|
|
{
|
|
GetOuter()->Modify();
|
|
UndoRedoIndex++;
|
|
|
|
FRigVMClientAction Action;
|
|
Action.Type = ERigVMClientAction_RenameModel;
|
|
Action.NodePath = OldNodePath;
|
|
Action.OtherNodePath = NewNodePath;
|
|
UndoStack.Push(Action);
|
|
RedoStack.Reset();
|
|
}
|
|
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
IRigVMClientHost* ClientHost = Cast<IRigVMClientHost>(GetOuter());
|
|
ClientHost->HandleRigVMGraphRenamed(this, OldNodePath, NewNodePath);
|
|
}
|
|
|
|
NotifyOuterOfPropertyChange();
|
|
return SafeNewName;
|
|
}
|
|
|
|
return NAME_None;
|
|
}
|
|
|
|
void FRigVMClient::PostTransacted(const FTransactionObjectEvent& TransactionEvent)
|
|
{
|
|
IRigVMClientHost* ClientHost = CastChecked<IRigVMClientHost>(GetOuter());
|
|
|
|
if (TransactionEvent.GetEventType() == ETransactionObjectEventType::UndoRedo)
|
|
{
|
|
auto PerformAction = [this, ClientHost](const FRigVMClientAction& InAction, bool bUndo)
|
|
{
|
|
switch(InAction.Type)
|
|
{
|
|
case ERigVMClientAction_AddModel:
|
|
case ERigVMClientAction_RemoveModel:
|
|
{
|
|
if(InAction.Type == ERigVMClientAction_RemoveModel)
|
|
{
|
|
bUndo = !bUndo;
|
|
}
|
|
|
|
if(URigVMGraph* Model = GetModel(InAction.NodePath))
|
|
{
|
|
if(bUndo)
|
|
{
|
|
ClientHost->HandleRigVMGraphRemoved(this, InAction.NodePath);
|
|
}
|
|
else
|
|
{
|
|
URigVMController* Controller = GetOrCreateController(Model);
|
|
ClientHost->HandleRigVMGraphAdded(this, InAction.NodePath);
|
|
if(Controller)
|
|
{
|
|
Controller->ResendAllNotifications();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ERigVMClientAction_RenameModel:
|
|
{
|
|
const FString NodePathA = bUndo ? InAction.OtherNodePath : InAction.NodePath;
|
|
const FString NodePathB = bUndo ? InAction.NodePath : InAction.OtherNodePath;
|
|
FString NodeNameB = NodePathB;
|
|
NodeNameB.Split(TEXT("|"), nullptr, &NodeNameB, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
|
|
NodeNameB.RemoveFromEnd(TEXT("::"));
|
|
|
|
RenameModel(NodePathA, *NodeNameB, false);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
while(UndoStack.Num() != UndoRedoIndex)
|
|
{
|
|
// do we need to undo - or redo?
|
|
if(UndoStack.Num() > UndoRedoIndex)
|
|
{
|
|
FRigVMClientAction Action = UndoStack.Pop();
|
|
PerformAction(Action, true);
|
|
RedoStack.Push(Action);
|
|
}
|
|
else
|
|
{
|
|
FRigVMClientAction Action = RedoStack.Pop();
|
|
PerformAction(Action, false);
|
|
UndoStack.Push(Action);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FRigVMClient::OnSubGraphRenamed(const FSoftObjectPath& OldObjectPath, const FSoftObjectPath& NewObjectPath)
|
|
{
|
|
if(OldObjectPath != NewObjectPath)
|
|
{
|
|
if (TObjectPtr<URigVMController>* Controller = Controllers.Find(OldObjectPath))
|
|
{
|
|
Controllers.Add(NewObjectPath, *Controller);
|
|
Controllers.Remove(OldObjectPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
URigVMNode* FRigVMClient::FindNode(const FString& InNodePathOrName) const
|
|
{
|
|
for(const URigVMGraph* Model : Models)
|
|
{
|
|
if(URigVMNode* Node = Model->FindNode(InNodePathOrName))
|
|
{
|
|
return Node;
|
|
}
|
|
}
|
|
if(FunctionLibrary)
|
|
{
|
|
return FunctionLibrary->FindNode(InNodePathOrName);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
URigVMPin* FRigVMClient::FindPin(const FString& InPinPath) const
|
|
{
|
|
for(const URigVMGraph* Model : Models)
|
|
{
|
|
if(URigVMPin* Pin = Model->FindPin(InPinPath))
|
|
{
|
|
return Pin;
|
|
}
|
|
}
|
|
if(FunctionLibrary)
|
|
{
|
|
return FunctionLibrary->FindPin(InPinPath);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
UObject* FRigVMClient::GetOuter() const
|
|
{
|
|
UObject* Outer = OuterClientHost.Get();
|
|
check(Outer);
|
|
return Outer;
|
|
}
|
|
|
|
FProperty* FRigVMClient::GetOuterClientProperty() const
|
|
{
|
|
return GetOuter()->GetClass()->FindPropertyByName(OuterClientPropertyName);
|
|
}
|
|
|
|
void FRigVMClient::NotifyOuterOfPropertyChange(EPropertyChangeType::Type ChangeType) const
|
|
{
|
|
if(bSuspendNotifications)
|
|
{
|
|
return;
|
|
}
|
|
FProperty* Property = GetOuterClientProperty();
|
|
FPropertyChangedEvent PropertyChangedEvent(Property, ChangeType);
|
|
GetOuter()->PostEditChangeProperty(PropertyChangedEvent);
|
|
}
|
|
|
|
URigVMController* FRigVMClient::CreateController(const URigVMGraph* InModel)
|
|
{
|
|
const FName SafeControllerName = GetUniqueName(*FString::Printf(TEXT("%s_Controller"), *InModel->GetName()));
|
|
URigVMController* Controller = NewObject<URigVMController>(GetOuter(), SafeControllerName);
|
|
Controllers.Add(InModel, Controller);
|
|
Controller->SetGraph((URigVMGraph*)InModel);
|
|
Controller->OnModified().AddLambda([this](ERigVMGraphNotifType InNotifType, URigVMGraph* InGraph, UObject* InSubject)
|
|
{
|
|
HandleGraphModifiedEvent(InNotifType, InGraph, InSubject);
|
|
});
|
|
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
IRigVMClientHost* ClientHost = Cast<IRigVMClientHost>(GetOuter());
|
|
ClientHost->HandleConfigureRigVMController(this, Controller);
|
|
}
|
|
|
|
Controller->RemoveStaleNodes();
|
|
return Controller;
|
|
}
|
|
|
|
FName FRigVMClient::GetUniqueName(const FName& InDesiredName) const
|
|
{
|
|
return GetUniqueName(GetOuter(), InDesiredName);
|
|
}
|
|
|
|
FName FRigVMClient::GetUniqueName(UObject* InOuter, const FName& InDesiredName)
|
|
{
|
|
return URigVMController::GetUniqueName(*InDesiredName.ToString(), [InOuter](const FName& InName) -> bool
|
|
{
|
|
return FindObjectWithOuter(InOuter, nullptr, InName) == nullptr;
|
|
}, false, true);
|
|
}
|
|
|
|
void FRigVMClient::DestroyObject(UObject* InObject)
|
|
{
|
|
if(InObject)
|
|
{
|
|
static int32 ObjectIndexToBeDestroyed = 0;
|
|
static constexpr TCHAR ObjectNameFormat[] = TEXT("RigVMClient_ObjectToBeDestroyed_%d");
|
|
const FString NewObjectName = FString::Printf(ObjectNameFormat, ObjectIndexToBeDestroyed++);
|
|
InObject->Rename(*NewObjectName, GetTransientPackage(), REN_ForceNoResetLoaders | REN_DontCreateRedirectors);
|
|
InObject->MarkAsGarbage();
|
|
}
|
|
}
|
|
|
|
uint32 FRigVMClient::GetStructureHash() const
|
|
{
|
|
uint32 Hash = 0;
|
|
const TArray<URigVMGraph*> ModelsAndFunctionLibrary = GetAllModels(true, true);
|
|
for(const URigVMGraph* Model : ModelsAndFunctionLibrary)
|
|
{
|
|
Hash = HashCombine(Hash, Model->GetStructureHash());
|
|
}
|
|
return Hash;
|
|
}
|
|
|
|
uint32 FRigVMClient::GetSerializedStructureHash() const
|
|
{
|
|
uint32 Hash = 0;
|
|
const TArray<URigVMGraph*> ModelsAndFunctionLibrary = GetAllModels(true, true);
|
|
for(const URigVMGraph* Model : ModelsAndFunctionLibrary)
|
|
{
|
|
Hash = HashCombine(Hash, Model->GetSerializedStructureHash());
|
|
}
|
|
return Hash;
|
|
}
|
|
|
|
FRigVMClientPatchResult FRigVMClient::PatchModelsOnLoad()
|
|
{
|
|
FRigVMClientPatchResult Result;
|
|
|
|
TArray<URigVMGraph*> AllModels = GetAllModels(true, true);
|
|
TGuardValue<bool> ClientIgnoreModificationsGuard(bIgnoreModelNotifications, true);
|
|
for(URigVMGraph* Model : AllModels)
|
|
{
|
|
URigVMController* Controller = GetOrCreateController(Model);
|
|
TGuardValue<bool> GuardSuspendTemplateComputation(Controller->bSuspendTemplateComputation, true);
|
|
TGuardValue<bool> GuardIsTransacting(Controller->bIsTransacting, true);
|
|
|
|
Result.Merge(Controller->PatchUnitNodesOnLoad());
|
|
Result.Merge(Controller->PatchDispatchNodesOnLoad());
|
|
Result.Merge(Controller->PatchBranchNodesOnLoad());
|
|
Result.Merge(Controller->PatchIfSelectNodesOnLoad());
|
|
Result.Merge(Controller->PatchArrayNodesOnLoad());
|
|
Result.Merge(Controller->PatchInvalidLinksOnWildcards());
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
void FRigVMClient::PostDuplicateHost(const FString& InOldPathName, const FString& InNewPathName)
|
|
{
|
|
TArray<URigVMGraph*> AllModels = GetAllModels(true, true);
|
|
for(URigVMGraph* Model : AllModels)
|
|
{
|
|
URigVMController* Controller = GetOrCreateController(Model);
|
|
Controller->PostDuplicateHost(InOldPathName, InNewPathName);
|
|
}
|
|
}
|
|
|
|
void FRigVMClient::PreSave()
|
|
{
|
|
for (URigVMNode* Node : FunctionLibrary->GetNodes())
|
|
{
|
|
if (URigVMLibraryNode* LibraryNode = Cast<URigVMLibraryNode>(Node))
|
|
{
|
|
UpdateGraphFunctionSerializedGraph(LibraryNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FRigVMClient::HandleGraphModifiedEvent(ERigVMGraphNotifType InNotifType, URigVMGraph* InGraph, UObject* InSubject)
|
|
{
|
|
if (bIgnoreModelNotifications)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
|
|
IRigVMClientHost* ClientHost = Cast<IRigVMClientHost>(GetOuter());
|
|
IRigVMGraphFunctionHost* FunctionHost = ClientHost->GetRigVMGraphFunctionHost();
|
|
FRigVMGraphFunctionStore* FunctionStore = FunctionHost->GetRigVMGraphFunctionStore();
|
|
|
|
switch (InNotifType)
|
|
{
|
|
case ERigVMGraphNotifType::NodeAdded: // A node has been added to the graph (Subject == URigVMNode)
|
|
{
|
|
// A node was added directly into the function library
|
|
if(InGraph->IsA<URigVMFunctionLibrary>())
|
|
{
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(InSubject))
|
|
{
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
FunctionStore->AddFunction(CollapseNode->GetFunctionHeader(FunctionHost), false);
|
|
}
|
|
}
|
|
}
|
|
// A node was added into the contained graph of a function
|
|
else if(URigVMLibraryNode* LibraryNode = Cast<URigVMNode>(InSubject)->FindFunctionForNode())
|
|
{
|
|
DirtyGraphFunctionCompilationData(LibraryNode);
|
|
if (URigVMFunctionReferenceNode* FunctionReference = Cast<URigVMFunctionReferenceNode>(InSubject))
|
|
{
|
|
UpdateDependenciesForFunction(LibraryNode);
|
|
UpdateExternalVariablesForFunction(LibraryNode);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ERigVMGraphNotifType::NodeRemoved: // A node has been removed from the graph (Subject == URigVMNode)
|
|
{
|
|
if(InSubject->GetOuter()->IsA<URigVMFunctionLibrary>())
|
|
{
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(InSubject))
|
|
{
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
FunctionStore->RemoveFunction(FRigVMGraphFunctionIdentifier (Cast<UObject>(FunctionHost), CollapseNode));
|
|
}
|
|
}
|
|
}
|
|
// A node was added into the contained graph of a function
|
|
else if(URigVMLibraryNode* LibraryNode = Cast<URigVMNode>(InSubject)->FindFunctionForNode())
|
|
{
|
|
DirtyGraphFunctionCompilationData(LibraryNode);
|
|
if (URigVMFunctionReferenceNode* FunctionReference = Cast<URigVMFunctionReferenceNode>(InSubject))
|
|
{
|
|
UpdateDependenciesForFunction(LibraryNode);
|
|
UpdateExternalVariablesForFunction(LibraryNode);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ERigVMGraphNotifType::VariableAdded: // A variable has been added (Subject == URigVMVariableNode)
|
|
case ERigVMGraphNotifType::VariableRemoved: // A variable has been removed (Subject == URigVMVariableNode)
|
|
case ERigVMGraphNotifType::VariableRenamed: // A variable has been renamed (Subject == URigVMVariableNode)
|
|
case ERigVMGraphNotifType::VariableRemappingChanged: // A function reference node's remapping has changed (Subject == URigVMFunctionReferenceNode)
|
|
{
|
|
if(URigVMLibraryNode* LibraryNode = Cast<URigVMNode>(InSubject)->FindFunctionForNode())
|
|
{
|
|
DirtyGraphFunctionCompilationData(LibraryNode);
|
|
UpdateExternalVariablesForFunction(LibraryNode);
|
|
}
|
|
break;
|
|
}
|
|
case ERigVMGraphNotifType::NodeRenamed: // A node has been renamed in the graph (Subject == URigVMNode)
|
|
{
|
|
if(InSubject->GetOuter()->IsA<URigVMFunctionLibrary>())
|
|
{
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(InSubject))
|
|
{
|
|
URigVMBuildData* BuildData = URigVMBuildData::Get();
|
|
IRigVMGraphFunctionHost* Host = Cast<IRigVMGraphFunctionHost>(CollapseNode->GetFunctionIdentifier().HostObject.ResolveObject());
|
|
FRigVMGraphFunctionData* Data = Host->GetRigVMGraphFunctionStore()->FindFunctionByName(CollapseNode->GetPreviousFName());
|
|
const FRigVMGraphFunctionIdentifier PreviousFunctionId = Data->Header.LibraryPointer;
|
|
Data->Header = CollapseNode->GetFunctionHeader();
|
|
|
|
if (const FRigVMFunctionReferenceArray* FunctionReferencesPtr = BuildData->GraphFunctionReferences.Find(PreviousFunctionId))
|
|
{
|
|
const FRigVMFunctionReferenceArray& FunctionReferences = *FunctionReferencesPtr;
|
|
BuildData->Modify();
|
|
FRigVMFunctionReferenceArray& NewFunctionReferences = BuildData->GraphFunctionReferences.Add(Data->Header.LibraryPointer, FunctionReferences);
|
|
BuildData->GraphFunctionReferences.Remove(PreviousFunctionId);
|
|
BuildData->MarkPackageDirty();
|
|
|
|
for (int32 i=0; i<NewFunctionReferences.Num(); ++i)
|
|
{
|
|
NewFunctionReferences[i]->ReferencedFunctionHeader = Data->Header;
|
|
}
|
|
}
|
|
|
|
UpdateGraphFunctionData(CollapseNode);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ERigVMGraphNotifType::NodeColorChanged: // A node's color has changed (Subject == URigVMNode)
|
|
case ERigVMGraphNotifType::NodeCategoryChanged: // A node's category has changed (Subject == URigVMNode)
|
|
case ERigVMGraphNotifType::NodeKeywordsChanged: // A node's keywords have changed (Subject == URigVMNode)
|
|
case ERigVMGraphNotifType::NodeDescriptionChanged: // A node's description has changed (Subject == URigVMNode)
|
|
{
|
|
if(InSubject->GetOuter()->IsA<URigVMFunctionLibrary>())
|
|
{
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(InSubject))
|
|
{
|
|
UpdateGraphFunctionData(CollapseNode);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ERigVMGraphNotifType::PinAdded: // A pin has been added to a given node (Subject == URigVMPin)
|
|
case ERigVMGraphNotifType::PinRemoved: // A pin has been removed from a given node (Subject == URigVMPin)
|
|
case ERigVMGraphNotifType::PinRenamed: // A pin has been renamed (Subject == URigVMPin)
|
|
case ERigVMGraphNotifType::PinArraySizeChanged: // An array pin's size has changed (Subject == URigVMPin)
|
|
case ERigVMGraphNotifType::PinDefaultValueChanged: // A pin's default value has changed (Subject == URigVMPin)
|
|
case ERigVMGraphNotifType::PinDirectionChanged: // A pin's direction has changed (Subject == URigVMPin)
|
|
case ERigVMGraphNotifType::PinTypeChanged: // A pin's data type has changed (Subject == URigVMPin)
|
|
case ERigVMGraphNotifType::PinIndexChanged: // A pin's index has changed (Subject == URigVMPin)
|
|
{
|
|
if (URigVMNode* Node = Cast<URigVMNode>(InSubject->GetOuter()))
|
|
{
|
|
if (URigVMLibraryNode* LibraryNode = Node->FindFunctionForNode())
|
|
{
|
|
DirtyGraphFunctionCompilationData(LibraryNode);
|
|
}
|
|
if(Node->GetOuter()->IsA<URigVMFunctionLibrary>())
|
|
{
|
|
if (URigVMCollapseNode* CollapseNode = Cast<URigVMCollapseNode>(Node))
|
|
{
|
|
UpdateGraphFunctionData(CollapseNode);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ERigVMGraphNotifType::LinkAdded: // A link has been added (Subject == URigVMLink)
|
|
case ERigVMGraphNotifType::LinkRemoved: // A link has been removed (Subject == URigVMLink)
|
|
{
|
|
if (URigVMLink* Link = Cast<URigVMLink>(InSubject))
|
|
{
|
|
if (URigVMNode* OuterNode = Cast<URigVMNode>(Link->GetGraph()->GetOuter()))
|
|
{
|
|
if (URigVMLibraryNode* LibraryNode = OuterNode->FindFunctionForNode())
|
|
{
|
|
DirtyGraphFunctionCompilationData(LibraryNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ERigVMGraphNotifType::FunctionAccessChanged: // A function was made public/private
|
|
{
|
|
if (URigVMLibraryNode* LibraryNode = Cast<URigVMLibraryNode>(InSubject))
|
|
{
|
|
if (URigVMFunctionLibrary* Library = Cast<URigVMFunctionLibrary>(InGraph))
|
|
{
|
|
bool bIsPublic = Library->IsFunctionPublic(LibraryNode->GetFName());
|
|
if (FRigVMGraphFunctionStore* Store = FindFunctionStore(LibraryNode))
|
|
{
|
|
Store->MarkFunctionAsPublic(LibraryNode->GetFunctionIdentifier(), bIsPublic);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
FRigVMGraphFunctionStore* FRigVMClient::FindFunctionStore(const URigVMLibraryNode* InLibraryNode)
|
|
{
|
|
if (IRigVMClientHost* ClientHost = InLibraryNode->GetImplementingOuter<IRigVMClientHost>())
|
|
{
|
|
if (IRigVMGraphFunctionHost* FunctionHost = ClientHost->GetRigVMGraphFunctionHost())
|
|
{
|
|
return FunctionHost->GetRigVMGraphFunctionStore();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool FRigVMClient::UpdateFunctionReferences(const FRigVMGraphFunctionHeader& Header, bool bUpdateDependencies, bool bUpdateExternalVariables)
|
|
{
|
|
URigVMBuildData* BuildData = URigVMBuildData::Get();
|
|
if (const FRigVMFunctionReferenceArray* FunctionReferenceArray = BuildData->FindFunctionReferences(Header.LibraryPointer))
|
|
{
|
|
for (int32 i=0; i<FunctionReferenceArray->Num(); ++i)
|
|
{
|
|
const TSoftObjectPtr<URigVMFunctionReferenceNode>& Reference = FunctionReferenceArray->FunctionReferences[i];
|
|
|
|
// Load reference package
|
|
if (!Reference.IsValid())
|
|
{
|
|
Reference.LoadSynchronous();
|
|
}
|
|
if (Reference.IsValid())
|
|
{
|
|
URigVMFunctionReferenceNode* Node = Reference.Get();
|
|
|
|
Node->Modify();
|
|
Node->ReferencedFunctionHeader = Header;
|
|
|
|
if (bUpdateDependencies || bUpdateExternalVariables)
|
|
{
|
|
if (URigVMLibraryNode* LibraryNode = Node->FindFunctionForNode())
|
|
{
|
|
IRigVMClientHost* OtherClientHost = LibraryNode->GetImplementingOuter<IRigVMClientHost>();
|
|
if (bUpdateDependencies)
|
|
{
|
|
OtherClientHost->GetRigVMClient()->UpdateDependenciesForFunction(LibraryNode);
|
|
}
|
|
if (bUpdateExternalVariables)
|
|
{
|
|
OtherClientHost->GetRigVMClient()->UpdateExternalVariablesForFunction(LibraryNode);
|
|
}
|
|
}
|
|
}
|
|
Node->MarkPackageDirty();
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FRigVMClient::UpdateGraphFunctionData(const URigVMLibraryNode* InLibraryNode)
|
|
{
|
|
if (GetOuter()->Implements<URigVMClientHost>())
|
|
{
|
|
if (FRigVMGraphFunctionStore* Store = FindFunctionStore(InLibraryNode))
|
|
{
|
|
if (FRigVMGraphFunctionData* Data = Store->UpdateFunctionInterface(InLibraryNode->GetFunctionHeader()))
|
|
{
|
|
UpdateFunctionReferences(Data->Header, false, false);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FRigVMClient::UpdateExternalVariablesForFunction(const URigVMLibraryNode* InLibraryNode)
|
|
{
|
|
if (FRigVMGraphFunctionStore* Store = FindFunctionStore(InLibraryNode))
|
|
{
|
|
FRigVMGraphFunctionIdentifier Identifier = InLibraryNode->GetFunctionIdentifier();
|
|
if (Store->UpdateExternalVariables(Identifier, InLibraryNode->GetExternalVariables()))
|
|
{
|
|
const FRigVMGraphFunctionData* Data = Store->FindFunction(Identifier);
|
|
UpdateFunctionReferences(Data->Header, false, true);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FRigVMClient::UpdateDependenciesForFunction(const URigVMLibraryNode* InLibraryNode)
|
|
{
|
|
if (FRigVMGraphFunctionStore* Store = FindFunctionStore(InLibraryNode))
|
|
{
|
|
TMap<FRigVMGraphFunctionIdentifier, uint32> Dependencies = InLibraryNode->GetDependencies();
|
|
FRigVMGraphFunctionIdentifier Identifier = InLibraryNode->GetFunctionIdentifier();
|
|
if (Store->UpdateDependencies(Identifier, Dependencies))
|
|
{
|
|
const FRigVMGraphFunctionData* Data = Store->FindFunction(Identifier);
|
|
UpdateFunctionReferences(Data->Header, true, false);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FRigVMClient::DirtyGraphFunctionCompilationData(URigVMLibraryNode* InLibraryNode)
|
|
{
|
|
if (FRigVMGraphFunctionStore* Store = FindFunctionStore(InLibraryNode))
|
|
{
|
|
FRigVMGraphFunctionIdentifier Identifier = InLibraryNode->GetFunctionIdentifier();
|
|
if (const FRigVMGraphFunctionData* Data = Store->FindFunction(Identifier))
|
|
{
|
|
Store->RemoveFunctionCompilationData(Identifier);
|
|
|
|
// References to this function will check if the compilation hash matches, and will recompile if they
|
|
// see a different compilation hash. No need to dirty their compilation data.
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FRigVMClient::UpdateGraphFunctionSerializedGraph(URigVMLibraryNode* InLibraryNode)
|
|
{
|
|
if (FRigVMGraphFunctionStore* Store = FindFunctionStore(InLibraryNode))
|
|
{
|
|
FRigVMGraphFunctionIdentifier Identifier = InLibraryNode->GetFunctionIdentifier();
|
|
if (FRigVMGraphFunctionData* Data = Store->FindFunction(Identifier))
|
|
{
|
|
FStringOutputDevice Archive;
|
|
const FExportObjectInnerContext Context;
|
|
UExporter::ExportToOutputDevice(&Context, InLibraryNode, NULL, Archive, TEXT("copy"), 0, PPF_ExportsNotFullyQualified | PPF_Copy | PPF_Delimited, false, nullptr);
|
|
Data->SerializedCollapsedNode = Archive;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool FRigVMClient::IsFunctionPublic(URigVMLibraryNode* InLibraryNode)
|
|
{
|
|
if (FRigVMGraphFunctionStore* Store = FindFunctionStore(InLibraryNode))
|
|
{
|
|
return Store->IsFunctionPublic(InLibraryNode->GetFunctionIdentifier());
|
|
}
|
|
return false;
|
|
}
|