void UAnimGraphNode_SkeletalControlBase::GetMenuEntries(FGraphContextMenuBuilder& ContextMenuBuilder) const { UAnimGraphNode_Base* TemplateNode = NewObject<UAnimGraphNode_Base>(GetTransientPackage(), GetClass()); FString Category = TemplateNode->GetNodeCategory(); FText MenuDesc = GetControllerDescription(); FString Tooltip = GetControllerDescription().ToString(); FString Keywords = TemplateNode->GetKeywords(); TSharedPtr<FEdGraphSchemaAction_K2NewNode> NodeAction = FK2ActionMenuBuilder::AddNewNodeAction(ContextMenuBuilder, Category, MenuDesc, Tooltip, 0, Keywords); NodeAction->NodeTemplate = TemplateNode; }
TSharedPtr<FEdGraphSchemaAction_K2NewNode> UAnimGraphNode_Base::CreateDefaultMenuEntry(FGraphContextMenuBuilder& ContextMenuBuilder) const { UAnimGraphNode_Base* TemplateNode = NewObject<UAnimGraphNode_Base>(GetTransientPackage(), GetClass()); FString Category = TemplateNode->GetNodeCategory(); FText MenuDesc = TemplateNode->GetNodeTitle(ENodeTitleType::ListView); FString Tooltip = TemplateNode->GetTooltipText().ToString(); FString Keywords = TemplateNode->GetKeywords(); TSharedPtr<FEdGraphSchemaAction_K2NewNode> NodeAction = FK2ActionMenuBuilder::AddNewNodeAction(ContextMenuBuilder, Category, MenuDesc, Tooltip, 0, Keywords); NodeAction->NodeTemplate = TemplateNode; return NodeAction; }
void UEditorParentPlayerListObj::InitialiseFromBlueprint(UAnimBlueprint* Blueprint) { AnimBlueprint = Blueprint; Overrides.Empty(); TArray<UBlueprint*> BlueprintHierarchy; Blueprint->GetBlueprintHierarchyFromClass(Blueprint->GetAnimBlueprintGeneratedClass(), BlueprintHierarchy); // Search from 1 as 0 is this class and we're looking for it's parents for(int32 BPIdx = 1 ; BPIdx < BlueprintHierarchy.Num() ; ++BPIdx) { UBlueprint* CurrBP = BlueprintHierarchy[BPIdx]; TArray<UEdGraph*> Graphs; CurrBP->GetAllGraphs(Graphs); for(UEdGraph* Graph : Graphs) { for(UEdGraphNode* Node : Graph->Nodes) { UAnimGraphNode_Base* AnimNode = Cast<UAnimGraphNode_Base>(Node); if(AnimNode && AnimNode->GetAnimationAsset()) { FAnimParentNodeAssetOverride& Override = AddOverridableNode(AnimNode); // Check the blueprint for saved overrides FAnimParentNodeAssetOverride* SavedOverride = AnimBlueprint->GetAssetOverrideForNode(Override.ParentNodeGuid); if(SavedOverride) { Override.NewAsset = SavedOverride->NewAsset; } } } } } }
void UEditorParentPlayerListObj::ApplyOverrideToBlueprint(FAnimParentNodeAssetOverride& Override) { FAnimParentNodeAssetOverride* ExistingOverride = AnimBlueprint->ParentAssetOverrides.FindByPredicate([Override](const FAnimParentNodeAssetOverride& Other) { return Other.ParentNodeGuid == Override.ParentNodeGuid; }); UAnimBlueprintGeneratedClass* GenClass = AnimBlueprint->GetAnimBlueprintGeneratedClass(); FScopedTransaction Transaction(NSLOCTEXT("AnimOverrideEditorObj", "ApplyToBlueprintTransaction", "Apply an override to a blueprint.")); AnimBlueprint->Modify(); if(ExistingOverride) { UAnimGraphNode_Base* ExistingNode = GetVisualNodeFromGuid(ExistingOverride->ParentNodeGuid); check(ExistingNode); FAnimParentNodeAssetOverride* ParentOverride = AnimBlueprint->GetAssetOverrideForNode(Override.ParentNodeGuid, true); if((ParentOverride && Override.NewAsset == ParentOverride->NewAsset) || Override.NewAsset == ExistingNode->GetAnimationAsset()) { // If the asset is the same as a parent, or failing that same as the root; remove it FAnimParentNodeAssetOverride OverrideToRemove = *ExistingOverride; AnimBlueprint->ParentAssetOverrides.Remove(OverrideToRemove); } else { // Otherwise just update the override ExistingOverride->NewAsset = Override.NewAsset; } } else { UAnimGraphNode_Base* GraphNode = GetVisualNodeFromGuid(Override.ParentNodeGuid); Override.ParentNodeGuid = GraphNode->NodeGuid; // Can't find the override so add it to the blueprint. AnimBlueprint->ParentAssetOverrides.Add(Override); } AnimBlueprint->NotifyOverrideChange(Override); FBlueprintEditorUtils::MarkBlueprintAsModified(AnimBlueprint); }
void UK2Node_TransitionRuleGetter::GetStateSpecificAnimTransitionSchemaMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar, const UAnimBlueprint* AnimBlueprint, UAnimStateNode* StateNode) const { // Offer options from the source state // Sequence player positions ETransitionGetter::Type SequenceSpecificGetters[] = { ETransitionGetter::AnimationAsset_GetCurrentTime, ETransitionGetter::AnimationAsset_GetLength, ETransitionGetter::AnimationAsset_GetCurrentTimeFraction, ETransitionGetter::AnimationAsset_GetTimeFromEnd, ETransitionGetter::AnimationAsset_GetTimeFromEndFraction }; // Using the State Machine's graph, find all asset players nodes TArray<UK2Node*> AssetPlayers; StateNode->BoundGraph->GetNodesOfClassEx<UAnimGraphNode_Base, UK2Node>(/*out*/ AssetPlayers); for (int32 TypeIndex = 0; TypeIndex < ARRAY_COUNT(SequenceSpecificGetters); ++TypeIndex) { for (auto NodeIt = AssetPlayers.CreateConstIterator(); NodeIt; ++NodeIt) { UAnimGraphNode_Base* AnimNode = CastChecked<UAnimGraphNode_Base>(*NodeIt); if (AnimNode->DoesSupportTimeForTransitionGetter()) { UAnimationAsset * AnimAsset = AnimNode->GetAnimationAsset(); if (AnimAsset) { auto UiSpecOverride = [](const FBlueprintActionContext& /*Context*/, const IBlueprintNodeBinder::FBindingSet& Bindings, FBlueprintActionUiSpec* UiSpecOut, FString AssetName, TEnumAsByte<ETransitionGetter::Type> InGetterType) { UiSpecOut->Category = LOCTEXT("AssetPlayer", "Asset Player"); FFormatNamedArguments Args; Args.Add(TEXT("NodeName"), UK2Node_TransitionRuleGetter::GetFriendlyName(InGetterType)); Args.Add(TEXT("AssetName"), FText::FromString(AssetName)); FText Title = FText::Format(LOCTEXT("TransitionFor", "{NodeName} for '{AssetName}'"), Args); UiSpecOut->MenuName = Title; }; auto PostSpawnSetupLambda = [](UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, UAnimGraphNode_Base* InAssociatedAnimAssetPlayerNode, TEnumAsByte<ETransitionGetter::Type> InGetterType) { UK2Node_TransitionRuleGetter* NewNodeTyped = CastChecked<UK2Node_TransitionRuleGetter>(NewNode); NewNodeTyped->AssociatedAnimAssetPlayerNode = InAssociatedAnimAssetPlayerNode; NewNodeTyped->GetterType = InGetterType; }; // Prepare the node spawner UAnimGraphNode_Base* AssociatedAnimNode = AnimNode; const FString AssetName = AnimAsset->GetName(); TEnumAsByte<ETransitionGetter::Type> TransitionGetterType = SequenceSpecificGetters[TypeIndex]; UBlueprintNodeSpawner* Spawner = UBlueprintNodeSpawner::Create( UK2Node_TransitionRuleGetter::StaticClass(), nullptr, UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(PostSpawnSetupLambda, AssociatedAnimNode, TransitionGetterType) ); Spawner->DynamicUiSignatureGetter = UBlueprintNodeSpawner::FUiSpecOverrideDelegate::CreateStatic(UiSpecOverride, AssetName, TransitionGetterType); ActionRegistrar.AddBlueprintAction( AnimBlueprint, Spawner ); } } } } }
void UAnimationTransitionSchema::GetSourceStateActions(FGraphContextMenuBuilder& ContextMenuBuilder) const { if ((ContextMenuBuilder.FromPin == NULL) || ((ContextMenuBuilder.FromPin->Direction == EGPD_Input) && (ContextMenuBuilder.FromPin->PinType.PinCategory == PC_Float))) { // Find the source state associated with this transition UAnimBlueprint* Blueprint = CastChecked<UAnimBlueprint>(FBlueprintEditorUtils::FindBlueprintForGraph(ContextMenuBuilder.CurrentGraph)); if (UAnimBlueprintGeneratedClass* AnimBlueprintClass = Blueprint->GetAnimBlueprintSkeletonClass()) { if (UAnimStateTransitionNode* TransNode = GetTransitionNodeFromGraph(AnimBlueprintClass->GetAnimBlueprintDebugData(), ContextMenuBuilder.CurrentGraph)) { if (UAnimStateNode* SourceStateNode = Cast<UAnimStateNode>(TransNode->GetPreviousState())) { // Offer options from the source state // Sequence player positions ETransitionGetter::Type SequenceSpecificGetters[] = { ETransitionGetter::AnimationAsset_GetCurrentTime, ETransitionGetter::AnimationAsset_GetLength, ETransitionGetter::AnimationAsset_GetCurrentTimeFraction, ETransitionGetter::AnimationAsset_GetTimeFromEnd, ETransitionGetter::AnimationAsset_GetTimeFromEndFraction }; TArray<UK2Node*> AssetPlayers; SourceStateNode->BoundGraph->GetNodesOfClassEx<UAnimGraphNode_Base, UK2Node>(/*out*/ AssetPlayers); const FString Category_AssetPlayer(TEXT("Asset Player")); for (int32 TypeIndex = 0; TypeIndex < ARRAY_COUNT(SequenceSpecificGetters); ++TypeIndex) { for (auto NodeIt = AssetPlayers.CreateConstIterator(); NodeIt; ++NodeIt) { UAnimGraphNode_Base* AnimNode = CastChecked<UAnimGraphNode_Base>(*NodeIt); if (AnimNode->DoesSupportTimeForTransitionGetter()) { UK2Node_TransitionRuleGetter* NodeTemplate = ContextMenuBuilder.CreateTemplateNode<UK2Node_TransitionRuleGetter>(); FString AssetName; UAnimationAsset * AnimAsset = AnimNode->GetAnimationAsset(); if (AnimAsset) { NodeTemplate->AssociatedAnimAssetPlayerNode = AnimNode; AssetName = AnimAsset->GetName(); } NodeTemplate->GetterType = SequenceSpecificGetters[TypeIndex]; FFormatNamedArguments Args; Args.Add(TEXT("NodeName"), UK2Node_TransitionRuleGetter::GetFriendlyName(NodeTemplate->GetterType)); Args.Add(TEXT("AssetName"), FText::FromString(AssetName)); FText Title = FText::Format(LOCTEXT("TransitionFor", "{NodeName} for '{AssetName}'"), Args); TSharedPtr<FEdGraphSchemaAction_K2NewNode> Action = FK2ActionMenuBuilder::AddNewNodeAction(ContextMenuBuilder, Category_AssetPlayer, Title, NodeTemplate->GetTooltipText().ToString(), 0, NodeTemplate->GetKeywords()); Action->NodeTemplate = NodeTemplate; } } } // Non-sequence specific ones ETransitionGetter::Type NonSpecificGetters[] = { ETransitionGetter::CurrentTransitionDuration, ETransitionGetter::CurrentState_ElapsedTime, ETransitionGetter::CurrentState_GetBlendWeight }; for (int32 TypeIndex = 0; TypeIndex < ARRAY_COUNT(NonSpecificGetters); ++TypeIndex) { FString Category_Transition(TEXT("Transition")); UK2Node_TransitionRuleGetter* NodeTemplate = ContextMenuBuilder.CreateTemplateNode<UK2Node_TransitionRuleGetter>(); NodeTemplate->GetterType = NonSpecificGetters[TypeIndex]; FText Title = UK2Node_TransitionRuleGetter::GetFriendlyName(NodeTemplate->GetterType); TSharedPtr<FEdGraphSchemaAction_K2NewNode> Action = FK2ActionMenuBuilder::AddNewNodeAction(ContextMenuBuilder, Category_Transition, Title, NodeTemplate->GetTooltipText().ToString(), 0, NodeTemplate->GetKeywords()); Action->NodeTemplate = NodeTemplate; } } } } } }