Files
MingSimulator/Plugins/Puerts/Source/PuertsEditor/Private/PEBlueprintAsset.cpp
T
starmen1265 ed21658256 从master分支拉取puerts,并拉取v8制品,修改puerts插件部分UE5_5以下兼容的宏代码。保证puerts编译通过。包括
CSharpParamDefaultValueMetas.cs和ubtplugin.csproj和declarationGenerator.cpp和PropertyTranslator.cpp对UserDefinedStruct.h的引用
2024-12-02 01:03:52 +08:00

1395 lines
54 KiB
C++

/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "PEBlueprintAsset.h"
#include "Modules/ModuleManager.h"
#include "KismetCompilerModule.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "AssetToolsModule.h"
#if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) || ENGINE_MAJOR_VERSION > 5
#include "AssetRegistry/AssetRegistryModule.h"
#else
#include "AssetRegistryModule.h"
#endif
#include "FileHelpers.h"
#include "Misc/PackageName.h"
#include "UObject/MetaData.h"
#include "CoreGlobals.h"
#include "K2Node_FunctionEntry.h"
#include "EdGraphSchema_K2_Actions.h"
#include "K2Node_Event.h"
#include "K2Node_CustomEvent.h"
#include "K2Node_FunctionResult.h"
#include "GameFramework/InputSettings.h"
#include "K2Node_InputAxisEvent.h"
#include "K2Node_InputAction.h"
#include "K2Node_CallFunction.h"
#include "K2Node_ComponentBoundEvent.h"
#include "ScopedTransaction.h"
#include "Kismet/KismetSystemLibrary.h"
#include "TypeScriptGeneratedClass.h"
#include "TypeScriptBlueprint.h"
#include "utility"
#include "PuertsModule.h"
#include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h"
#include "Kismet2/ComponentEditorUtils.h"
#include "Editor.h"
#include "HAL/PlatformFileManager.h"
#include "Framework/Application/SlateApplication.h"
#include "Misc/MessageDialog.h"
#define LOCTEXT_NAMESPACE "UPEBlueprintAsset"
DEFINE_LOG_CATEGORY_STATIC(PuertsEditorModule, Log, All);
static bool IsPlaying()
{
return GEditor && IPuertsModule::IsInPIEMode();
}
#define CanChangeCheckWithBoolRet() \
if (IsPlaying()) \
{ \
UE_LOG(PuertsEditorModule, Error, TEXT("change the layout of class[%s] in PIE mode is forbiden!"), \
*GeneratedClass->GetName()); \
NeedSave = false; \
return false; \
}
#define CanChangeCheck() \
if (IsPlaying()) \
{ \
UE_LOG(PuertsEditorModule, Error, TEXT("change the layout of class[%s] in PIE mode is forbiden!"), \
*GeneratedClass->GetName()); \
NeedSave = false; \
return; \
}
bool UPEBlueprintAsset::Existed(const FString& InName, const FString& InPath)
{
FString BPPath = FString(TEXT(TS_BLUEPRINT_PATH)) / InName + TEXT(".uasset");
if (BPPath[0] == TEXT('/') || BPPath[0] == TEXT('\\'))
{
BPPath = BPPath.Mid(1);
}
BPPath = FPaths::ProjectContentDir() / BPPath;
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
return PlatformFile.FileExists(*BPPath);
}
bool UPEBlueprintAsset::LoadOrCreate(
const FString& InName, const FString& InPath, UClass* ParentClass, int32 InSetFlags, int32 InClearFlags)
{
FString PackageName = FString(TEXT("/Game" TS_BLUEPRINT_PATH)) / InPath / InName;
// UE_LOG(LogTemp, Warning, TEXT("LoadOrCreate.PackageName: %s"), *PackageName);
Blueprint = LoadObject<UBlueprint>(nullptr, *PackageName, nullptr, LOAD_NoWarn | LOAD_NoRedirects);
if (Blueprint)
{
GeneratedClass = Blueprint->GeneratedClass;
if (auto TypeScriptGeneratedClass = Cast<UTypeScriptGeneratedClass>(GeneratedClass))
{
HasConstructor = TypeScriptGeneratedClass->HasConstructor;
}
Package = Cast<UPackage>(Blueprint->GetOuter());
if (Blueprint->ParentClass != ParentClass)
{
CanChangeCheckWithBoolRet();
Blueprint->ParentClass = ParentClass;
NeedSave = true;
}
else
{
NeedSave = false;
}
return true;
}
if (!ParentClass)
return false;
if (IsPlaying())
{
UE_LOG(PuertsEditorModule, Error, TEXT("create class[%s] in PIE mode is forbiden!"), *InName);
return false;
}
NeedSave = true;
UClass* BlueprintClass = UBlueprint::StaticClass();
UClass* BlueprintGeneratedClass = UTypeScriptGeneratedClass::StaticClass();
if (!ParentClass->IsChildOf(AActor::StaticClass()))
{
BlueprintClass = UTypeScriptBlueprint::StaticClass();
}
// UE_LOG(LogTemp, Warning, TEXT("BlueprintClass: %s"), *BlueprintClass->GetName());
// UE_LOG(LogTemp, Warning, TEXT("BlueprintGeneratedClass: %s"), *BlueprintGeneratedClass->GetName());
// FString Name;
// FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
// AssetToolsModule.Get().CreateUniqueAssetName(PackageName, TEXT(""), PackageName, Name);
// UE_LOG(LogTemp, Warning, TEXT("Name: %s, PackageName: %s, InName:%s, InPath:%s"), *Name, *PackageName, *InName, *InPath);
#if ENGINE_MINOR_VERSION < 26 && ENGINE_MAJOR_VERSION <= 4
Package = CreatePackage(NULL, *PackageName);
#else
Package = CreatePackage(*PackageName);
#endif
check(Package);
EBlueprintType BlueprintType =
ParentClass && ParentClass->IsChildOf(UBlueprintFunctionLibrary::StaticClass()) ? BPTYPE_FunctionLibrary : BPTYPE_Normal;
// Create and init a new Blueprint
Blueprint = FKismetEditorUtilities::CreateBlueprint(
ParentClass, Package, *InName, BlueprintType, BlueprintClass, BlueprintGeneratedClass, FName("PuertsAutoGen"));
if (Blueprint)
{
// Notify the asset registry
FAssetRegistryModule::AssetCreated(Blueprint);
// Mark the package dirty...
Package->MarkPackageDirty();
GeneratedClass = Blueprint->GeneratedClass;
return true;
}
else
{
return false;
}
}
bool UPEBlueprintAsset::LoadOrCreateWithMetaData(const FString& InName, const FString& InPath, UClass* InParentClass,
int32 InSetFlags, int32 InClearFlags, UPEClassMetaData* InMetaData)
{
if (!IsValid(InParentClass))
{ // the parent class should be valid
return false;
}
if (!LoadOrCreate(InName, InPath, InParentClass, InSetFlags, InClearFlags))
{ // create the class
return false;
}
if (IsValid(InMetaData))
{ // apply the meta data
NeedSave = InMetaData->Apply(GeneratedClass, Blueprint) || NeedSave;
if (NeedSave)
CanChangeCheckWithBoolRet();
}
return true;
}
bool IsImplementationDesiredAsFunction(UBlueprint* InBlueprint, const UFunction* OverrideFunc)
{
// If the original function was created in a parent blueprint, then prefer a BP function
if (OverrideFunc)
{
FName OverrideName = *OverrideFunc->GetName();
TSet<FName> GraphNames;
FBlueprintEditorUtils::GetAllGraphNames(InBlueprint, GraphNames);
for (const FName& Name : GraphNames)
{
if (Name == OverrideName)
{
return true;
}
}
}
// Otherwise, we would prefer an event
return false;
}
static FEdGraphPinType ToFEdGraphPinType(FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType)
{
if (InGraphPinType.PinSubCategoryObject && InGraphPinType.PinCategory == UEdGraphSchema_K2::PC_Object)
{
if (InGraphPinType.PinSubCategoryObject->IsA<UScriptStruct>())
{
InGraphPinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
}
else if (InGraphPinType.PinSubCategoryObject->IsA<UEnum>())
{
InGraphPinType.PinCategory = UEdGraphSchema_K2::PC_Byte;
}
else
{
InGraphPinType.PinCategory = UEdGraphSchema_K2::PC_Object;
}
}
FName InGraphSubCategory;
FName InPinValueSubCategory;
#if (ENGINE_MAJOR_VERSION >= 5)
if (InGraphPinType.PinCategory == UEdGraphSchema_K2::PC_Float)
{
InGraphPinType.PinCategory = UEdGraphSchema_K2::PC_Real;
InGraphSubCategory = UEdGraphSchema_K2::PC_Double;
}
if (InPinValueType.PinCategory == UEdGraphSchema_K2::PC_Float)
{
InPinValueType.PinCategory = UEdGraphSchema_K2::PC_Real;
InPinValueSubCategory = UEdGraphSchema_K2::PC_Double;
}
#endif
FEdGraphPinType PinType(InGraphPinType.PinCategory, InGraphSubCategory, InGraphPinType.PinSubCategoryObject,
(EPinContainerType) InGraphPinType.PinContainerType, InGraphPinType.bIsReference, FEdGraphTerminalType());
if (PinType.ContainerType == EPinContainerType::Map)
{
PinType.PinValueType.TerminalCategory = InPinValueType.PinCategory;
PinType.PinValueType.TerminalSubCategory = InPinValueSubCategory;
PinType.PinValueType.TerminalSubCategoryObject = InPinValueType.PinSubCategoryObject;
if (InPinValueType.PinSubCategoryObject && InPinValueType.PinCategory == UEdGraphSchema_K2::PC_Object)
{
if (InPinValueType.PinSubCategoryObject->IsA<UScriptStruct>())
{
PinType.PinValueType.TerminalCategory = UEdGraphSchema_K2::PC_Struct;
}
else if (InPinValueType.PinSubCategoryObject->IsA<UEnum>())
{
PinType.PinValueType.TerminalCategory = UEdGraphSchema_K2::PC_Byte;
}
else
{
PinType.PinValueType.TerminalCategory = UEdGraphSchema_K2::PC_Object;
}
}
}
return PinType;
}
void UPEBlueprintAsset::AddParameter(FName InParameterName, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType)
{
ParameterNames.Add(InParameterName);
ParameterIsIn.Add(InGraphPinType.bIn);
ParameterTypes.Add(ToFEdGraphPinType(InGraphPinType, InPinValueType));
}
void UPEBlueprintAsset::AddParameterWithMetaData(
FName InParameterName, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType, UPEParamMetaData* InMetaData)
{
ParameterNames.Add(InParameterName);
ParameterIsIn.Add(InGraphPinType.bIn);
FEdGraphPinType PinType = ToFEdGraphPinType(InGraphPinType, InPinValueType);
if (IsValid(InMetaData))
{
if (InMetaData->Apply(PinType))
{
// "Currently Parameter Type Don't Affect NeedSava In Add Parameter Process"
}
}
ParameterTypes.Add(PinType);
}
static TArray<UK2Node_EditablePinBase*> GatherAllResultNodes(UK2Node_EditablePinBase* TargetNode)
{
TArray<UK2Node_EditablePinBase*> Result;
if (UK2Node_FunctionResult* ResultNode = Cast<UK2Node_FunctionResult>(TargetNode))
{
for (auto& Node : ResultNode->GetAllResultNodes())
{
if (Node)
{
Result.Add(Node);
}
}
return Result;
}
if (TargetNode)
{
Result.Add(TargetNode);
}
return Result;
}
#if ENGINE_MINOR_VERSION <= 23 && ENGINE_MAJOR_VERSION < 5
UFunction* GetInterfaceFunction(UBlueprint* Blueprint, const FName FuncName)
{
UFunction* Function = nullptr;
// If that class is an interface class implemented by this function, then return true
for (const FBPInterfaceDescription& I : Blueprint->ImplementedInterfaces)
{
if (I.Interface)
{
Function = FindField<UFunction>(I.Interface, FuncName);
if (Function)
{
// found it, done
return Function;
}
}
}
// Check if it is in a native class or parent class
for (UClass* TempClass = Blueprint->ParentClass; (nullptr != TempClass) && (nullptr == Function);
TempClass = TempClass->GetSuperClass())
{
for (const FImplementedInterface& I : TempClass->Interfaces)
{
Function = FindField<UFunction>(I.Class, FuncName);
if (Function)
{
// found it, done
return Function;
}
}
}
return nullptr;
}
UClass* const GetOverrideFunctionClass(UBlueprint* Blueprint, const FName FuncName, UFunction** OutFunction)
{
if (!Blueprint->SkeletonGeneratedClass)
{
return nullptr;
}
UFunction* OverrideFunc = GetInterfaceFunction(Blueprint, FuncName);
if (OverrideFunc == nullptr)
{
OverrideFunc = FindField<UFunction>(Blueprint->SkeletonGeneratedClass, FuncName);
// search up the class hierarchy, we want to find the original declaration of the function to match
// FBlueprintEventNodeSpawner. Doing so ensures that we can find the existing node if there is one:
const UClass* Iter = Blueprint->SkeletonGeneratedClass->GetSuperClass();
while (Iter != nullptr && OverrideFunc == nullptr)
{
if (UFunction* F = Iter->FindFunctionByName(FuncName))
{
OverrideFunc = F;
}
else
{
break;
}
Iter = Iter->GetSuperClass();
}
}
if (OutFunction != nullptr)
{
*OutFunction = OverrideFunc;
}
return (OverrideFunc ? CastChecked<UClass>(OverrideFunc->GetOuter())->GetAuthoritativeClass() : nullptr);
}
#endif
void UPEBlueprintAsset::AddFunction(FName InName, bool IsVoid, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType,
int32 InSetFlags, int32 InClearFlags)
{
InSetFlags &= ~InClearFlags;
InSetFlags &= ~FUNC_Native;
const int32 NetMask = FUNC_Net | FUNC_NetMulticast | FUNC_NetServer | FUNC_NetClient | FUNC_NetReliable;
if (InSetFlags & NetMask)
{
InSetFlags |= FUNC_Net;
}
UClass* SuperClass = GeneratedClass->GetSuperClass();
UFunction* ParentFunction = SuperClass->FindFunctionByName(InName);
UFunction* Function = GeneratedClass->FindFunctionByName(InName, EIncludeSuperFlag::ExcludeSuper);
TArray<FName> AxisNames;
TArray<FName> ActionNames;
GetDefault<UInputSettings>()->GetAxisNames(AxisNames);
GetDefault<UInputSettings>()->GetActionNames(ActionNames);
UK2Node_EditablePinBase* FunctionEntryNode = nullptr;
bool IsCustomEvent = false;
// Create the function graph.
const bool bUserCreated = true;
if (ParentFunction)
{
// UE_LOG(LogTemp, Warning, TEXT("Override Function %s"), *ParentFunction->GetName());
// FBlueprintEditorUtils::AddFunctionGraph(Blueprint, FunctionGraph, bUserCreated, ParentFunction);
UFunction* OverrideFunc = nullptr;
#if ENGINE_MINOR_VERSION <= 23 && ENGINE_MAJOR_VERSION < 5
UClass* const OverrideFuncClass = GetOverrideFunctionClass(Blueprint, InName, &OverrideFunc);
#else
UClass* const OverrideFuncClass = FBlueprintEditorUtils::GetOverrideFunctionClass(Blueprint, InName, &OverrideFunc);
#endif
check(OverrideFunc);
UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(Blueprint);
if (UEdGraphSchema_K2::FunctionCanBePlacedAsEvent(OverrideFunc) &&
!IsImplementationDesiredAsFunction(Blueprint, OverrideFunc) && EventGraph)
{
// Add to event graph
FName EventName = OverrideFunc->GetFName();
UK2Node_Event* ExistingNode = FBlueprintEditorUtils::FindOverrideForFunction(Blueprint, OverrideFuncClass, EventName);
if (!ExistingNode && !Function)
{
ExistingNode = FBlueprintEditorUtils::FindOverrideForFunction(Blueprint, UObject::StaticClass(), EventName);
if (ExistingNode)
{
if (!ExistingNode->IsNodeEnabled())
{
CanChangeCheck();
ExistingNode->SetEnabledState(ENodeEnabledState::Enabled);
ExistingNode->NodeComment.Empty();
NeedSave = true;
}
}
else
{
CanChangeCheck();
UK2Node_Event* NewEventNode = FEdGraphSchemaAction_K2NewNode::SpawnNode<UK2Node_Event>(EventGraph,
EventGraph->GetGoodPlaceForNewNode(), EK2NewNodeFlags::SelectNewNode,
[EventName, OverrideFuncClass](UK2Node_Event* NewInstance)
{
NewInstance->EventReference.SetExternalMember(EventName, OverrideFuncClass);
NewInstance->bOverrideFunction = true;
});
NeedSave = true;
}
}
OverrideAdded.Add(InName);
}
else
{
if (FunctionAdded.Contains(InName))
return;
UEdGraph* const ExistingGraph = FindObject<UEdGraph>(Blueprint, *InName.ToString());
if (!ExistingGraph)
{
CanChangeCheck();
const FScopedTransaction Transaction(LOCTEXT("CreateOverrideFunctionGraph", "Create Override Function Graph"));
Blueprint->Modify();
// Implement the function graph
UEdGraph* const NewGraph = FBlueprintEditorUtils::CreateNewGraph(
Blueprint, InName, UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
FBlueprintEditorUtils::AddFunctionGraph(Blueprint, NewGraph, /*bIsUserCreated=*/false, OverrideFuncClass);
NewGraph->Modify();
NeedSave = true;
}
FunctionAdded.Add(InName);
}
ParameterNames.Empty();
ParameterIsIn.Empty();
ParameterTypes.Empty();
return;
}
else if (AxisNames.Contains(InName))
{
TArray<UK2Node_InputAxisEvent*> AllEvents;
// TODO: K2Node_InputTouchEvent,K2Node_InputVectorAxisEvent,K2Node_InputAxisKeyEvent,UK2Node_InputKeyEvent
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_InputAxisEvent>(Blueprint, AllEvents);
UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(Blueprint);
if (EventGraph && !AllEvents.FindByPredicate([&](UK2Node_InputAxisEvent* Node) { return Node->InputAxisName == InName; }))
{
CanChangeCheck();
// UE_LOG(LogTemp, Warning, TEXT("Add Axis: %s"), *InName.ToString());
FEdGraphSchemaAction_K2NewNode::SpawnNode<UK2Node_InputAxisEvent>(EventGraph, EventGraph->GetGoodPlaceForNewNode(),
EK2NewNodeFlags::SelectNewNode, [InName](UK2Node_InputAxisEvent* NewInstance) { NewInstance->Initialize(InName); });
NeedSave = true;
}
}
// Create Action node and PrintString node
// then Connection them.
// UK2Node_InputAction Node must have one connected node to create function "InpActEvt_%s_%s"
else if (ActionNames.Contains(InName))
{
TArray<UK2Node_InputAction*> AllEvents;
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_InputAction>(Blueprint, AllEvents);
UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(Blueprint);
if (EventGraph && !AllEvents.FindByPredicate([&](UK2Node_InputAction* Node) { return Node->InputActionName == InName; }))
{
CanChangeCheck();
UK2Node_InputAction* NewNode = FEdGraphSchemaAction_K2NewNode::SpawnNode<UK2Node_InputAction>(EventGraph,
EventGraph->GetGoodPlaceForNewNode(), EK2NewNodeFlags::SelectNewNode,
[InName](UK2Node_InputAction* NewInstance) { NewInstance->InputActionName = InName; });
// UK2Node_CallFunction
UK2Node_CallFunction* NewNode2 = FEdGraphSchemaAction_K2NewNode::SpawnNode<UK2Node_CallFunction>(EventGraph,
EventGraph->GetGoodPlaceForNewNode(), EK2NewNodeFlags::SelectNewNode,
[InName](UK2Node_CallFunction* NewInstance)
{ NewInstance->FunctionReference.SetExternalMember(FName("PrintString"), UKismetSystemLibrary::StaticClass()); });
EventGraph->GetSchema()->TryCreateConnection(NewNode->Pins[0], NewNode2->Pins[0]);
NeedSave = true;
}
}
else if (InSetFlags & FUNC_Net)
{
TArray<UK2Node_CustomEvent*> AllEvents;
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_CustomEvent>(Blueprint, AllEvents);
UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(Blueprint);
auto Iter = AllEvents.FindByPredicate([&](UK2Node_CustomEvent* Node) { return Node->CustomFunctionName == InName; });
if (EventGraph)
{
if (EventGraph && !Iter)
{
CanChangeCheck();
// 处理标签改变的情况
Blueprint->FunctionGraphs.RemoveAll([&](UEdGraph* Graph) { return Graph->GetFName() == InName; });
UEdGraph* ExistingGraph = FindObject<UEdGraph>(Blueprint, *(InName.ToString()));
if (ExistingGraph)
{
ExistingGraph->Rename(*FString::Printf(TEXT("%s%s"), *ExistingGraph->GetName(), TEXT("__Removed")), nullptr,
REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
}
UK2Node_CustomEvent* EventNode = FEdGraphSchemaAction_K2NewNode::SpawnNode<UK2Node_CustomEvent>(EventGraph,
EventGraph->GetGoodPlaceForNewNode(), EK2NewNodeFlags::SelectNewNode,
[InName](UK2Node_Event* NewInstance)
{
NewInstance->CustomFunctionName = InName;
NewInstance->bIsEditable = true;
});
FunctionEntryNode = EventNode;
NeedSave = true;
}
else
{
FunctionEntryNode = *Iter;
}
IsCustomEvent = true;
FunctionAdded.Add(InName);
}
}
else
{
if (FunctionAdded.Contains(InName))
return;
TArray<UEdGraph*> GraphList;
Blueprint->GetAllGraphs(GraphList);
UEdGraph** ExistedGraph = GraphList.FindByPredicate([&](UEdGraph* Graph) { return Graph->GetFName() == InName; });
UEdGraph* FunctionGraph;
if (ExistedGraph)
{
// UE_LOG(LogTemp, Warning, TEXT("FunctionGraph %s existed, delete it!"), *InName.ToString());
// FBlueprintEditorUtils::RemoveGraph(Blueprint, *ExistedGraph);
FunctionGraph = *ExistedGraph;
}
else
{
CanChangeCheck();
UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(Blueprint);
if (EventGraph)
{
EventGraph->Nodes.RemoveAll(
[&](UEdGraphNode* GraphNode)
{
UK2Node_CustomEvent* CustomEvent = Cast<UK2Node_CustomEvent>(GraphNode);
return CustomEvent && CustomEvent->CustomFunctionName == InName;
});
UEdGraph* ExistingGraph = FindObject<UEdGraph>(Blueprint, *(InName.ToString()));
if (ExistingGraph)
{
ExistingGraph->Rename(*FString::Printf(TEXT("%s%s"), *ExistingGraph->GetName(), TEXT("__Removed")), nullptr,
REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
}
}
FunctionGraph = FBlueprintEditorUtils::CreateNewGraph(Blueprint,
InName, // FBlueprintEditorUtils::FindUniqueKismetName(Blueprint, FuncName.ToString()),
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
FBlueprintEditorUtils::AddFunctionGraph<UClass>(Blueprint, FunctionGraph, bUserCreated, nullptr);
NeedSave = true;
}
// if (InFlags)
//{
// const UEdGraphSchema_K2* K2Schema = Cast<const UEdGraphSchema_K2>(FunctionGraph->GetSchema());
// K2Schema->AddExtraFunctionFlags(FunctionGraph, InFlags);
//}
TArray<UK2Node_FunctionEntry*> EntryNodes;
FunctionGraph->GetNodesOfClass(EntryNodes);
if (EntryNodes.Num() == 1)
{
FunctionEntryNode = EntryNodes[0];
}
FunctionAdded.Add(InName);
}
if (FunctionEntryNode)
{
if (UK2Node_FunctionEntry* TypedEntryNode = Cast<UK2Node_FunctionEntry>(FunctionEntryNode))
{
int32 ExtraFlags = TypedEntryNode->GetExtraFlags();
int32 NewExtraFlags = ((ExtraFlags & ~NetMask) | InSetFlags) & ~InClearFlags;
if (ExtraFlags != NewExtraFlags)
{
CanChangeCheck();
TypedEntryNode->SetExtraFlags(NewExtraFlags);
NeedSave = true;
}
}
else if (UK2Node_CustomEvent* CustomEventNode = Cast<UK2Node_CustomEvent>(FunctionEntryNode))
{
int32 NewFunctionFlags = ((CustomEventNode->FunctionFlags & ~NetMask) | InSetFlags) & ~InClearFlags;
if (CustomEventNode->FunctionFlags != NewFunctionFlags)
{
CanChangeCheck();
CustomEventNode->FunctionFlags = NewFunctionFlags;
NeedSave = true;
}
}
TArray<TSharedPtr<FUserPinInfo>> OldUserDefinedPins = FunctionEntryNode->UserDefinedPins;
TArray<TPair<FName, FEdGraphPinType>> InputParameterTypes;
TArray<TPair<FName, FEdGraphPinType>> OutputParameterTypes;
for (int i = 0; i < ParameterTypes.Num(); ++i)
{
FEdGraphPinType ParameterType = ParameterTypes[i];
if (ParameterType.bIsReference && !ParameterIsIn[i])
{
ParameterType.bIsReference = false;
OutputParameterTypes.Add(TPair<FName, FEdGraphPinType>(ParameterNames[i], ParameterType));
}
else
{
InputParameterTypes.Add(TPair<FName, FEdGraphPinType>(ParameterNames[i], ParameterType));
}
}
bool ParameterChanged = OldUserDefinedPins.Num() != InputParameterTypes.Num();
if (!ParameterChanged)
{
for (int i = 0; i < OldUserDefinedPins.Num(); i++)
{
if (OldUserDefinedPins[i]->PinType != InputParameterTypes[i].Value)
{
CanChangeCheck();
ParameterChanged = true;
}
}
}
if (ParameterChanged)
{
for (TSharedPtr<FUserPinInfo> pinInfo : OldUserDefinedPins)
{
FunctionEntryNode->RemoveUserDefinedPin(pinInfo);
}
for (int i = 0; i < InputParameterTypes.Num(); i++)
{
FunctionEntryNode->CreateUserDefinedPin(InputParameterTypes[i].Key, InputParameterTypes[i].Value, EGPD_Output);
}
}
auto TryAddOutput = [](TArray<UK2Node_EditablePinBase*> TargetNodes, FName PinName, const FEdGraphPinType& PinType) -> bool
{
bool Changed = false;
for (UK2Node_EditablePinBase* Node : TargetNodes)
{
TArray<TSharedPtr<FUserPinInfo>> OldUserDefinedReturnPins = Node->UserDefinedPins;
auto Old = Node->UserDefinedPins.FindByPredicate(
[&PinName](const TSharedPtr<FUserPinInfo>& UDPin) { return UDPin.IsValid() && (UDPin->PinName == PinName); });
if (!Old || (*Old)->PinType != PinType)
{
Changed = true;
if (Old)
{
Node->RemoveUserDefinedPinByName(PinName);
}
Node->CreateUserDefinedPin(PinName, PinType, EGPD_Input, false);
}
}
return Changed;
};
bool RetChanged = false;
const FName RetValName = FName(TEXT("ReturnValue"));
if (!IsVoid && !IsCustomEvent)
{
FEdGraphPinType PinType = ToFEdGraphPinType(InGraphPinType, InPinValueType);
auto FunctionResultNode = FBlueprintEditorUtils::FindOrCreateFunctionResultNode(FunctionEntryNode);
RetChanged = RetChanged || TryAddOutput(GatherAllResultNodes(FunctionResultNode), RetValName, PinType);
}
else if (IsCustomEvent || (IsVoid && OutputParameterTypes.Num() == 0))
{
UEdGraph* Graph = FunctionEntryNode->GetGraph();
TArray<UK2Node_FunctionResult*> ResultNodes;
if (Graph)
{
Graph->GetNodesOfClass(ResultNodes);
}
if (ResultNodes.Num() == 1)
{
auto FunctionResultNode = ResultNodes[0];
TArray<UK2Node_EditablePinBase*> TargetNodes = GatherAllResultNodes(FunctionResultNode);
for (UK2Node_EditablePinBase* Node : TargetNodes)
{
TArray<TSharedPtr<FUserPinInfo>> OldUserDefinedReturnPins = Node->UserDefinedPins;
RetChanged = RetChanged || (OldUserDefinedReturnPins.Num() != 0);
if (RetChanged)
{
CanChangeCheck();
Node->Modify();
for (TSharedPtr<FUserPinInfo> pinInfo : OldUserDefinedReturnPins)
{
Node->RemoveUserDefinedPin(pinInfo);
}
}
}
}
}
if (!IsCustomEvent && OutputParameterTypes.Num() > 0)
{
auto FunctionResultNode = FBlueprintEditorUtils::FindOrCreateFunctionResultNode(FunctionEntryNode);
TArray<UK2Node_EditablePinBase*> TargetNodes = GatherAllResultNodes(FunctionResultNode);
TSet<FName> OutputSet;
for (auto& Pair : OutputParameterTypes)
{
RetChanged = TryAddOutput(TargetNodes, Pair.Key, Pair.Value) || RetChanged;
if (RetChanged)
CanChangeCheck();
OutputSet.Add(Pair.Key);
}
OutputSet.Add(RetValName);
for (UK2Node_EditablePinBase* Node : TargetNodes)
{
for (TSharedPtr<FUserPinInfo> UserDefinedPin : Node->UserDefinedPins)
{
if (!OutputSet.Contains(UserDefinedPin->PinName))
{
CanChangeCheck();
RetChanged = true;
Node->RemoveUserDefinedPinByName(UserDefinedPin->PinName);
}
}
}
}
NeedSave = NeedSave || ParameterChanged || RetChanged;
}
ParameterNames.Empty();
ParameterIsIn.Empty();
ParameterTypes.Empty();
}
void UPEBlueprintAsset::AddFunctionWithMetaData(FName InName, bool IsVoid, FPEGraphPinType InGraphPinType,
FPEGraphTerminalType InPinValueType, int32 InSetFlags, int32 InClearFlags, UPEFunctionMetaData* InMetaData)
{
// a helper function used to find custom event by name
static const auto FindCustomEvent = [](UBlueprint* InBlueprint, FName InName) -> UK2Node_CustomEvent*
{
if (!IsValid(InBlueprint))
{
return nullptr;
}
TArray<UK2Node_CustomEvent*> Result;
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_CustomEvent>(InBlueprint, Result);
const auto pFindResult = Result.FindByPredicate(
[Name = InName](const UK2Node_CustomEvent* InEvent) -> bool { return InEvent->CustomFunctionName == Name; });
return pFindResult == nullptr ? nullptr : *pFindResult;
};
// a helper function used to find function entry of a function
static const auto FindFunctionEntry = [](UBlueprint* InBlueprint, FName InName) -> UK2Node_FunctionEntry*
{
if (!IsValid(InBlueprint))
{
return nullptr;
}
TArray<UEdGraph*> Graphs;
InBlueprint->GetAllGraphs(Graphs);
const auto pFunctionGraph =
Graphs.FindByPredicate([Name = InName](const UEdGraph* InGraph) { return InGraph->GetFName() == Name; });
if (pFunctionGraph == nullptr)
{
return nullptr;
}
TArray<UK2Node_FunctionEntry*> Entries;
(*pFunctionGraph)->GetNodesOfClass(Entries);
if (Entries.Num() == 1)
{
return Entries[0];
}
return nullptr;
};
/**
* @brief
* function body
*/
if (IsValid(InMetaData))
{
InSetFlags |= static_cast<int32>(InMetaData->FunctionFlags);
InClearFlags &= ~static_cast<int32>(InMetaData->FunctionFlags);
}
AddFunction(InName, IsVoid, InGraphPinType, InPinValueType, InSetFlags, InClearFlags);
if (!IsValid(InMetaData))
{
return;
}
// check if input function is custom event
if (UK2Node_CustomEvent* CustomEvent = FindCustomEvent(Blueprint, InName))
{
NeedSave = InMetaData->Apply(CustomEvent) || NeedSave;
}
else if (UK2Node_FunctionEntry* FunctionEntry = FindFunctionEntry(Blueprint, InName))
{
NeedSave = InMetaData->Apply(FunctionEntry) || NeedSave;
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Currently, Only Custom Event and Function Graph Support MetaData"));
}
if (NeedSave)
CanChangeCheck();
}
void UPEBlueprintAsset::ClearParameter()
{
ParameterNames.Empty();
ParameterIsIn.Empty();
ParameterTypes.Empty();
}
void UPEBlueprintAsset::RemoveComponent(FName ComponentName)
{
auto SCS_Node = Blueprint->SimpleConstructionScript->FindSCSNode(ComponentName);
if (SCS_Node)
{
// from Editor\Kismet\Private\SSCSEditor.cpp: SSCSEditor::RemoveComponentNode
FBlueprintEditorUtils::RemoveVariableNodes(Blueprint, SCS_Node->GetVariableName());
TArray<UK2Node_ComponentBoundEvent*> EventNodes;
FKismetEditorUtilities::FindAllBoundEventsForComponent(Blueprint, SCS_Node->GetVariableName(), EventNodes);
if (EventNodes.Num() > 0)
{
for (UK2Node_ComponentBoundEvent* Node : EventNodes)
{
UE_LOG(PuertsEditorModule, Error,
TEXT("The component that %s was bound to has been deleted! This node is no longer valid"), *Node->GetName());
}
}
USimpleConstructionScript* SCS = Blueprint->SimpleConstructionScript;
// Remove node from SCS tree
SCS->RemoveNodeAndPromoteChildren(SCS_Node);
// Clear the delegate
SCS_Node->SetOnNameChanged(FSCSNodeNameChanged());
// USceneComponent::GetDefaultSceneRootVariableName()
if (SCS_Node != SCS->GetDefaultSceneRootNode() && SCS_Node->ComponentTemplate != nullptr)
{
UE_LOG(LogTemp, Warning, TEXT("NOT DefaultSceneRoot: %s"), *ComponentName.ToString());
const FName TemplateName = SCS_Node->ComponentTemplate->GetFName();
const FString RemovedName = SCS_Node->GetVariableName().ToString() + TEXT("_REMOVED_") + FGuid::NewGuid().ToString();
SCS_Node->ComponentTemplate->Modify();
SCS_Node->ComponentTemplate->Rename(*RemovedName, /*NewOuter =*/nullptr, REN_DontCreateRedirectors);
TArray<UObject*> ArchetypeInstances;
auto DestroyArchetypeInstances = [&ArchetypeInstances, &RemovedName](UActorComponent* ComponentTemplate)
{
ComponentTemplate->GetArchetypeInstances(ArchetypeInstances);
for (UObject* ArchetypeInstance : ArchetypeInstances)
{
if (!ArchetypeInstance->HasAllFlags(RF_ArchetypeObject | RF_InheritableComponentTemplate))
{
CastChecked<UActorComponent>(ArchetypeInstance)->DestroyComponent();
ArchetypeInstance->Rename(*RemovedName, nullptr, REN_DontCreateRedirectors);
}
}
};
DestroyArchetypeInstances(SCS_Node->ComponentTemplate);
if (Blueprint)
{
// Children need to have their inherited component template instance of the component renamed out of the way as well
TArray<UClass*> ChildrenOfClass;
GetDerivedClasses(Blueprint->GeneratedClass, ChildrenOfClass);
for (UClass* ChildClass : ChildrenOfClass)
{
UBlueprintGeneratedClass* BPChildClass = CastChecked<UBlueprintGeneratedClass>(ChildClass);
if (UActorComponent* Component =
(UActorComponent*) FindObjectWithOuter(BPChildClass, UActorComponent::StaticClass(), TemplateName))
{
Component->Modify();
Component->Rename(*RemovedName, /*NewOuter =*/nullptr, REN_DontCreateRedirectors);
DestroyArchetypeInstances(Component);
}
}
}
}
}
}
void UPEBlueprintAsset::SetupAttachment(FName InComponentName, FName InParentComponentName)
{
if (Blueprint->SimpleConstructionScript)
{
auto SCS_Node = Blueprint->SimpleConstructionScript->FindSCSNode(InComponentName);
if (!SCS_Node)
{
UE_LOG(LogTemp, Error, TEXT("SetupAttachment: can not find %s"), *InComponentName.ToString());
return;
}
if (!SCS_Node->ComponentClass || !SCS_Node->ComponentClass->IsChildOf<UActorComponent>())
{
UE_LOG(LogTemp, Error, TEXT("SetupAttachment: %s not a UActorComponent"), *InComponentName.ToString());
return;
}
auto Parent_SCS_Node = Blueprint->SimpleConstructionScript->FindSCSNode(InParentComponentName);
if (!Parent_SCS_Node)
{
UE_LOG(LogTemp, Error, TEXT("SetupAttachment: can not find parent %s"), *InParentComponentName.ToString());
return;
}
if (!Parent_SCS_Node->ComponentClass || !Parent_SCS_Node->ComponentClass->IsChildOf<UActorComponent>())
{
UE_LOG(LogTemp, Error, TEXT("SetupAttachment: %s not a UActorComponent"), *InParentComponentName.ToString());
return;
}
if (!Parent_SCS_Node->ChildNodes.Contains(SCS_Node))
{
NeedSave = true;
Blueprint->SimpleConstructionScript->RemoveNode(SCS_Node);
USceneComponent* SceneComponentTemplate = Cast<USceneComponent>(SCS_Node->ComponentClass->GetDefaultObject());
if (SceneComponentTemplate)
{
// Save current state
SceneComponentTemplate->Modify();
// Reset the attach socket name
SceneComponentTemplate->SetupAttachment(SceneComponentTemplate->GetAttachParent(), NAME_None);
SCS_Node->Modify();
SCS_Node->AttachToName = NAME_None;
}
Parent_SCS_Node->AddChildNode(SCS_Node);
}
}
}
void UPEBlueprintAsset::SetupAttachments(TMap<FName, FName> InAttachments)
{
if (Blueprint->SimpleConstructionScript)
{
for (auto& KV : InAttachments)
{
SetupAttachment(KV.Key, KV.Value);
}
for (auto& Component : ComponentsAdded)
{
auto SCS_Node = Blueprint->SimpleConstructionScript->FindSCSNode(Component);
if (SCS_Node)
{
for (int32 ChildIdx = 0; ChildIdx < SCS_Node->ChildNodes.Num(); ChildIdx++)
{
USCS_Node* ChildNode = SCS_Node->ChildNodes[ChildIdx];
check(ChildNode != NULL);
if (!InAttachments.Contains(ChildNode->GetVariableName()) ||
InAttachments[ChildNode->GetVariableName()] != Component)
{
SCS_Node->RemoveChildNode(ChildNode);
Blueprint->SimpleConstructionScript->AddNode(ChildNode);
SCS_Node->Modify();
NeedSave = true;
}
}
}
}
}
}
void UPEBlueprintAsset::AddMemberVariable(FName NewVarName, FPEGraphPinType InGraphPinType, FPEGraphTerminalType InPinValueType,
int32 InLFlags, int32 InHFlags, int32 InLifetimeCondition)
{
uint64 InFlags = (uint64) InHFlags << 32 | InLFlags;
FEdGraphPinType PinType = ToFEdGraphPinType(InGraphPinType, InPinValueType);
if (PinType.ContainerType == EPinContainerType::None)
{
if (auto ComponentClass = Cast<UClass>(PinType.PinSubCategoryObject))
{
if (Blueprint->GeneratedClass->IsChildOf<AActor>() && Blueprint->SimpleConstructionScript &&
PinType.PinCategory == UEdGraphSchema_K2::PC_Object &&
(ComponentClass == UActorComponent::StaticClass() || ComponentClass->IsChildOf<UActorComponent>()))
{
auto SCSNode = Blueprint->SimpleConstructionScript->FindSCSNode(NewVarName);
if (!SCSNode || SCSNode->ComponentClass != ComponentClass)
{
if (SCSNode)
{
RemoveComponent(NewVarName);
}
USCS_Node* NewSCSNode = Blueprint->SimpleConstructionScript->CreateNode(ComponentClass, NewVarName);
Blueprint->SimpleConstructionScript->AddNode(NewSCSNode);
NeedSave = true;
}
ComponentsAdded.Add(NewVarName);
return;
}
}
}
int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(Blueprint, NewVarName);
if (VarIndex == INDEX_NONE)
{
CanChangeCheck();
if (NewVarName == NAME_None)
{
FString Message = FString::Printf(TEXT("VariableName is None, unable to add variable"));
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message));
}
else if (FBlueprintEditorUtils::AddMemberVariable(Blueprint, NewVarName, PinType))
{
NeedSave = true;
}
else
{
FString Message = FString::Printf(
TEXT("Failed to add variable: %s. Please check if the parent class already has a variable with the same name."),
*NewVarName.ToString());
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message));
}
}
else
{
FBPVariableDescription& Variable = Blueprint->NewVariables[VarIndex];
if (Variable.VarType != PinType)
{
CanChangeCheck();
FBlueprintEditorUtils::ChangeMemberVariableType(Blueprint, NewVarName, PinType);
NeedSave = true;
}
// else
//{
// UE_LOG(LogTemp, Error, TEXT("do not changed %s"), *NewVarName.ToString());
//}
}
VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(Blueprint, NewVarName);
if (VarIndex != INDEX_NONE)
{
FBPVariableDescription& Variable = Blueprint->NewVariables[VarIndex];
const uint64 NetMask = CPF_Net | CPF_RepNotify;
uint64 NetFlags = InFlags & NetMask;
if ((Variable.PropertyFlags & NetMask) != NetFlags)
{
CanChangeCheck();
Variable.PropertyFlags &= ~NetMask;
Variable.PropertyFlags |= NetFlags;
if (Variable.PropertyFlags & CPF_RepNotify)
{
FString NewFuncNameStr = FString::Printf(TEXT("OnRep_%s"), *NewVarName.ToString());
FName NewFuncName = FName(*NewFuncNameStr);
UEdGraph* FuncGraph = FindObject<UEdGraph>(Blueprint, *NewFuncNameStr);
if (!FuncGraph)
{
FuncGraph = FBlueprintEditorUtils::CreateNewGraph(
Blueprint, NewFuncName, UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
FBlueprintEditorUtils::AddFunctionGraph<UClass>(Blueprint, FuncGraph, false, NULL);
}
FunctionAdded.Add(NewFuncName);
Blueprint->NewVariables[VarIndex].RepNotifyFunc = NewFuncName;
}
NeedSave = true;
}
if (InLifetimeCondition < COND_Max && Variable.ReplicationCondition != InLifetimeCondition)
{
CanChangeCheck();
Variable.ReplicationCondition = (ELifetimeCondition) InLifetimeCondition;
NeedSave = true;
}
// The following code recalculates the final flags.
// Variables added to the blueprint via FBlueprintEditorUtils::AddMemberVariable come with some default flags.
InFlags |= CPF_Edit | CPF_BlueprintVisible | CPF_DisableEditOnInstance;
if (Blueprint->NewVariables[VarIndex].VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate)
{
InFlags |= CPF_BlueprintAssignable | CPF_BlueprintCallable;
}
else if ((Blueprint->NewVariables[VarIndex].VarType.PinCategory == UEdGraphSchema_K2::PC_Object) ||
(Blueprint->NewVariables[VarIndex].VarType.PinCategory == UEdGraphSchema_K2::PC_Interface))
{
check(Blueprint->NewVariables[VarIndex].VarType.PinSubCategoryObject.IsValid());
const UClass* ClassObject = Cast<UClass>(Blueprint->NewVariables[VarIndex].VarType.PinSubCategoryObject.Get());
check(ClassObject != nullptr);
if (ClassObject->IsChildOf(AActor::StaticClass()))
{
InFlags |= CPF_DisableEditOnTemplate;
}
}
if (Variable.PropertyFlags != InFlags)
{
CanChangeCheck();
Blueprint->NewVariables[VarIndex].PropertyFlags = InFlags;
NeedSave = true;
}
}
MemberVariableAdded.Add(NewVarName);
}
void UPEBlueprintAsset::AddMemberVariableWithMetaData(FName InNewVarName, FPEGraphPinType InGraphPinType,
FPEGraphTerminalType InPinValueType, int32 InLFlags, int32 InHFLags, int32 InLifetimeCondition, UPEPropertyMetaData* InMetaData)
{
if (IsValid(InMetaData))
{ // handle the conflict here
EPropertyFlags InputFlags = static_cast<EPropertyFlags>((static_cast<uint64>(InHFLags) << 32) + InLFlags);
InputFlags |= InMetaData->PropertyFlags;
InLFlags = (static_cast<uint64>(InputFlags) & 0xffffffff);
InHFLags = (static_cast<uint64>(InputFlags) >> 32);
}
AddMemberVariable(InNewVarName, InGraphPinType, InPinValueType, InLFlags, InHFLags, InLifetimeCondition);
int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(Blueprint, InNewVarName);
if (VarIndex != INDEX_NONE && VarIndex != VariableIndexInTS)
{
if (Blueprint->NewVariables.IsValidIndex(VariableIndexInTS))
{
Blueprint->NewVariables.Swap(VarIndex, VariableIndexInTS);
VarIndex = VariableIndexInTS;
NeedSave = true;
}
else
{
UE_LOG(PuertsEditorModule, Error,
TEXT("The added variables have been deleted elsewhere, making it impossible to correctly adjust the variable "
"order."))
}
}
if (VarIndex != INDEX_NONE)
{
++VariableIndexInTS;
}
if (VarIndex == INDEX_NONE)
{
return;
}
if (!IsValid(InMetaData))
{
if (!InMetaData && Blueprint->NewVariables[VarIndex].MetaDataArray.Num() > 0)
{
NeedSave = true;
Blueprint->NewVariables[VarIndex].MetaDataArray.Empty();
}
return;
}
// currently the replicated behaviour is different from cpp
NeedSave = InMetaData->Apply(Blueprint->NewVariables[VarIndex]) || NeedSave;
if (NeedSave)
CanChangeCheck();
}
void UPEBlueprintAsset::RemoveNotExistedComponent()
{
if (IsPlaying())
{
return;
}
if (Blueprint && Blueprint->GeneratedClass && Blueprint->GeneratedClass->IsChildOf<AActor>())
{
ComponentsAdded.Add(TEXT("DefaultSceneRoot"));
}
if (Blueprint && Blueprint->SimpleConstructionScript)
{
TArray<FName> ToDelete;
for (int32 i = 0; i < Blueprint->SimpleConstructionScript->GetAllNodes().Num(); i++)
{
if (!ComponentsAdded.Contains(Blueprint->SimpleConstructionScript->GetAllNodes()[i]->GetVariableName()))
{
ToDelete.Add(Blueprint->SimpleConstructionScript->GetAllNodes()[i]->GetVariableName());
}
}
for (auto Name : ToDelete)
{
NeedSave = true;
RemoveComponent(Name);
}
}
// ComponentsAdded.Empty();
}
void UPEBlueprintAsset::RemoveNotExistedMemberVariable()
{
if (IsPlaying())
{
return;
}
if (Blueprint)
{
TArray<FName> ToDelete;
for (int32 i = 0; i < Blueprint->NewVariables.Num(); i++)
{
if (!MemberVariableAdded.Contains(Blueprint->NewVariables[i].VarName))
{
ToDelete.Add(Blueprint->NewVariables[i].VarName);
}
}
for (auto Name : ToDelete)
{
NeedSave = true;
FBlueprintEditorUtils::RemoveMemberVariable(Blueprint, Name);
}
}
MemberVariableAdded.Empty();
}
void UPEBlueprintAsset::RemoveNotExistedFunction()
{
if (IsPlaying())
{
return;
}
if (Blueprint)
{
if (FBlueprintEditorUtils::SupportsConstructionScript(Blueprint) && Blueprint->SimpleConstructionScript)
{
if (UEdGraph* ExistingUCS = FBlueprintEditorUtils::FindUserConstructionScript(Blueprint))
{
ExistingUCS->bAllowDeletion = false;
}
else
{
UEdGraph* UCSGraph = FBlueprintEditorUtils::CreateNewGraph(Blueprint, UEdGraphSchema_K2::FN_UserConstructionScript,
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
FBlueprintEditorUtils::AddFunctionGraph(Blueprint, UCSGraph, /*bIsUserCreated=*/false, AActor::StaticClass());
UCSGraph->bAllowDeletion = false;
NeedSave = true;
}
FunctionAdded.Add(UEdGraphSchema_K2::FN_UserConstructionScript);
}
auto RemovedFunction =
Blueprint->FunctionGraphs.RemoveAll([&](UEdGraph* Graph) { return !FunctionAdded.Contains(Graph->GetFName()); });
NeedSave = NeedSave || (RemovedFunction > 0);
UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(Blueprint);
if (EventGraph)
{
auto RemovedCustomEvent = EventGraph->Nodes.RemoveAll(
[&](UEdGraphNode* GraphNode)
{
UK2Node_CustomEvent* CustomEvent = Cast<UK2Node_CustomEvent>(GraphNode);
return CustomEvent && !FunctionAdded.Contains(CustomEvent->CustomFunctionName);
});
NeedSave = NeedSave || (RemovedCustomEvent > 0);
auto RemoveOverrideEvent = EventGraph->Nodes.RemoveAll(
[&](UEdGraphNode* GraphNode)
{
UK2Node_Event* Event = Cast<UK2Node_Event>(GraphNode);
return Event && Event->bOverrideFunction && !OverrideAdded.Contains(Event->EventReference.GetMemberName());
});
NeedSave = NeedSave || (RemoveOverrideEvent > 0);
}
}
}
void UPEBlueprintAsset::Save()
{
auto TypeScriptGeneratedClass = Cast<UTypeScriptGeneratedClass>(GeneratedClass);
if (Blueprint && TypeScriptGeneratedClass)
{
NeedSave = NeedSave || (TypeScriptGeneratedClass->HasConstructor != HasConstructor);
if (NeedSave)
CanChangeCheck();
TypeScriptGeneratedClass->HasConstructor = HasConstructor;
if (NeedSave)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
FKismetEditorUtilities::CompileBlueprint(Blueprint);
for (TFieldIterator<UFunction> FuncIt(TypeScriptGeneratedClass, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
{
auto Function = *FuncIt;
Function->FunctionFlags &= ~FUNC_Native;
auto FunctionFName = Function->GetFName();
FString FunctionName = Function->GetName();
static FString AxisPrefix(TEXT("InpAxisEvt_"));
if (FunctionName.StartsWith(AxisPrefix))
{
auto FunctionNameWithoutPrefix = FunctionName.Mid(AxisPrefix.Len());
int32 SubPos;
if (FunctionNameWithoutPrefix.FindChar('_', SubPos))
{
FunctionName = FunctionNameWithoutPrefix.Mid(0, SubPos);
}
}
static FString ActionPrefix(TEXT("InpActEvt_"));
if (FunctionName.StartsWith(ActionPrefix))
{
auto FunctionNameWithoutPrefix = FunctionName.Mid(ActionPrefix.Len());
int32 SubPos;
if (FunctionNameWithoutPrefix.FindChar('_', SubPos))
{
FunctionName = FunctionNameWithoutPrefix.Mid(0, SubPos);
}
}
if (FunctionAdded.Contains(*FunctionName))
{
TypeScriptGeneratedClass->FunctionToRedirect.Add(FunctionFName);
}
}
TArray<UPackage*> PackagesToSave;
PackagesToSave.Add(Package);
FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, false, false);
}
}
FunctionAdded.Empty();
}