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

1243 lines
36 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "RigVMBlueprintLegacy.h"
#include "RigVMBlueprintGeneratedClass.h"
#include "EdGraph/EdGraph.h"
#include "EdGraphNode_Comment.h"
#include "BlueprintActionDatabaseRegistrar.h"
#include "EdGraph/RigVMEdGraph.h"
#include "EdGraph/RigVMEdGraphNode.h"
#include "EdGraph/RigVMEdGraphSchema.h"
#include "UObject/AssetRegistryTagsContext.h"
#include "UObject/ObjectSaveContext.h"
#include "UObject/UObjectGlobals.h"
#include "RigVMObjectVersion.h"
#include "BlueprintCompilationManager.h"
#include "IMessageLogListing.h"
#include "RigVMCompiler/RigVMCompiler.h"
#include "RigVMCore/RigVMRegistry.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "RigVMPythonUtils.h"
#include "RigVMTypeUtils.h"
#include "Algo/Count.h"
#include "Misc/StringOutputDevice.h"
#include "RigVMModel/RigVMControllerActions.h"
#include "RigVMModel/Nodes/RigVMAggregateNode.h"
#include "RigVMModel/Nodes/RigVMDispatchNode.h"
#include "UObject/UE5MainStreamObjectVersion.h"
#include "Stats/StatsHierarchical.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(RigVMBlueprintLegacy)
#if WITH_EDITOR
#include "Kismet2/KismetDebugUtilities.h"
#include "Kismet2/WatchedPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "RigVMBlueprintUtils.h"
#include "Editor/UnrealEdEngine.h"
#include "Editor/Transactor.h"
#include "CookOnTheSide/CookOnTheFlyServer.h"
#include "RigVMEditorModule.h"
#include "ScopedTransaction.h"
#if !WITH_RIGVMLEGACYEDITOR
#include "RigVMEditor/Private/Editor/Kismet/RigVMBlueprintCompilationManager.h"
#endif
#endif//WITH_EDITOR
#define LOCTEXT_NAMESPACE "RigVMBlueprint"
FEdGraphPinType FRigVMOldPublicFunctionArg::GetPinType() const
{
FRigVMExternalVariable Variable;
Variable.Name = Name;
Variable.bIsArray = bIsArray;
Variable.TypeName = CPPType;
if(CPPTypeObjectPath.IsValid())
{
Variable.TypeObject = RigVMTypeUtils::FindObjectFromCPPTypeObjectPath(CPPTypeObjectPath.ToString());
}
return RigVMTypeUtils::PinTypeFromExternalVariable(Variable);
}
FRigVMOldPublicFunctionData::~FRigVMOldPublicFunctionData() = default;
bool FRigVMOldPublicFunctionData::IsMutable() const
{
for(const FRigVMOldPublicFunctionArg& Arg : Arguments)
{
if(!Arg.CPPTypeObjectPath.IsNone())
{
if(UScriptStruct* Struct = Cast<UScriptStruct>(
RigVMTypeUtils::FindObjectFromCPPTypeObjectPath(Arg.CPPTypeObjectPath.ToString())))
{
if(Struct->IsChildOf(FRigVMExecuteContext::StaticStruct()))
{
return true;
}
}
}
}
return false;
}
void URigVMBlueprint::BeginDestroy()
{
Super::BeginDestroy();
Clear();
}
void URigVMBlueprint::UpdateSupportedEventNames()
{
SupportedEventNames.Reset();
if (URigVMHost* CDO = Cast<URigVMHost>(GetDefaultsObject()))
{
SupportedEventNames = CDO->GetSupportedEvents();
}
}
UObject* URigVMBlueprint::GetDefaultsObject()
{
if (GeneratedClass)
{
return GeneratedClass->GetDefaultObject();
}
return nullptr;
}
void URigVMBlueprint::PostEditChangeBlueprintActors()
{
FBlueprintEditorUtils::PostEditChangeBlueprintActors(this);
}
FCompilerResultsLog URigVMBlueprint::CompileBlueprint()
{
FCompilerResultsLog LogResults;
LogResults.SetSourcePath(GetPathName());
LogResults.BeginEvent(TEXT("Compile"));
// TODO: sara-s remove once blueprint backend is replaced
{
EBlueprintCompileOptions CompileOptions = EBlueprintCompileOptions::None;
// If compilation is enabled during PIE/simulation, references to the CDO might be held by a script variable.
// Thus, we set the flag to direct the compiler to allow those references to be replaced during reinstancing.
if (GEditor->PlayWorld != nullptr)
{
CompileOptions |= EBlueprintCompileOptions::IncludeCDOInReferenceReplacement;
}
FKismetEditorUtilities::CompileBlueprint(this, CompileOptions, &LogResults);
}
LogResults.EndEvent();
// CachedNumWarnings = LogResults.NumWarnings;
// CachedNumErrors = LogResults.NumErrors;
if (UpgradeNotesLog.IsValid())
{
for (TSharedRef<FTokenizedMessage> Message :UpgradeNotesLog->Messages)
{
LogResults.AddTokenizedMessage(Message);
}
}
return LogResults;
}
URigVMBlueprint::URigVMBlueprint()
: IRigVMAssetInterface()
{
}
URigVMBlueprint::URigVMBlueprint(const FObjectInitializer& ObjectInitializer)
: IRigVMAssetInterface(ObjectInitializer)
{
#if WITH_EDITORONLY_DATA
ReferencedObjectPathsStored = false;
#endif
bRecompileOnLoad = 0;
SupportedEventNames.Reset();
VMCompileSettings.ASTSettings.ReportDelegate.BindUObject(this, &IRigVMAssetInterface::HandleReportFromCompiler);
bUpdatingExternalVariables = false;
#if WITH_EDITOR
if (HasAnyFlags(RF_ClassDefaultObject))
{
CompileLog.bSilentMode = true;
}
CompileLog.SetSourcePath(GetPathName());
#endif
if(GetClass() == URigVMBlueprint::StaticClass())
{
CommonInitialization(ObjectInitializer);
}
UBlueprint::OnChanged().AddUObject(this, &URigVMBlueprint::OnBlueprintChanged);
UBlueprint::OnSetObjectBeingDebugged().AddUObject(this, &URigVMBlueprint::OnSetObjectBeingDebuggedReceived);
}
URigVMBlueprintGeneratedClass* URigVMBlueprint::GetRigVMBlueprintGeneratedClass() const
{
URigVMBlueprintGeneratedClass* Result = Cast<URigVMBlueprintGeneratedClass>(*GeneratedClass);
return Result;
}
void URigVMBlueprint::PostSerialize(FArchive& Ar)
{
if(Ar.IsLoading())
{
if(Model_DEPRECATED || FunctionLibrary_DEPRECATED)
{
TGuardValue<bool> DisableClientNotifs(GetRigVMClient()->bSuspendNotifications, true);
GetRigVMClient()->SetFromDeprecatedData(Model_DEPRECATED, FunctionLibrary_DEPRECATED);
}
}
}
UClass* URigVMBlueprint::GetBlueprintClass() const
{
return URigVMBlueprintGeneratedClass::StaticClass();
}
UClass* URigVMBlueprint::RegenerateClass(UClass* ClassToRegenerate, UObject* PreviousCDO)
{
UClass* Result;
{
TGuardValue<bool> NotificationGuard(bSuspendAllNotifications, true);
Result = Super::RegenerateClass(ClassToRegenerate, PreviousCDO);
if (URigVMBlueprintGeneratedClass* Generated = Cast<URigVMBlueprintGeneratedClass>(Result))
{
Generated->SupportedEventNames = SupportedEventNames;
Generated->AssetVariant = AssetVariant;
}
}
return Result;
}
TArray<FRigVMExternalVariable> URigVMBlueprint::GetExternalVariables(bool bFallbackToBlueprint) const
{
TArray<FRigVMExternalVariable> ExternalVariables;
if (URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass())
{
if (URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(true /* create if needed */)))
{
return CDO->GetExternalVariablesImpl(bFallbackToBlueprint /* rely on variables within blueprint */);
}
}
return ExternalVariables;
}
URigVM* URigVMBlueprint::GetVM(bool bCreateIfNeeded) const
{
if (URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass())
{
if (URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(bCreateIfNeeded)))
{
return CDO->GetVM();
}
}
return nullptr;
}
FRigVMExtendedExecuteContext* URigVMBlueprint::GetRigVMExtendedExecuteContext()
{
if (URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass())
{
if (URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(false)))
{
return &CDO->GetRigVMExtendedExecuteContext();
}
}
return nullptr;
}
void URigVMBlueprint::SetAssetStatus(const ERigVMAssetStatus& InStatus)
{
switch (InStatus)
{
case RVMA_Dirty: Status = BS_Dirty; break;
case RVMA_Error: Status = BS_Error; break;
case RVMA_UpToDate: Status = BS_UpToDate; break;
case RVMA_BeingCreated: Status = BS_BeingCreated; break;
case RVMA_UpToDateWithWarnings: Status = BS_UpToDateWithWarnings; break;
default: Status = BS_Unknown; break;
}
}
ERigVMAssetStatus URigVMBlueprint::GetAssetStatus() const
{
switch (Status)
{
case BS_Dirty: return RVMA_Dirty; break;
case BS_Error: return RVMA_Error; break;
case BS_UpToDate: return RVMA_UpToDate; break;
case BS_BeingCreated: return RVMA_BeingCreated; break;
case BS_UpToDateWithWarnings: return RVMA_UpToDateWithWarnings; break;
default: return RVMA_Unknown; break;
}
}
TArray<UObject*> URigVMBlueprint::GetArchetypeInstances(bool bIncludeCDO, bool bIncludeDerivedClasses) const
{
URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass();
TArray<UObject*> ArchetypeInstances;
if (bIncludeCDO)
{
URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(false /* create if needed */));
ArchetypeInstances.Add(CDO);
}
//CDO->GetArchetypeInstances(ArchetypeInstances);
GetObjectsOfClass(RigClass, ArchetypeInstances, bIncludeDerivedClasses);
return ArchetypeInstances;
}
FRigVMDebugInfo& URigVMBlueprint::GetDebugInfo()
{
URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass();
URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(false));
return CDO->GetDebugInfo();
}
URigVMHost* URigVMBlueprint::CreateRigVMHostSuper(UObject* InOuter)
{
return NewObject<URigVMHost>(InOuter, GetRigVMHostClass());
}
void URigVMBlueprint::MarkAssetAsStructurallyModified(bool bSkipDirtyAssetStatus)
{
const TEnumAsByte<EBlueprintStatus> OldStatus = Status;
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
if (bSkipDirtyAssetStatus)
{
Status = OldStatus;
}
}
void URigVMBlueprint::MarkAssetAsModified(FPropertyChangedEvent PropertyChangedEvent)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(this, PropertyChangedEvent);
}
void URigVMBlueprint::AddUbergraphPage(URigVMEdGraph* RigVMEdGraph)
{
FBlueprintEditorUtils::AddUbergraphPage(this, RigVMEdGraph);
}
void URigVMBlueprint::AddLastEditedDocument(URigVMEdGraph* RigVMEdGraph)
{
LastEditedDocuments.AddUnique(RigVMEdGraph);
}
void URigVMBlueprint::Compile()
{
#if WITH_RIGVMLEGACYEDITOR
FBPCompileRequest Request(this, EBlueprintCompileOptions::None, nullptr);
FBlueprintCompilationManager::CompileSynchronously(Request);
#else
// FRigVMBPCompileRequest Request(this, EBlueprintCompileOptions::None, nullptr);
// FRigVMBlueprintCompilationManager::CompileSynchronously(Request);
#endif
}
void URigVMBlueprint::PatchVariableNodesOnLoad()
{
IRigVMAssetInterface::PatchVariableNodesOnLoad();
#if WITH_EDITOR
LastNewVariables = NewVariables;
#endif
}
void URigVMBlueprint::AddPinWatch(UEdGraphPin* InPin)
{
if (!FKismetDebugUtilities::IsPinBeingWatched(this, InPin))
{
FKismetDebugUtilities::AddPinWatch(this, FBlueprintWatchedPin(InPin));
}
}
void URigVMBlueprint::RemovePinWatch(UEdGraphPin* InPin)
{
FKismetDebugUtilities::RemovePinWatch(this, InPin);
}
void URigVMBlueprint::ClearPinWatches()
{
FKismetDebugUtilities::ClearPinWatches(this);
}
bool URigVMBlueprint::IsPinBeingWatched(const UEdGraphPin* InPin) const
{
return FKismetDebugUtilities::IsPinBeingWatched(this, InPin);
}
void URigVMBlueprint::ForeachPinWatch(TFunctionRef<void(UEdGraphPin*)> Task)
{
FKismetDebugUtilities::ForeachPinWatch(this, Task);
}
TMap<FString, FSoftObjectPath>& URigVMBlueprint::GetUserDefinedStructGuidToPathName(bool bFromCDO)
{
if (bFromCDO)
{
URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass();
URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(true /* create if needed */));
if (CDO)
{
return CDO->UserDefinedStructGuidToPathName;
}
}
return UserDefinedStructGuidToPathName;
}
TMap<FString, FSoftObjectPath>& URigVMBlueprint::GetUserDefinedEnumToPathName(bool bFromCDO)
{
if (bFromCDO)
{
URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass();
URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(true /* create if needed */));
if (CDO)
{
return CDO->UserDefinedEnumToPathName;
}
}
return UserDefinedEnumToPathName;
}
TSet<TObjectPtr<UObject>>& URigVMBlueprint::GetUserDefinedTypesInUse(bool bFromCDO)
{
if (bFromCDO)
{
URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass();
URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(true /* create if needed */));
if (CDO)
{
return CDO->UserDefinedTypesInUse;
}
}
return UserDefinedTypesInUse;
}
void URigVMBlueprint::PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent)
{
UBlueprint::PostEditChangeChainProperty(PropertyChangedEvent);
IRigVMAssetInterface::PostEditChangeChainProperty(PropertyChangedEvent);
}
void URigVMBlueprint::PostRename(UObject* OldOuter, const FName OldName)
{
UBlueprint::PostRename(OldOuter, OldName);
IRigVMAssetInterface::PostRename(OldOuter, OldName);
}
void URigVMBlueprint::GetPreloadDependencies(TArray<UObject*>& OutDeps)
{
UBlueprint::GetPreloadDependencies(OutDeps);
IRigVMAssetInterface::GetPreloadDependencies(OutDeps);
}
void URigVMBlueprint::PostSaveRoot(FObjectPostSaveRootContext ObjectSaveContext)
{
Super::PostSaveRoot(ObjectSaveContext);
// Make sure all the tags are accounted for in the TypeActions after we save
if (FBlueprintActionDatabase* ActionDatabase = FBlueprintActionDatabase::TryGet())
{
ActionDatabase->ClearAssetActions(GetClass());
ActionDatabase->RefreshClassActions(GetClass());
}
}
void URigVMBlueprint::PreSave(FObjectPreSaveContext ObjectSaveContext)
{
UBlueprint::PreSave(ObjectSaveContext);
IRigVMAssetInterface::PreSave(ObjectSaveContext);
if (URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass())
{
if (const URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(true /* create if needed */)))
{
RigClass->SupportedEventNames = SupportedEventNames;
}
RigClass->AssetVariant = AssetVariant;
}
}
void URigVMBlueprint::PostLoad()
{
UBlueprint::PostLoad();
IRigVMAssetInterface::PostLoad();
FCoreUObjectDelegates::OnObjectModified.RemoveAll(this);
FCoreUObjectDelegates::OnObjectModified.AddUObject(this, &URigVMBlueprint::OnPreVariableChange);
UBlueprint::OnChanged().RemoveAll(this);
UBlueprint::OnChanged().AddUObject(this, &URigVMBlueprint::OnPostVariableChange);
}
#if WITH_EDITORONLY_DATA
void URigVMBlueprint::DeclareConstructClasses(TArray<FTopLevelAssetPath>& OutConstructClasses, const UClass* SpecificSubclass)
{
UBlueprint::DeclareConstructClasses(OutConstructClasses, SpecificSubclass);
IRigVMAssetInterface::DeclareConstructClasses(OutConstructClasses, SpecificSubclass);
}
#endif
void URigVMBlueprint::OnBlueprintChanged(UBlueprint* InBlueprint)
{
IRigVMAssetInterface::OnChanged().Broadcast(InBlueprint);
}
void URigVMBlueprint::OnSetObjectBeingDebuggedReceived(UObject* InObject)
{
IRigVMAssetInterface::OnSetObjectBeingDebugged().Broadcast(InObject);
}
void URigVMBlueprint::PreCompile()
{
if (URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass())
{
URigVMHost* CDO = Cast<URigVMHost>(RigClass->GetDefaultObject(true /* create if needed */));
{
SetupDefaultObjectDuringCompilation(CDO);
if (!this->HasAnyFlags(RF_Transient | RF_Transactional))
{
CDO->Modify(false);
}
}
}
}
FProperty* URigVMBlueprint::FindGeneratedPropertyByName(const FName& InName) const
{
return SkeletonGeneratedClass->FindPropertyByName(InName);
}
bool URigVMBlueprint::SetVariableTooltip(const FName& InName, const FText& InTooltip)
{
FBlueprintEditorUtils::SetBlueprintVariableMetaData(this, InName, nullptr, FBlueprintMetadata::MD_Tooltip, InTooltip.ToString());
return true;
}
FText URigVMBlueprint::GetVariableTooltip(const FName& InName) const
{
FString Result;
FBlueprintEditorUtils::GetBlueprintVariableMetaData(this, InName, nullptr, FBlueprintMetadata::MD_Tooltip, Result);
return FText::FromString(Result);
}
bool URigVMBlueprint::SetVariableCategory(const FName& InName, const FString& InCategory)
{
FBlueprintEditorUtils::SetBlueprintVariableCategory(this, InName, nullptr, FText::FromString(InCategory), true);
return true;
}
FString URigVMBlueprint::GetVariableCategory(const FName& InName)
{
return FBlueprintEditorUtils::GetBlueprintVariableCategory(this, InName, nullptr).ToString();
}
FString URigVMBlueprint::GetVariableMetadataValue(const FName& InName, const FName& InKey)
{
FString Result;
FBlueprintEditorUtils::GetBlueprintVariableMetaData(this, InName, nullptr, InKey, /*out*/ Result);
return Result;
}
bool URigVMBlueprint::SetVariableExposeOnSpawn(const FName& InName, const bool bInExposeOnSpawn)
{
if(bInExposeOnSpawn)
{
FBlueprintEditorUtils::SetBlueprintVariableMetaData(this, InName, nullptr, FBlueprintMetadata::MD_ExposeOnSpawn, TEXT("true"));
}
else
{
FBlueprintEditorUtils::RemoveBlueprintVariableMetaData(this, InName, nullptr, FBlueprintMetadata::MD_ExposeOnSpawn);
}
return true;
}
bool URigVMBlueprint::SetVariableExposeToCinematics(const FName& InName, const bool bInExposeToCinematics)
{
FBlueprintEditorUtils::SetInterpFlag(this, InName, bInExposeToCinematics);
return true;
}
bool URigVMBlueprint::SetVariablePrivate(const FName& InName, const bool bInPrivate)
{
if(bInPrivate)
{
FBlueprintEditorUtils::SetBlueprintVariableMetaData(this, InName, nullptr, FBlueprintMetadata::MD_Private, TEXT("true"));
}
else
{
FBlueprintEditorUtils::RemoveBlueprintVariableMetaData(this, InName, nullptr, FBlueprintMetadata::MD_Private);
}
return true;
}
bool URigVMBlueprint::SetVariablePublic(const FName& InName, const bool bIsPublic)
{
FBlueprintEditorUtils::SetBlueprintOnlyEditableFlag(this, InName, bIsPublic);
return true;
}
FString URigVMBlueprint::OnCopyVariable(const FName& InName) const
{
FString OutputString;
int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InName);
if (VarIndex != INDEX_NONE)
{
// make a copy of the Variable description so we can set the default value
FBPVariableDescription Description = NewVariables[VarIndex];
//Grab property of blueprint's current CDO
UObject* GeneratedCDO = GeneratedClass->GetDefaultObject();
if (FProperty* TargetProperty = FindFProperty<FProperty>(GeneratedClass, Description.VarName))
{
// Grab the address of where the property is actually stored (UObject* base, plus the offset defined in the property)
if (void* OldPropertyAddr = TargetProperty->ContainerPtrToValuePtr<void>(GeneratedCDO))
{
TargetProperty->ExportTextItem_Direct(Description.DefaultValue, OldPropertyAddr, OldPropertyAddr, nullptr, PPF_SerializedAsImportText);
}
}
FBPVariableDescription::StaticStruct()->ExportText(OutputString, &Description, &Description, nullptr, 0, nullptr, false);
OutputString = TEXT("BPVar") + OutputString;
}
return OutputString;
}
bool URigVMBlueprint::OnPasteVariable(const FString& InText)
{
if (!ensure(InText.StartsWith(TEXT("BPVar"), ESearchCase::CaseSensitive)))
{
return false;
}
FBPVariableDescription Description;
FStringOutputDevice Errors;
const TCHAR* Import = InText.GetCharArray().GetData() + FCString::Strlen(TEXT("BPVar"));
FBPVariableDescription::StaticStruct()->ImportText(Import, &Description, nullptr, PPF_None, &Errors, FBPVariableDescription::StaticStruct()->GetName());
if (Errors.IsEmpty())
{
FBPVariableDescription NewVar = FBlueprintEditorUtils::DuplicateVariableDescription(this, Description);
if (NewVar.VarGuid.IsValid())
{
FScopedTransaction Transaction(FText::Format(LOCTEXT("PasteVariable", "Paste Variable: {0}"), FText::FromName(NewVar.VarName)));
Modify();
NewVariables.Add(NewVar);
// Potentially adjust variable names for any child blueprints
FBlueprintEditorUtils::ValidateBlueprintChildVariables(this, NewVar.VarName);
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
return true;
}
}
return false;
}
void URigVMBlueprint::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
UBlueprint::GetAssetRegistryTags(OutTags);
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
}
TArray<FRigVMGraphVariableDescription> URigVMBlueprint::GetAssetVariables() const
{
TArray<FRigVMGraphVariableDescription> Variables;
for (const FBPVariableDescription& BPVariable : NewVariables)
{
FRigVMGraphVariableDescription NewVariable;
NewVariable.Name = BPVariable.VarName;
NewVariable.DefaultValue = BPVariable.DefaultValue;
NewVariable.Category = BPVariable.Category;
FString CPPType;
UObject* CPPTypeObject;
RigVMTypeUtils::CPPTypeFromPinType(BPVariable.VarType, CPPType, &CPPTypeObject);
NewVariable.CPPType = CPPType;
NewVariable.CPPTypeObject = CPPTypeObject;
if (NewVariable.CPPTypeObject)
{
NewVariable.CPPTypeObjectPath = *NewVariable.CPPTypeObject->GetPathName();
}
if(BPVariable.HasMetaData(FBlueprintMetadata::MD_Tooltip))
{
NewVariable.Tooltip = FText::FromString(BPVariable.GetMetaData(FBlueprintMetadata::MD_Tooltip));
}
if(BPVariable.HasMetaData(FBlueprintMetadata::MD_ExposeOnSpawn))
{
NewVariable.bExposedOnSpawn = BPVariable.GetMetaData(FBlueprintMetadata::MD_ExposeOnSpawn) == TEXT("true");
}
if (BPVariable.PropertyFlags & CPF_Interp)
{
NewVariable.bExposeToCinematics = true;
}
if (!(BPVariable.PropertyFlags & CPF_DisableEditOnInstance))
{
NewVariable.bPublic = true;
}
if(BPVariable.HasMetaData(FBlueprintMetadata::MD_Private))
{
NewVariable.bPrivate = BPVariable.GetMetaData(FBlueprintMetadata::MD_Private) == TEXT("true");
}
Variables.Add(NewVariable);
}
return Variables;
}
#if WITH_EDITOR
// FName URigVMBlueprint::AddAssetVariable(const FName& InName, const FString& InCPPType, bool bIsPublic, bool bIsReadOnly, FString InDefaultValue)
// {
// FBPVariableDescription NewVar;
// const FRigVMExternalVariable Variable = RigVMTypeUtils::ExternalVariableFromCPPTypePath(InName, InCPPType, bIsPublic, bIsReadOnly);
// if (!Variable.IsValid(true))
// {
// return NAME_None;
// }
//
// return AddAssetVariableFromExternal(Variable, InDefaultValue);
// }
//
// FName URigVMBlueprint::AddAssetVariableFromExternal(const FRigVMExternalVariable& Variable, const FString& InDefaultValue)
// {
// FBPVariableDescription NewVar;
// TSharedPtr<FKismetNameValidator> NameValidator = MakeShareable(new FKismetNameValidator(this, NAME_None, nullptr));
// const FName VarName = FindHostMemberVariableUniqueName(NameValidator, Variable.Name.ToString());
// NewVar.VarName = VarName;
// NewVar.VarGuid = FGuid::NewGuid();
//
// NewVar.VarType = RigVMTypeUtils::PinTypeFromCPPType(Variable.TypeName, Variable.TypeObject);
// if (!NewVar.VarType.PinCategory.IsValid())
// {
// return NAME_None;
// }
// NewVar.FriendlyName = FName::NameToDisplayString(Variable.Name.ToString(), (NewVar.VarType.PinCategory == UEdGraphSchema_K2::PC_Boolean) ? true : false);
//
// NewVar.PropertyFlags |= (CPF_Edit | CPF_BlueprintVisible | CPF_DisableEditOnInstance);
//
// if (Variable.bIsPublic)
// {
// NewVar.PropertyFlags &= ~CPF_DisableEditOnInstance;
// }
//
// if (Variable.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"));
//
// NewVar.DefaultValue = InDefaultValue;
//
// Modify();
// NewVariables.Add(NewVar);
// MarkAssetAsModified();
//
// #if WITH_RIGVMLEGACYEDITOR
// FBPCompileRequest Request(this, EBlueprintCompileOptions::None, nullptr);
// FBlueprintCompilationManager::CompileSynchronously(Request);
// #endif
//
// return NewVar.VarName;
// }
//
// bool URigVMBlueprint::RemoveAssetVariable(const FName& InName)
// {
// const int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InName);
// if (VarIndex == INDEX_NONE)
// {
// return false;
// }
//
// FBlueprintEditorUtils::RemoveMemberVariable(this, InName);
// return true;
// }
//
// bool URigVMBlueprint::RenameAssetVariable(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 URigVMBlueprint::ChangeAssetVariableType(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(LogRigVMDeveloper, Warning, TEXT("TMap Variables are not supported."));
// return false;
// }
//
// Variable.bIsArray = RigVMTypeUtils::IsArrayType(CPPType);
// if (Variable.bIsArray)
// {
// CPPType = RigVMTypeUtils::BaseTypeFromArrayType(CPPType);
// }
//
// 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 = RigVMTypeUtils::FindObjectFromCPPTypeObjectPath<UScriptStruct>(CPPType))
// {
// Variable.TypeName = *RigVMTypeUtils::GetUniqueStructTypeName(ScriptStruct);
// Variable.TypeObject = ScriptStruct;
// Variable.Size = ScriptStruct->GetStructureSize();
// }
// else if (UEnum* Enum= RigVMTypeUtils::FindObjectFromCPPTypeObjectPath<UEnum>(CPPType))
// {
// Variable.TypeName = *RigVMTypeUtils::CPPTypeFromEnum(Enum);
// Variable.TypeObject = Enum;
// Variable.Size = static_cast<int32>(Enum->GetResourceSizeBytes(EResourceSizeMode::EstimatedTotal));
// }
//
// FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromExternalVariable(Variable);
// if (!PinType.PinCategory.IsValid())
// {
// return false;
// }
//
// ChangeAssetVariableType(InName, PinType);
//
// return true;
// }
FString URigVMBlueprint::GetVariableDefaultValue(const FName& InName, bool bFromDebuggedObject) const
{
FString DefaultValue;
UObject* ObjectContainer = bFromDebuggedObject ? GetObjectBeingDebugged() : GeneratedClass->GetDefaultObject();
if(ObjectContainer)
{
FProperty* TargetProperty = FindFProperty<FProperty>(GeneratedClass, InName);
if (TargetProperty)
{
const uint8* Container = (const uint8*)ObjectContainer;
FBlueprintEditorUtils::PropertyValueToString(TargetProperty, Container, DefaultValue, nullptr);
return DefaultValue;
}
}
return DefaultValue;
}
// bool URigVMBlueprint::ChangeAssetVariableType(const FName& InName, const FEdGraphPinType& InType)
// {
// FBlueprintEditorUtils::ChangeMemberVariableType(this, InName, InType);
// return true;
// }
FName URigVMBlueprint::AddMemberVariable(const FName& InName, const FString& InCPPType, bool bIsPublic, bool bIsReadOnly, FString InDefaultValue)
{
FRigVMExternalVariable Variable = RigVMTypeUtils::ExternalVariableFromCPPTypePath(InName, InCPPType, bIsPublic, bIsReadOnly);
FName Result = AddHostMemberVariableFromExternal(Variable, InDefaultValue);
if (!Result.IsNone())
{
#if WITH_RIGVMLEGACYEDITOR
FBPCompileRequest Request(this, EBlueprintCompileOptions::None, nullptr);
FBlueprintCompilationManager::CompileSynchronously(Request);
#else
// FRigVMBPCompileRequest Request(this, EBlueprintCompileOptions::None, nullptr);
// FRigVMBlueprintCompilationManager::CompileSynchronously(Request);
#endif
}
return Result;
}
bool URigVMBlueprint::RemoveMemberVariable(const FName& InName)
{
const int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InName);
if (VarIndex == INDEX_NONE)
{
return false;
}
FBlueprintEditorUtils::RemoveMemberVariable(this, InName);
return true;
}
bool URigVMBlueprint::BulkRemoveMemberVariables(const TArray<FName>& InNames)
{
for (const FName& Name : InNames)
{
const int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, Name);
if (VarIndex == INDEX_NONE)
{
return false;
}
}
FBlueprintEditorUtils::BulkRemoveMemberVariables(this, InNames);
return true;
}
bool URigVMBlueprint::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 URigVMBlueprint::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(LogRigVMDeveloper, Warning, TEXT("TMap Variables are not supported."));
return false;
}
Variable.bIsArray = RigVMTypeUtils::IsArrayType(CPPType);
if (Variable.bIsArray)
{
CPPType = RigVMTypeUtils::BaseTypeFromArrayType(CPPType);
}
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 = RigVMTypeUtils::FindObjectFromCPPTypeObjectPath<UScriptStruct>(CPPType))
{
Variable.TypeName = *RigVMTypeUtils::GetUniqueStructTypeName(ScriptStruct);
Variable.TypeObject = ScriptStruct;
Variable.Size = ScriptStruct->GetStructureSize();
}
else if (UEnum* Enum= RigVMTypeUtils::FindObjectFromCPPTypeObjectPath<UEnum>(CPPType))
{
Variable.TypeName = *RigVMTypeUtils::CPPTypeFromEnum(Enum);
Variable.TypeObject = Enum;
Variable.Size = static_cast<int32>(Enum->GetResourceSizeBytes(EResourceSizeMode::EstimatedTotal));
}
FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromExternalVariable(Variable);
if (!PinType.PinCategory.IsValid())
{
return false;
}
FBlueprintEditorUtils::ChangeMemberVariableType(this, InName, PinType);
return true;
}
bool URigVMBlueprint::ChangeMemberVariableType(const FName& InName, const FEdGraphPinType& InType)
{
int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(this, InName);
if (VarIndex == INDEX_NONE)
{
return false;
}
FBlueprintEditorUtils::ChangeMemberVariableType(this, InName, InType);
return true;
}
FName URigVMBlueprint::FindHostMemberVariableUniqueName(TSharedPtr<FKismetNameValidator> InNameValidator, const FString& InBaseName)
{
FString BaseName = InBaseName;
if (InNameValidator->IsValid(BaseName) == EValidatorResult::ContainsInvalidCharacters)
{
for (TCHAR& TestChar : BaseName)
{
for (TCHAR BadChar : UE_BLUEPRINT_INVALID_NAME_CHARACTERS)
{
if (TestChar == BadChar)
{
TestChar = TEXT('_');
break;
}
}
}
}
FString KismetName = BaseName;
int32 Suffix = 0;
while (InNameValidator->IsValid(KismetName) != EValidatorResult::Ok)
{
KismetName = FString::Printf(TEXT("%s_%d"), *BaseName, Suffix);
Suffix++;
}
return *KismetName;
}
int32 URigVMBlueprint::AddHostMemberVariable(URigVMBlueprint* InBlueprint, const FName& InVarName, FEdGraphPinType InVarType, bool bIsPublic, bool bIsReadOnly, FString InDefaultValue)
{
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"));
NewVar.DefaultValue = InDefaultValue;
return InBlueprint->NewVariables.Add(NewVar);
}
FName URigVMBlueprint::AddHostMemberVariableFromExternal(FRigVMExternalVariable InVariableToCreate, FString InDefaultValue)
{
FEdGraphPinType PinType = RigVMTypeUtils::PinTypeFromExternalVariable(InVariableToCreate);
if (!PinType.PinCategory.IsValid())
{
return NAME_None;
}
Modify();
TSharedPtr<FKismetNameValidator> NameValidator = MakeShareable(new FKismetNameValidator(this, NAME_None, nullptr));
FName VarName = FindHostMemberVariableUniqueName(NameValidator, InVariableToCreate.Name.ToString());
int32 VariableIndex = AddHostMemberVariable(this, VarName, PinType, InVariableToCreate.bIsPublic, InVariableToCreate.bIsReadOnly, InDefaultValue);
if (VariableIndex != INDEX_NONE)
{
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(this);
return VarName;
}
return NAME_None;
}
void URigVMBlueprint::OnPreVariableChange(UObject* InObject)
{
if (InObject != this)
{
return;
}
LastNewVariables = NewVariables;
}
void URigVMBlueprint::OnPostVariableChange(UBlueprint* InBlueprint)
{
if (InBlueprint != this)
{
return;
}
if (bUpdatingExternalVariables)
{
return;
}
TGuardValue<bool> UpdatingVariablesGuard(bUpdatingExternalVariables, true);
TArray<FBPVariableDescription> LocalLastNewVariables = LastNewVariables;
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 < LocalLastNewVariables.Num(); VarIndex++)
{
OldVariablesByGuid.Add(LocalLastNewVariables[VarIndex].VarGuid, VarIndex);
}
for (const FBPVariableDescription& OldVariable : LocalLastNewVariables)
{
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 = LocalLastNewVariables[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 URigVMBlueprint::GetTypeActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
#if WITH_EDITOR
GetEditorModule()->GetTypeActions(FRigVMAssetInterfacePtr(const_cast<URigVMBlueprint*>(this)), ActionRegistrar);
#endif
}
void URigVMBlueprint::GetInstanceActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC()
#if WITH_EDITOR
GetEditorModule()->GetInstanceActions(FRigVMAssetInterfacePtr(const_cast<URigVMBlueprint*>(this)), ActionRegistrar);
#endif
}
#endif
#undef LOCTEXT_NAMESPACE