创建Blueprint
核心方法
UBlueprint* FKismetEditorUtilities::CreateBlueprint(UClass* ParentClass, UObject* Outer, const FName NewBPName, EBlueprintType BlueprintType, TSubclassOf<UBlueprint> BlueprintClassType, TSubclassOf<UBlueprintGeneratedClass> BlueprintGeneratedClassType, FName CallingContext)
{
FSecondsCounterScope Timer(BlueprintCompileAndLoadTimerData);
check(FindObject<UBlueprint>(Outer, *NewBPName.ToString()) == NULL);
if ((BlueprintType == BPTYPE_Normal) && (ParentClass->HasAnyClassFlags(CLASS_Const)))
{
BlueprintType = BPTYPE_Const;
}
UBlueprint* NewBP = NewObject<UBlueprint>(Outer, *BlueprintClassType, NewBPName, RF_Public | RF_Standalone | RF_Transactional | RF_LoadCompleted);
NewBP->Status = BS_BeingCreated;
NewBP->BlueprintType = BlueprintType;
NewBP->ParentClass = ParentClass;
NewBP->BlueprintSystemVersion = UBlueprint::GetCurrentBlueprintSystemVersion();
NewBP->bIsNewlyCreated = true;
NewBP->bLegacyNeedToPurgeSkelRefs = false;
NewBP->GenerateNewGuid();
if (FBlueprintEditorUtils::SupportsConstructionScript(NewBP))
{
FName NewSkelClassName, NewGenClassName;
NewBP->GetBlueprintClassNames(NewGenClassName, NewSkelClassName);
UBlueprintGeneratedClass* NewClass = NewObject<UBlueprintGeneratedClass>(
NewBP->GetOutermost(), *BlueprintGeneratedClassType, NewGenClassName, RF_Public | RF_Transactional);
NewBP->GeneratedClass = NewClass;
NewClass->ClassGeneratedBy = NewBP;
NewClass->SetSuperStruct(ParentClass);
NewBP->SimpleConstructionScript = NewObject<USimpleConstructionScript>(NewClass);
NewBP->SimpleConstructionScript->SetFlags(RF_Transactional);
NewBP->LastEditedDocuments.Add(NewBP->SimpleConstructionScript);
UEdGraph* UCSGraph = FBlueprintEditorUtils::CreateNewGraph(NewBP, UEdGraphSchema_K2::FN_UserConstructionScript, UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
FBlueprintEditorUtils::AddFunctionGraph(NewBP, UCSGraph, false, AActor::StaticClass());
if( NewBP->ParentClass && NewBP->ParentClass->ClassGeneratedBy )
{
check( UCSGraph->Nodes.Num() > 0 );
UK2Node_FunctionEntry* UCSEntry = CastChecked<UK2Node_FunctionEntry>(UCSGraph->Nodes[0]);
FGraphNodeCreator<UK2Node_CallParentFunction> FunctionNodeCreator(*UCSGraph);
UK2Node_CallParentFunction* ParentFunctionNode = FunctionNodeCreator.CreateNode();
ParentFunctionNode->FunctionReference.SetExternalMember(UEdGraphSchema_K2::FN_UserConstructionScript, NewBP->ParentClass);
ParentFunctionNode->NodePosX = 200;
ParentFunctionNode->NodePosY = 0;
ParentFunctionNode->AllocateDefaultPins();
FunctionNodeCreator.Finalize();
UEdGraphPin* ExecPin = UCSEntry->FindPin(UEdGraphSchema_K2::PN_Then);
UEdGraphPin* SuperPin = ParentFunctionNode->FindPin(UEdGraphSchema_K2::PN_Execute);
ExecPin->MakeLinkTo(SuperPin);
}
NewBP->LastEditedDocuments.Add(UCSGraph);
UCSGraph->bAllowDeletion = false;
}
if (FBlueprintEditorUtils::DoesSupportEventGraphs(NewBP))
{
check(NewBP->UbergraphPages.Num() == 0);
CreateDefaultEventGraphs(NewBP);
}
if (UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(NewBP))
{
UAnimBlueprint* RootAnimBP = UAnimBlueprint::FindRootAnimBlueprint(AnimBP);
if (RootAnimBP == nullptr)
{
if(AnimBP->BlueprintType != BPTYPE_Interface)
{
UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(AnimBP, UEdGraphSchema_K2::GN_AnimGraph, UAnimationGraph::StaticClass(), UAnimationGraphSchema::StaticClass());
FBlueprintEditorUtils::AddDomainSpecificGraph(NewBP, NewGraph);
NewBP->LastEditedDocuments.Add(NewGraph);
NewGraph->bAllowDeletion = false;
}
}
else
{
AnimBP->TargetSkeleton = RootAnimBP->TargetSkeleton;
}
}
IKismetCompilerInterface& Compiler = FModuleManager::LoadModuleChecked<IKismetCompilerInterface>(KISMET_COMPILER_MODULENAME);
const EBlueprintCompileOptions CompileOptions =
EBlueprintCompileOptions::SkipGarbageCollection |
EBlueprintCompileOptions::SkipDefaultObjectValidation |
EBlueprintCompileOptions::SkipFiBSearchMetaUpdate;
FBlueprintCompilationManager::CompileSynchronously(
FBPCompileRequest(NewBP, CompileOptions, nullptr)
);
NewBP->bHasBeenRegenerated = true;
UBlueprintEditorSettings* Settings = GetMutableDefault<UBlueprintEditorSettings>();
if(Settings && Settings->bSpawnDefaultBlueprintNodes)
{
if(NewBP->UbergraphPages.Num() && FBlueprintEditorUtils::DoesSupportEventGraphs(NewBP))
{
UClass* WidgetClass = FindObject<UClass>(ANY_PACKAGE, TEXT("UserWidget"));
UClass* GameplayAbilityClass = FindObject<UClass>(ANY_PACKAGE, TEXT("GameplayAbility"));
TArray<FName> AutoSpawnedEventNames;
int32 NodePositionY = 0;
UClass* DefaultNodesClass = NewBP->GeneratedClass;
while ( DefaultNodesClass )
{
bool bFoundDefaultNodes = false;
for ( TMultiMap<void*, FDefaultEventNodeData>::TIterator DataIt(AutoGeneratedDefaultEventsMap); DataIt; ++DataIt )
{
FDefaultEventNodeData Data = DataIt.Value();
if ( DefaultNodesClass == Data.TargetClass )
{
bFoundDefaultNodes = true;
FKismetEditorUtilities::AddDefaultEventNode(NewBP, NewBP->UbergraphPages[0], Data.EventName, Data.TargetClass, NodePositionY);
}
}
if ( bFoundDefaultNodes )
{
break;
}
DefaultNodesClass = DefaultNodesClass->GetSuperClass();
}
}
for (TMultiMap<void*, FKismetEditorUtilities::FOnBlueprintCreatedData>::TIterator DataIt(OnBlueprintCreatedCallbacks); DataIt; ++DataIt)
{
FOnBlueprintCreatedData Data = DataIt.Value();
if (NewBP->GeneratedClass->IsChildOf(Data.TargetClass))
{
FKismetEditorUtilities::FOnBlueprintCreated BlueprintCreatedDelegate = Data.OnBlueprintCreated;
BlueprintCreatedDelegate.Execute(NewBP);
}
}
}
UBlueprintGeneratedClass* BlueprintGeneratedClass = CastChecked<UBlueprintGeneratedClass>(NewBP->GeneratedClass);
void* SparseDataPtr = BlueprintGeneratedClass->GetOrCreateSparseClassData();
BlueprintGeneratedClass->bIsSparseClassDataSerializable = SparseDataPtr != nullptr;
if (FEngineAnalytics::IsAvailable())
{
TArray<FAnalyticsEventAttribute> Attribs;
if (CallingContext != NAME_None)
{
Attribs.Add(FAnalyticsEventAttribute(FString("Context"), CallingContext.ToString()));
}
Attribs.Add(FAnalyticsEventAttribute(FString("ParentType"), ParentClass->ClassGeneratedBy == NULL ? FString("Native") : FString("Blueprint")));
if(IsTrackedBlueprintParent(ParentClass))
{
Attribs.Add(FAnalyticsEventAttribute(FString("ParentClass"), ParentClass->GetName()));
}
const UGeneralProjectSettings& ProjectSettings = *GetDefault<UGeneralProjectSettings>();
Attribs.Add(FAnalyticsEventAttribute(FString("ProjectId"), ProjectSettings.ProjectID.ToString()));
Attribs.Add(FAnalyticsEventAttribute(FString("BlueprintId"), NewBP->GetBlueprintGuid().ToString()));
FEngineAnalytics::GetProvider().RecordEvent(FString("Editor.Usage.BlueprintCreated"), Attribs);
}
return NewBP;
}
创建Blueprint
UBlueprint* UAnimStrategy::CreateAnimBlueprint(UClass* ParentClass, const FString PackagePath,
const FName FileName, const FString SkeletonPath)
{
const FString InnerPackagePath = PackagePath + FileName.ToString();
UPackage* OuterForAsset = CreatePackage(nullptr, *InnerPackagePath);
UClass* BlueprintClass = nullptr;
UClass* BlueprintGeneratedClass = nullptr;
KismetCompilerModule.GetBlueprintTypesForClass(AActor::StaticClass(), BlueprintClass,
BlueprintGeneratedClass);
UAnimBlueprint* NewBlueprint = CastChecked<UAnimBlueprint>(FKismetEditorUtilities::CreateBlueprint(
ParentClass, OuterForAsset, FileName, BPTYPE_Normal, UAnimBlueprint::StaticClass(),
UBlueprintGeneratedClass::StaticClass(), FName("GeneratingAnimBlueprintTest")));
return NewBlueprint;
}
创建AnimBlueprint
UAnimBlueprint* UAnimStrategy::CreateAnimBlueprint(UClass* ParentClass, const FString PackagePath,
const FName FileName, const FString SkeletonPath)
{
const FString InnerPackagePath = PackagePath + FileName.ToString();
UPackage* OuterForAsset = CreatePackage(nullptr, *InnerPackagePath);
UObject* SkeletonObject = LoadObject<UObject>(nullptr, *SkeletonPath);
UAnimBlueprint* NewBlueprint = CastChecked<UAnimBlueprint>(FKismetEditorUtilities::CreateBlueprint(
ParentClass, OuterForAsset, FileName, BPTYPE_Normal, UAnimBlueprint::StaticClass(),
UAnimBlueprintGeneratedClass::StaticClass(), FName("GeneratingAnimBlueprintTest")));
NewBlueprint->TargetSkeleton = Cast<USkeleton>(SkeletonObject);
return NewBlueprint;
}
将Blueprint保存到Content中
void UAnimStrategy::SaveAnimBlueprint(UAnimBlueprint* AnimBlueprint, UPackage* OuterForAsset)
{
FAssetRegistryModule::AssetCreated(AnimBlueprint);
OuterForAsset->SetDirtyFlag(true);
TArray<UPackage*> PackagesToSave;
PackagesToSave.Add(OuterForAsset);
FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, false, false);
}
编译Blueprint
void UAnimStrategy::CompileBlueprint(UBlueprint* Blueprint)
{
FCompilerResultsLog LogResults;
LogResults.SetSourcePath(Blueprint->GetPathName());
LogResults.BeginEvent(TEXT("Compile"));
const EBlueprintCompileOptions CompileOptions = EBlueprintCompileOptions::None;
FKismetEditorUtilities::CompileBlueprint(Blueprint, CompileOptions, &LogResults);
LogResults.EndEvent();
}