// 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( 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(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 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(*GeneratedClass); return Result; } void URigVMBlueprint::PostSerialize(FArchive& Ar) { if(Ar.IsLoading()) { if(Model_DEPRECATED || FunctionLibrary_DEPRECATED) { TGuardValue 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 NotificationGuard(bSuspendAllNotifications, true); Result = Super::RegenerateClass(ClassToRegenerate, PreviousCDO); if (URigVMBlueprintGeneratedClass* Generated = Cast(Result)) { Generated->SupportedEventNames = SupportedEventNames; Generated->AssetVariant = AssetVariant; } } return Result; } TArray URigVMBlueprint::GetExternalVariables(bool bFallbackToBlueprint) const { TArray ExternalVariables; if (URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass()) { if (URigVMHost* CDO = Cast(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(RigClass->GetDefaultObject(bCreateIfNeeded))) { return CDO->GetVM(); } } return nullptr; } FRigVMExtendedExecuteContext* URigVMBlueprint::GetRigVMExtendedExecuteContext() { if (URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass()) { if (URigVMHost* CDO = Cast(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 URigVMBlueprint::GetArchetypeInstances(bool bIncludeCDO, bool bIncludeDerivedClasses) const { URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass(); TArray ArchetypeInstances; if (bIncludeCDO) { URigVMHost* CDO = Cast(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(RigClass->GetDefaultObject(false)); return CDO->GetDebugInfo(); } URigVMHost* URigVMBlueprint::CreateRigVMHostSuper(UObject* InOuter) { return NewObject(InOuter, GetRigVMHostClass()); } void URigVMBlueprint::MarkAssetAsStructurallyModified(bool bSkipDirtyAssetStatus) { const TEnumAsByte 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 Task) { FKismetDebugUtilities::ForeachPinWatch(this, Task); } TMap& URigVMBlueprint::GetUserDefinedStructGuidToPathName(bool bFromCDO) { if (bFromCDO) { URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass(); URigVMHost* CDO = Cast(RigClass->GetDefaultObject(true /* create if needed */)); if (CDO) { return CDO->UserDefinedStructGuidToPathName; } } return UserDefinedStructGuidToPathName; } TMap& URigVMBlueprint::GetUserDefinedEnumToPathName(bool bFromCDO) { if (bFromCDO) { URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass(); URigVMHost* CDO = Cast(RigClass->GetDefaultObject(true /* create if needed */)); if (CDO) { return CDO->UserDefinedEnumToPathName; } } return UserDefinedEnumToPathName; } TSet>& URigVMBlueprint::GetUserDefinedTypesInUse(bool bFromCDO) { if (bFromCDO) { URigVMBlueprintGeneratedClass* RigClass = GetRigVMBlueprintGeneratedClass(); URigVMHost* CDO = Cast(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& 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(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& 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(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(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(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& OutTags) const { PRAGMA_DISABLE_DEPRECATION_WARNINGS; UBlueprint::GetAssetRegistryTags(OutTags); PRAGMA_ENABLE_DEPRECATION_WARNINGS; } TArray URigVMBlueprint::GetAssetVariables() const { TArray 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 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(CPPType)) // { // Variable.TypeName = *RigVMTypeUtils::GetUniqueStructTypeName(ScriptStruct); // Variable.TypeObject = ScriptStruct; // Variable.Size = ScriptStruct->GetStructureSize(); // } // else if (UEnum* Enum= RigVMTypeUtils::FindObjectFromCPPTypeObjectPath(CPPType)) // { // Variable.TypeName = *RigVMTypeUtils::CPPTypeFromEnum(Enum); // Variable.TypeObject = Enum; // Variable.Size = static_cast(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(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& 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(CPPType)) { Variable.TypeName = *RigVMTypeUtils::GetUniqueStructTypeName(ScriptStruct); Variable.TypeObject = ScriptStruct; Variable.Size = ScriptStruct->GetStructureSize(); } else if (UEnum* Enum= RigVMTypeUtils::FindObjectFromCPPTypeObjectPath(CPPType)) { Variable.TypeName = *RigVMTypeUtils::CPPTypeFromEnum(Enum); Variable.TypeObject = Enum; Variable.Size = static_cast(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 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 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 UpdatingVariablesGuard(bUpdatingExternalVariables, true); TArray LocalLastNewVariables = LastNewVariables; TMap NewVariablesByGuid; for (int32 VarIndex = 0; VarIndex < NewVariables.Num(); VarIndex++) { NewVariablesByGuid.Add(NewVariables[VarIndex].VarGuid, VarIndex); } TMap 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(this)), ActionRegistrar); #endif } void URigVMBlueprint::GetInstanceActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const { DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC() #if WITH_EDITOR GetEditorModule()->GetInstanceActions(FRigVMAssetInterfacePtr(const_cast(this)), ActionRegistrar); #endif } #endif #undef LOCTEXT_NAMESPACE