//------------------------------------------------------------------------------ static void BlueprintActionDatabaseImpl::AddBlueprintGraphActions(UBlueprint const* const Blueprint, FActionList& ActionListOut) { using namespace FBlueprintNodeSpawnerFactory; // for MakeMacroNodeSpawner() for (auto GraphIt = Blueprint->MacroGraphs.CreateConstIterator(); GraphIt; ++GraphIt) { ActionListOut.Add(MakeMacroNodeSpawner(*GraphIt)); } // local variables for (auto GraphIt = Blueprint->FunctionGraphs.CreateConstIterator(); GraphIt; ++GraphIt) { UEdGraph* FunctionGraph = (*GraphIt); TArray<UK2Node_FunctionEntry*> GraphEntryNodes; FunctionGraph->GetNodesOfClass<UK2Node_FunctionEntry>(GraphEntryNodes); for (UK2Node_FunctionEntry* FunctionEntry : GraphEntryNodes) { for (FBPVariableDescription const& LocalVar : FunctionEntry->LocalVariables) { UBlueprintNodeSpawner* GetVarSpawner = UBlueprintVariableNodeSpawner::Create(UK2Node_VariableGet::StaticClass(), FunctionGraph, LocalVar); ActionListOut.Add(GetVarSpawner); UBlueprintNodeSpawner* SetVarSpawner = UBlueprintVariableNodeSpawner::Create(UK2Node_VariableSet::StaticClass(), FunctionGraph, LocalVar); ActionListOut.Add(SetVarSpawner); } } } }
//------------------------------------------------------------------------------ static void BlueprintActionDatabaseImpl::AddClassCastActions(UClass* Class, FActionList& ActionListOut) { Class = Class->GetAuthoritativeClass(); check(Class); UEdGraphSchema_K2 const* K2Schema = GetDefault<UEdGraphSchema_K2>(); bool bIsCastPermitted = UEdGraphSchema_K2::IsAllowableBlueprintVariableType(Class); if (bIsCastPermitted) { auto CustomizeCastNodeLambda = [](UEdGraphNode* NewNode, bool bIsTemplateNode, UClass* TargetType) { UK2Node_DynamicCast* CastNode = CastChecked<UK2Node_DynamicCast>(NewNode); CastNode->TargetType = TargetType; }; UBlueprintNodeSpawner* CastObjNodeSpawner = UBlueprintNodeSpawner::Create<UK2Node_DynamicCast>(); CastObjNodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(CustomizeCastNodeLambda, Class); ActionListOut.Add(CastObjNodeSpawner); UBlueprintNodeSpawner* CastClassNodeSpawner = UBlueprintNodeSpawner::Create<UK2Node_ClassDynamicCast>(); CastClassNodeSpawner->CustomizeNodeDelegate = CastObjNodeSpawner->CustomizeNodeDelegate; ActionListOut.Add(CastClassNodeSpawner); } }
//------------------------------------------------------------------------------ void FBlueprintActionDatabase::ClearAssetActions(UObject* const AssetObject) { FActionList* ActionList = ActionRegistry.Find(AssetObject); bool const bHasEntry = (ActionList != nullptr); if (bHasEntry) { for (UBlueprintNodeSpawner* Action : *ActionList) { // because some asserts expect everything to be cleaned up in a // single GC pass, we can't wait for the GC'd Action to release its // template node from the cache Action->ClearCachedTemplateNode(); } ActionRegistry.Remove(AssetObject); } if (UBlueprint* BlueprintAsset = Cast<UBlueprint>(AssetObject)) { BlueprintAsset->OnChanged().RemoveAll(this); BlueprintAsset->OnCompiled().RemoveAll(this); } if (bHasEntry && (ActionList->Num() > 0) && !BlueprintActionDatabaseImpl::bIsInitializing) { EntryRemovedDelegate.Broadcast(AssetObject); } }
//------------------------------------------------------------------------------ static void BlueprintActionDatabaseImpl::AddClassPropertyActions(UClass const* const Class, FActionList& ActionListOut) { using namespace FBlueprintNodeSpawnerFactory; // for MakeDelegateNodeSpawner() bool const bIsComponent = Class->IsChildOf<UActorComponent>(); bool const bIsActorClass = Class->IsChildOf<AActor>(); // loop over all the properties in the specified class; exclude-super because // we can always get the super properties by looking up that class separateHavely for (TFieldIterator<UProperty> PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt) { UProperty* Property = *PropertyIt; if (!IsPropertyBlueprintVisible(Property)) { continue; } bool const bIsDelegate = Property->IsA(UMulticastDelegateProperty::StaticClass()); if (bIsDelegate) { UMulticastDelegateProperty* DelegateProperty = CastChecked<UMulticastDelegateProperty>(Property); if (DelegateProperty->HasAnyPropertyFlags(CPF_BlueprintAssignable)) { UBlueprintNodeSpawner* AddSpawner = UBlueprintDelegateNodeSpawner::Create(UK2Node_AddDelegate::StaticClass(), DelegateProperty); ActionListOut.Add(AddSpawner); UBlueprintNodeSpawner* AssignSpawner = MakeAssignDelegateNodeSpawner(DelegateProperty); ActionListOut.Add(AssignSpawner); } if (DelegateProperty->HasAnyPropertyFlags(CPF_BlueprintCallable)) { UBlueprintNodeSpawner* CallSpawner = UBlueprintDelegateNodeSpawner::Create(UK2Node_CallDelegate::StaticClass(), DelegateProperty); ActionListOut.Add(CallSpawner); } UBlueprintNodeSpawner* RemoveSpawner = UBlueprintDelegateNodeSpawner::Create(UK2Node_RemoveDelegate::StaticClass(), DelegateProperty); ActionListOut.Add(RemoveSpawner); UBlueprintNodeSpawner* ClearSpawner = UBlueprintDelegateNodeSpawner::Create(UK2Node_ClearDelegate::StaticClass(), DelegateProperty); ActionListOut.Add(ClearSpawner); if (bIsComponent) { ActionListOut.Add(MakeComponentBoundEventSpawner(DelegateProperty)); } else if (bIsActorClass) { ActionListOut.Add(MakeActorBoundEventSpawner(DelegateProperty)); } } else { UBlueprintVariableNodeSpawner* GetterSpawner = UBlueprintVariableNodeSpawner::Create(UK2Node_VariableGet::StaticClass(), Property); ActionListOut.Add(GetterSpawner); UBlueprintVariableNodeSpawner* SetterSpawner = UBlueprintVariableNodeSpawner::Create(UK2Node_VariableSet::StaticClass(), Property); ActionListOut.Add(SetterSpawner); } } }
//------------------------------------------------------------------------------ static void BlueprintActionDatabaseImpl::AddClassFunctionActions(UClass const* const Class, FActionList& ActionListOut) { using namespace FBlueprintNodeSpawnerFactory; // for MakeMessageNodeSpawner() check(Class != nullptr); // loop over all the functions in the specified class; exclude-super because // we can always get the super functions by looking up that class separately for (TFieldIterator<UFunction> FunctionIt(Class, EFieldIteratorFlags::ExcludeSuper); FunctionIt; ++FunctionIt) { UFunction* Function = *FunctionIt; bool const bIsInheritedFunction = BlueprintActionDatabaseImpl::IsInheritedBlueprintFunction(Function); if (bIsInheritedFunction) { // inherited functions will be captured when the parent class is ran // through this function (no need to duplicate) continue; } bool const bIsBpInterfaceFunc = BlueprintActionDatabaseImpl::IsBlueprintInterfaceFunction(Function); if (UEdGraphSchema_K2::FunctionCanBePlacedAsEvent(Function) && !bIsBpInterfaceFunc) { if (UBlueprintEventNodeSpawner* NodeSpawner = UBlueprintEventNodeSpawner::Create(Function)) { ActionListOut.Add(NodeSpawner); } } if (UEdGraphSchema_K2::CanUserKismetCallFunction(Function)) { // @TODO: if this is a Blueprint, and this function is from a // Blueprint "implemented interface", then we don't need to // include it (the function is accounted for in from the // interface class). UBlueprintFunctionNodeSpawner* FuncSpawner = UBlueprintFunctionNodeSpawner::Create(Function); ActionListOut.Add(FuncSpawner); if (FKismetEditorUtilities::IsClassABlueprintInterface(Class)) { FuncSpawner->DefaultMenuSignature.MenuName = FText::Format(LOCTEXT("InterfaceCallMenuName", "{0} (Interface Call)"), FuncSpawner->DefaultMenuSignature.MenuName); ActionListOut.Add(MakeMessageNodeSpawner(Function)); } } } }
//------------------------------------------------------------------------------ void FBlueprintActionDatabase::ClearUnloadedAssetActions(FName ObjectPath) { // Check if the asset can be found in the unloaded action registry, if it can, we need to remove it if(TArray<UBlueprintNodeSpawner*>* UnloadedActionList = UnloadedActionRegistry.Find(ObjectPath)) { for(UBlueprintNodeSpawner* NodeSpawner : *UnloadedActionList) { FActionList* ActionList = ActionRegistry.Find(NodeSpawner->NodeClass); // Remove the NodeSpawner from the main registry, it will be replaced with the loaded version of the action ActionList->Remove(NodeSpawner); } // Remove the asset's path from the unloaded registry, it is no longer needed UnloadedActionRegistry.Remove(ObjectPath); } }
void FLatentActionManager::TickLatentActionForObject(float DeltaTime, FActionList& ObjectActionList, UObject* InObject) { typedef TPair<int32, FPendingLatentAction*> FActionListPair; TArray<FActionListPair, TInlineAllocator<4>> ItemsToRemove; FLatentResponse Response(DeltaTime); for (TMultiMap<int32, FPendingLatentAction*>::TConstIterator It(ObjectActionList); It; ++It) { FPendingLatentAction* Action = It.Value(); Response.bRemoveAction = false; Action->UpdateOperation(Response); if (Response.bRemoveAction) { new (ItemsToRemove) FActionListPair(TPairInitializer<int32, FPendingLatentAction*>(It.Key(), Action)); } } // Remove any items that were deleted for (int32 i = 0; i < ItemsToRemove.Num(); ++i) { const FActionListPair& ItemPair = ItemsToRemove[i]; const int32 ItemIndex = ItemPair.Key; FPendingLatentAction* DyingAction = ItemPair.Value; ObjectActionList.Remove(ItemIndex, DyingAction); delete DyingAction; } // Trigger any pending execution links for (int32 i = 0; i < Response.LinksToExecute.Num(); ++i) { FLatentResponse::FExecutionInfo& LinkInfo = Response.LinksToExecute[i]; if (LinkInfo.LinkID != INDEX_NONE) { if (UObject* CallbackTarget = LinkInfo.CallbackTarget.Get()) { check(CallbackTarget == InObject); if (UFunction* ExecutionFunction = CallbackTarget->FindFunction(LinkInfo.ExecutionFunction)) { CallbackTarget->ProcessEvent(ExecutionFunction, &(LinkInfo.LinkID)); } else { UE_LOG(LogScript, Warning, TEXT("FLatentActionManager::ProcessLatentActions: Could not find latent action resume point named '%s' on '%s' called by '%s'"), *LinkInfo.ExecutionFunction.ToString(), *(CallbackTarget->GetPathName()), *(InObject->GetPathName())); } } else { UE_LOG(LogScript, Warning, TEXT("FLatentActionManager::ProcessLatentActions: CallbackTarget is None.")); } } } }
//------------------------------------------------------------------------------ static void BlueprintActionDatabaseImpl::AddSkeletonActions(const USkeleton& Skeleton, FActionList& ActionListOut) { for (int32 I = 0; I < Skeleton.AnimationNotifies.Num(); ++I) { FName NotifyName = Skeleton.AnimationNotifies[I]; FString Label = NotifyName.ToString(); FString SignatureName = FString::Printf(TEXT("AnimNotify_%s"), *Label); ActionListOut.Add(FBlueprintNodeSpawnerFactory::MakeAnimOwnedEventSpawner(FName(*SignatureName), FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::AnimNotify))); } }
//------------------------------------------------------------------------------ static void BlueprintActionDatabaseImpl::AddAnimBlueprintGraphActions(UAnimBlueprint const* AnimBlueprint, FActionList& ActionListOut) { if (UAnimBlueprintGeneratedClass* GeneratedClass = AnimBlueprint->GetAnimBlueprintGeneratedClass()) { for (int32 NotifyIdx = 0; NotifyIdx < GeneratedClass->AnimNotifies.Num(); NotifyIdx++) { FName NotifyName = GeneratedClass->AnimNotifies[NotifyIdx].NotifyName; if (NotifyName != NAME_None) { FString Label = NotifyName.ToString(); FString SignatureName = FString::Printf(TEXT("AnimNotify_%s"), *Label); ActionListOut.Add(FBlueprintNodeSpawnerFactory::MakeAnimOwnedEventSpawner(FName(*SignatureName), FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::AnimNotify))); } } } }