diff --git a/Source/ComboInput/Private/Components/ComboManagerComponent.cpp b/Source/ComboInput/Private/Components/ComboManagerComponent.cpp index 56644f0..51ded3c 100644 --- a/Source/ComboInput/Private/Components/ComboManagerComponent.cpp +++ b/Source/ComboInput/Private/Components/ComboManagerComponent.cpp @@ -52,10 +52,11 @@ void UComboManagerComponent::ActivateComboInput(const UComboInputAsset *Input) /********** END DEBUG **********/ // If we received an offset input, perform the offset here and then leave. - if (Input == this->OffsetInput) + if (Input == this->OffsetMap.ComboInput) { this->ActiveNode = this->PreviousNode; this->GetWorld()->GetTimerManager().ClearTimer(this->FinishTransitionTimer); + this->BroadcastDelegates(this->OffsetMap.ComboAction, EComboActionTriggerEvent::Activated); UE_LOG(LogComboManagerComponent, Verbose, TEXT("Combo has been offset by %s"), *Input->ComboInputName.ToString()); return; } @@ -69,12 +70,7 @@ void UComboManagerComponent::ActivateComboInput(const UComboInputAsset *Input) if (ActionData.ComboAction) { this->BeginNodeTransition(ActionData.NextNode); - - for (const FComboActionHandlerDynamicSignature &Binding : this->ComboActionEventBindings) - { - Binding.Execute(/*EComboActionTriggerEvent::Activated*/); - } - + this->BroadcastDelegates(ActionData.ComboAction, EComboActionTriggerEvent::Activated); UE_LOG(LogComboManagerComponent, Verbose, TEXT("%s activated"), *ActionData.ComboAction->ActionName.ToString()); } } @@ -108,3 +104,14 @@ void UComboManagerComponent::FinishTransition() { this->PreviousNode = this->ActiveNode; } + + +void UComboManagerComponent::BroadcastDelegates(const UComboAction *ComboAction, const EComboActionTriggerEvent &TriggerEvent) +{ + const FComboDelegateKey Key(ComboAction, TriggerEvent); + if (const FComboActionHandlerDynamicSignature *Binding = this->ComboActionEventBindings.Find(Key.Key)) + { + Binding->Execute(ComboAction, TriggerEvent); + } + this->OnComboAction.Broadcast(ComboAction, (TriggerEvent == EComboActionTriggerEvent::Activated) ? true : false); +} diff --git a/Source/ComboInput/Private/Events/ComboActionDelegateBinding.cpp b/Source/ComboInput/Private/Events/ComboActionDelegateBinding.cpp index 0021cf1..5a1a257 100644 --- a/Source/ComboInput/Private/Events/ComboActionDelegateBinding.cpp +++ b/Source/ComboInput/Private/Events/ComboActionDelegateBinding.cpp @@ -26,11 +26,7 @@ void UComboActionDelegateBinding::BindDynamicDelegates(UObject *InInstance) cons { for (const FBlueprintComboActionBinding &Binding : this->ComboActionDelegateBindings) { - // Get the function we want to bind - if (UFunction *FunctionToBind = InInstance->GetClass()->FindFunctionByName(Binding.FunctionNameToBind)) - { - ComboManager->BindAction(InInstance, Binding.FunctionNameToBind); - } + ComboManager->BindAction(PlayerController, Binding.FunctionNameToBind, Binding.ComboAction, Binding.TriggerEvent); } } } diff --git a/Source/ComboInput/Private/Events/K2Node_ComboAction.cpp b/Source/ComboInput/Private/Events/K2Node_ComboAction.cpp index b2b3414..427db22 100644 --- a/Source/ComboInput/Private/Events/K2Node_ComboAction.cpp +++ b/Source/ComboInput/Private/Events/K2Node_ComboAction.cpp @@ -26,48 +26,17 @@ #define LOCTEXT_NAMESPACE "K2Node_ComboAction" +#define COMBO_ACTION_ACTIVATED_PIN_NAME TEXT("Activated") +#define COMBO_ACTION_RELEASED_PIN_NAME TEXT("Released") +#define COMBO_ACTION_OBJECT_PIN_NAME TEXT("ComboAction") -namespace UE::Input -{ - static bool bComboActionShouldWarnOnUnsupportedInputPin = false; - static FAutoConsoleVariableRef CVarShouldWarnOnUnsupportedInputPin( - TEXT("ComboAction.bp.bComboActionShouldWarnOnUnsupportedInputPin"), - bComboActionShouldWarnOnUnsupportedInputPin, - TEXT("Should the Combo Action event node throw a warning if an \"Unsupported\" pin has a connection?"), - ECVF_Default); -} - -UK2Node_ComboAction::UK2Node_ComboAction(const FObjectInitializer &ObjectInitializer) - : Super(ObjectInitializer) -{ -} - -void ForEachEventPinName(TFunctionRef PinLambda) -{ - UEnum *EventEnum = StaticEnum(); - for (int32 i = 0; i < EventEnum->NumEnums() - 1; ++i) - { - if (!EventEnum->HasMetaData(TEXT("Hidden"), i)) - { - PinLambda(EComboActionTriggerEvent(EventEnum->GetValueByIndex(i)), *EventEnum->GetNameStringByIndex(i)); - } - } -} void UK2Node_ComboAction::AllocateDefaultPins() { - this->PreloadObject((UObject*)this->ComboAction); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, COMBO_ACTION_ACTIVATED_PIN_NAME); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, COMBO_ACTION_RELEASED_PIN_NAME); + CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, UComboAction::StaticClass(), COMBO_ACTION_OBJECT_PIN_NAME); - ForEachEventPinName([this](EComboActionTriggerEvent Event, FName PinName) - { - static const UEnum *EventEnum = StaticEnum(); - - UEdGraphPin *NewPin = CreatePin(EEdGraphPinDirection::EGPD_Output, UEdGraphSchema_K2::PC_Exec, PinName); - NewPin->PinToolTip = EventEnum->GetToolTipTextByIndex(EventEnum->GetIndexByValue(static_cast(Event))).ToString(); - }); - - this->AdvancedPinDisplay = ENodeAdvancedPins::NoPins; - Super::AllocateDefaultPins(); } @@ -83,7 +52,6 @@ FName UK2Node_ComboAction::GetActionName() const FText UK2Node_ComboAction::GetNodeTitle(ENodeTitleType::Type TitleType) const { - // TODO: Is Using InputAction->GetFName okay here? Full Asset path would be better for disambiguation. if (TitleType == ENodeTitleType::MenuTitle) { return FText::FromName(this->GetActionName()); @@ -106,23 +74,18 @@ FText UK2Node_ComboAction::GetTooltipText() const if (CachedTooltip.IsOutOfDate(this)) { // FText::Format() is slow, so we cache this to save on performance - FString ActionPath = this->ComboAction ? this->ComboAction->GetFullName() : TEXT(""); - CachedTooltip.SetCachedText( - FText::Format( - LOCTEXT("ComboAction_Tooltip", "Event for when '{0}' triggers.\n\nNOTE: This is not guaranteed to fire every frame, only when the Action is triggered and the current Input Mode includes 'Game'."), - FText::FromString(ActionPath)), - this); + CachedTooltip.SetCachedText(FText::Format(NSLOCTEXT("K2Node", "ComboAction_Tooltip", "Event for when the combo action {0} is pressed or released."), FText::FromName(this->ComboAction->GetFName())), this); } return CachedTooltip; } -FSlateIcon UK2Node_ComboAction::GetIconAndTint(FLinearColor& OutColor) const +FSlateIcon UK2Node_ComboAction::GetIconAndTint(FLinearColor &OutColor) const { static FSlateIcon Icon(FAppStyle::GetAppStyleSetName(), "GraphEditor.Event_16x"); return Icon; } -bool UK2Node_ComboAction::IsCompatibleWithGraph(UEdGraph const* Graph) const +bool UK2Node_ComboAction::IsCompatibleWithGraph(UEdGraph const *Graph) const { // This node expands into event nodes and must be placed in a Ubergraph EGraphType const GraphType = Graph->GetSchema()->GetGraphType(Graph); @@ -130,9 +93,9 @@ bool UK2Node_ComboAction::IsCompatibleWithGraph(UEdGraph const* Graph) const if (bIsCompatible) { - UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(Graph); + UBlueprint *Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(Graph); - UEdGraphSchema_K2 const* K2Schema = Cast(Graph->GetSchema()); + UEdGraphSchema_K2 const *K2Schema = Cast(Graph->GetSchema()); bool const bIsConstructionScript = (K2Schema != nullptr) ? UEdGraphSchema_K2::IsConstructionScript(Graph) : false; bIsCompatible = (Blueprint != nullptr) && Blueprint->SupportsInputEvents() && !bIsConstructionScript && Super::IsCompatibleWithGraph(Graph); @@ -140,9 +103,9 @@ bool UK2Node_ComboAction::IsCompatibleWithGraph(UEdGraph const* Graph) const return bIsCompatible; } -UObject*UK2Node_ComboAction::GetJumpTargetForDoubleClick() const +UObject *UK2Node_ComboAction::GetJumpTargetForDoubleClick() const { - return const_cast(Cast(this->ComboAction)); + return const_cast(Cast(this->ComboAction)); } void UK2Node_ComboAction::JumpToDefinition() const @@ -165,79 +128,101 @@ void UK2Node_ComboAction::ExpandNode(FKismetCompilerContext &CompilerContext, UE { Super::ExpandNode(CompilerContext, SourceGraph); - if(!this->ComboAction) + UEdGraphPin *ComboActionActivatedPin = this->FindPin(COMBO_ACTION_ACTIVATED_PIN_NAME); + UEdGraphPin *ComboActionReleasedPin = this->FindPin(COMBO_ACTION_RELEASED_PIN_NAME); + + struct EventPinData { - static const FText InvalidActionWarning = LOCTEXT("InvalidComboActionDuringExpansion", "@@ does not have a valid Combo Action asset!!"); - CompilerContext.MessageLog.Warning(*InvalidActionWarning.ToString(), this); - return; - } - - // Establish active pins - struct ActivePinData - { - ActivePinData(UEdGraphPin* InPin, EComboActionTriggerEvent InTriggerEvent) : Pin(InPin), TriggerEvent(InTriggerEvent) {} - UEdGraphPin* Pin; + EventPinData(UEdGraphPin *InPin, EComboActionTriggerEvent InEvent) { this->Pin = InPin; this->TriggerEvent = InEvent; } + UEdGraphPin *GetPin() const { return this->Pin; } + const EComboActionTriggerEvent &GetTriggerEvent() { return this->TriggerEvent; } + private: + UEdGraphPin *Pin; EComboActionTriggerEvent TriggerEvent; }; - TArray ActivePins; - ForEachEventPinName([this, &ActivePins, &CompilerContext](EComboActionTriggerEvent Event, FName PinName) + TArray ActivePins; + if ((ComboActionActivatedPin != nullptr) && (ComboActionActivatedPin->LinkedTo.Num() > 0)) { - UEdGraphPin *ComboActionPin = FindPin(PinName, EEdGraphPinDirection::EGPD_Output); - if (ComboActionPin && ComboActionPin->LinkedTo.Num() > 0) - { - ActivePins.Add(ActivePinData(ComboActionPin, Event)); - } - }); - - if (ActivePins.Num() == 0) + ActivePins.Add(EventPinData(ComboActionActivatedPin, EComboActionTriggerEvent::Activated)); + } + if ((ComboActionReleasedPin != nullptr) && (ComboActionReleasedPin->LinkedTo.Num() > 0)) { - return; + ActivePins.Add(EventPinData(ComboActionReleasedPin, EComboActionTriggerEvent::Released)); } - // Bind all active pins to their action delegate const UEdGraphSchema_K2 *Schema = CompilerContext.GetSchema(); - auto CreateComboActionEvent = [this, &CompilerContext, &SourceGraph](UEdGraphPin *Pin, EComboActionTriggerEvent TriggerEvent) -> UK2Node_ComboActionEvent * - { - if (!this->ComboAction) + // If more than one is linked we have to do more complicated behaviors + //if (ActivePins.Num() > 1) + //{ + // Create a temporary variable to copy Key in to + UK2Node_TemporaryVariable *ComboActionObjectVar = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + ComboActionObjectVar->VariableType.PinCategory = UEdGraphSchema_K2::PC_Object; + ComboActionObjectVar->VariableType.PinSubCategoryObject = UComboAction::StaticClass(); + ComboActionObjectVar->AllocateDefaultPins(); + + for (auto PinIt = ActivePins.CreateIterator(); PinIt; ++PinIt) { - return nullptr; + UEdGraphPin *EachPin = (*PinIt).GetPin(); + + // Create the combo action event + UK2Node_ComboActionEvent *ComboActionEvent = CompilerContext.SpawnIntermediateEventNode(this, EachPin, SourceGraph); + ComboActionEvent->CustomFunctionName = FName(*FString::Printf(TEXT("ComboActionEvent_%s_%s"), *this->GetActionName().ToString(), *ComboActionEvent->GetName())); + ComboActionEvent->ComboAction = this->ComboAction; + ComboActionEvent->TriggerEvent = (*PinIt).GetTriggerEvent(); + ComboActionEvent->EventReference.SetExternalDelegateMember(FName(TEXT("ComboActionHandlerDynamicSignature__DelegateSignature"))); + ComboActionEvent->bInternalEvent = true; + ComboActionEvent->AllocateDefaultPins(); + + // Create assignment nodes to assign the key + UK2Node_AssignmentStatement *ComboActionObjectInitialize = CompilerContext.SpawnIntermediateNode(this, SourceGraph); + ComboActionObjectInitialize->AllocateDefaultPins(); + Schema->TryCreateConnection(ComboActionObjectVar->GetVariablePin(), ComboActionObjectInitialize->GetVariablePin()); + Schema->TryCreateConnection(ComboActionObjectInitialize->GetValuePin(), ComboActionEvent->FindPinChecked(COMBO_ACTION_OBJECT_PIN_NAME)); + // Connect the events to the assign key nodes + Schema->TryCreateConnection(Schema->FindExecutionPin(*ComboActionEvent, EGPD_Output), ComboActionObjectInitialize->GetExecPin()); + + // Move the original event connections to the then pin of the key assign + CompilerContext.MovePinLinksToIntermediate(*EachPin, *ComboActionObjectInitialize->GetThenPin()); + + // Move the original event variable connections to the intermediate nodes + CompilerContext.MovePinLinksToIntermediate(*this->FindPin(COMBO_ACTION_OBJECT_PIN_NAME), *ComboActionObjectVar->GetVariablePin()); } + //} + //else if (ActivePins.Num() == 1) + //{ + // UEdGraphPin *ComboActionPin = ActivePins[0].GetPin(); + // EComboActionTriggerEvent ComboActionTriggerEvent = ActivePins[0].GetTriggerEvent(); - UK2Node_ComboActionEvent *ComboActionEvent = CompilerContext.SpawnIntermediateEventNode(this, Pin, SourceGraph); - ComboActionEvent->CustomFunctionName = FName(*FString::Printf(TEXT("ComboActionEvent_%s_%s"), *this->ComboAction->GetName(), *ComboActionEvent->GetName())); - ComboActionEvent->ComboAction = this->ComboAction; - ComboActionEvent->TriggerEvent = TriggerEvent; - ComboActionEvent->EventReference.SetExternalDelegateMember(FName(TEXT("ComboActionHandlerDynamicSignature__DelegateSignature"))); - ComboActionEvent->AllocateDefaultPins(); - return ComboActionEvent; - }; + // if (ComboActionPin->LinkedTo.Num() > 0) + // { + // UK2Node_ComboActionEvent *ComboActionEvent = CompilerContext.SpawnIntermediateEventNode(this, ComboActionPin, SourceGraph); + // ComboActionEvent->CustomFunctionName = FName(*FString::Printf(TEXT("ComboActionEvent_%s_%s"), *this->GetActionName().ToString(), *ComboActionEvent->GetName())); + // ComboActionEvent->ComboAction = this->ComboAction; + // ComboActionEvent->TriggerEvent = ComboActionTriggerEvent; + // ComboActionEvent->EventReference.SetExternalDelegateMember(FName(TEXT("ComboActionHandlerDynamicSignature__DelegateSignature"))); + // ComboActionEvent->bInternalEvent = true; + // ComboActionEvent->AllocateDefaultPins(); - for (ActivePinData &PinData : ActivePins) - { - UEdGraphPin *EachPin = PinData.Pin; - UK2Node_ComboActionEvent *ComboActionEvent = CreateComboActionEvent(EachPin, PinData.TriggerEvent); - - if (!ComboActionEvent) - { - continue; - } - } + // CompilerContext.MovePinLinksToIntermediate(*ComboActionPin, *Schema->FindExecutionPin(*ComboActionEvent, EGPD_Output)); + // CompilerContext.MovePinLinksToIntermediate(*this->FindPin(COMBO_ACTION_OBJECT_PIN_NAME), *ComboActionEvent->FindPin(COMBO_ACTION_OBJECT_PIN_NAME)); + // } + //} } -void UK2Node_ComboAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const +void UK2Node_ComboAction::GetMenuActions(FBlueprintActionDatabaseRegistrar &ActionRegistrar) const { auto CustomizeComboActionNodeLambda = [](UEdGraphNode *NewNode, bool bIsTemplateNode, TWeakObjectPtr Action) { - UK2Node_ComboAction* ComboActionNode = CastChecked(NewNode); + UK2Node_ComboAction *ComboActionNode = CastChecked(NewNode); ComboActionNode->ComboAction = Action.Get(); }; // Do a first time registration using the node's class to pull in all existing actions if (ActionRegistrar.IsOpenForRegistration(GetClass())) { - IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")).Get(); + IAssetRegistry &AssetRegistry = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")).Get(); static bool bRegisterOnce = true; if (bRegisterOnce) @@ -245,15 +230,18 @@ void UK2Node_ComboAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& Acti bRegisterOnce = false; if (AssetRegistry.IsLoadingAssets()) { - AssetRegistry.OnFilesLoaded().AddLambda([]() { FBlueprintActionDatabase::Get().RefreshClassActions(StaticClass()); }); + AssetRegistry.OnFilesLoaded().AddLambda([]() + { + FBlueprintActionDatabase::Get().RefreshClassActions(StaticClass()); + }); } } TArray ActionAssets; AssetRegistry.GetAssetsByClass(UComboAction::StaticClass()->GetClassPathName(), ActionAssets, true); - for (const FAssetData& ActionAsset : ActionAssets) + for (const FAssetData &ActionAsset : ActionAssets) { - UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass()); + UBlueprintNodeSpawner *NodeSpawner = UBlueprintNodeSpawner::Create(GetClass()); check(NodeSpawner != nullptr); if (FPackageName::GetPackageMountPoint(ActionAsset.PackageName.ToString()) != NAME_None) @@ -269,7 +257,7 @@ void UK2Node_ComboAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& Acti else if (const UComboAction *Action = Cast(ActionRegistrar.GetActionKeyFilter())) { // If this is a specific UComboAction asset update it. - UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass()); + UBlueprintNodeSpawner *NodeSpawner = UBlueprintNodeSpawner::Create(GetClass()); check(NodeSpawner != nullptr); NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(CustomizeComboActionNodeLambda, TWeakObjectPtr(Action)); @@ -296,7 +284,7 @@ FBlueprintNodeSignature UK2Node_ComboAction::GetSignature() const return NodeSignature; } -TSharedPtr UK2Node_ComboAction::GetEventNodeAction(const FText& ActionCategory) +TSharedPtr UK2Node_ComboAction::GetEventNodeAction(const FText &ActionCategory) { // TODO: Custom EdGraphSchemaAction required? TSharedPtr EventNodeAction = MakeShareable(new FEdGraphSchemaAction_K2InputAction(ActionCategory, GetNodeTitle(ENodeTitleType::EditableTitle), GetTooltipText(), 0)); @@ -305,4 +293,3 @@ TSharedPtr UK2Node_ComboAction::GetEventNodeAction(const F } #undef LOCTEXT_NAMESPACE - diff --git a/Source/ComboInput/Private/Events/K2Node_ComboActionEvent.cpp b/Source/ComboInput/Private/Events/K2Node_ComboActionEvent.cpp index 666f0d7..fe2fd97 100644 --- a/Source/ComboInput/Private/Events/K2Node_ComboActionEvent.cpp +++ b/Source/ComboInput/Private/Events/K2Node_ComboActionEvent.cpp @@ -26,6 +26,7 @@ void UK2Node_ComboActionEvent::RegisterDynamicBinding(UDynamicBlueprintBinding * FBlueprintComboActionBinding Binding; Binding.FunctionNameToBind = this->CustomFunctionName; + Binding.ComboAction = this->ComboAction; Binding.TriggerEvent = this->TriggerEvent; ComboActionBindingObject->ComboActionDelegateBindings.Add(Binding); diff --git a/Source/ComboInput/Public/Components/ComboManagerComponent.h b/Source/ComboInput/Public/Components/ComboManagerComponent.h index 8012efc..ef77664 100644 --- a/Source/ComboInput/Public/Components/ComboManagerComponent.h +++ b/Source/ComboInput/Public/Components/ComboManagerComponent.h @@ -12,9 +12,29 @@ DECLARE_LOG_CATEGORY_EXTERN(LogComboManagerComponent, Log, All); -DECLARE_DYNAMIC_DELEGATE/*_OneParam*/(FComboActionHandlerDynamicSignature/*, EComboActionTriggerEvent, TriggerEvent*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FComboActionHandlerDelegate, const class UComboAction *, ComboAction, const bool, Activated); +DECLARE_DYNAMIC_DELEGATE_TwoParams(FComboActionHandlerDynamicSignature, const class UComboAction *, ComboAction, const EComboActionTriggerEvent &, TriggerEvent); +struct COMBOINPUT_API FComboDelegateKey +{ +public: + FComboDelegateKey(const class UComboAction *ComboAction, const EComboActionTriggerEvent &TriggerEvent) + { + this->Key = FName(ComboAction->GetName() + TEXT("_") + StaticEnum()->GetDisplayNameTextByIndex((uint8)TriggerEvent).ToString()); + } + FName Key; +}; + +USTRUCT(BlueprintType) +struct COMBOINPUT_API FComboOffsetMap +{ + GENERATED_BODY() +public: + UPROPERTY(BlueprintReadOnly, EditAnywhere) TObjectPtr ComboInput; + UPROPERTY(BlueprintReadOnly, EditAnywhere) TObjectPtr ComboAction; +}; + UCLASS(BlueprintType, ClassGroup=(Input), meta=(BlueprintSpawnableComponent)) class COMBOINPUT_API UComboManagerComponent : public UActorComponent { @@ -27,11 +47,12 @@ public: UFUNCTION(BlueprintCallable) void ActivateComboInput(const class UComboInputAsset *Input); - void BindAction(UObject *ObjectToBindTo, FName FunctionName) + void BindAction(UObject *ObjectToBindTo, FName FunctionName, const class UComboAction *ComboAction, const EComboActionTriggerEvent &TriggerEvent) { FComboActionHandlerDynamicSignature Delegate; Delegate.BindUFunction(ObjectToBindTo, FunctionName); - this->ComboActionEventBindings.Add(MoveTemp(Delegate)); + const FComboDelegateKey Key(ComboAction, TriggerEvent); + this->ComboActionEventBindings.Emplace(Key.Key, MoveTemp(Delegate)); } protected: @@ -41,23 +62,29 @@ protected: // This input will be recognised as an offset input, which cancels a node transition // if activated early enough in the transition. This locks the current place in the // combo and allows this combo string to be continued after this input has executed. + // The associated combo action will then be activated. UPROPERTY(BlueprintReadOnly, EditDefaultsOnly) - TObjectPtr OffsetInput; + FComboOffsetMap OffsetMap; UPROPERTY(BlueprintReadOnly, EditDefaultsOnly) TMap, float> DEBUG__UnlockTimers; + UPROPERTY(BlueprintReadWrite, BlueprintAssignable) + FComboActionHandlerDelegate OnComboAction; + private: void BeginNodeTransition(const class UComboSequenceNode *NextNode); void FinishTransition(); + void BroadcastDelegates(const class UComboAction *ComboAction, const EComboActionTriggerEvent &TriggerEvent); + void DEBUG__UnlockAction(TObjectPtr Unlock); void DEBUG__ResetCombo(); const class UComboSequenceNode *ActiveNode = nullptr; const class UComboSequenceNode *PreviousNode = nullptr; - TArray ComboActionEventBindings; + TMap ComboActionEventBindings; TObjectPtr AttachedInputBuffer; diff --git a/Source/ComboInput/Public/Events/ComboActionDelegateBinding.h b/Source/ComboInput/Public/Events/ComboActionDelegateBinding.h index a26126b..fff4946 100644 --- a/Source/ComboInput/Public/Events/ComboActionDelegateBinding.h +++ b/Source/ComboInput/Public/Events/ComboActionDelegateBinding.h @@ -15,6 +15,7 @@ struct COMBOINPUT_API FBlueprintComboActionBinding public: UPROPERTY() FName FunctionNameToBind = NAME_None; + UPROPERTY() TObjectPtr ComboAction; UPROPERTY() EComboActionTriggerEvent TriggerEvent = EComboActionTriggerEvent::None; }; diff --git a/Source/ComboInput/Public/Events/K2Node_ComboAction.h b/Source/ComboInput/Public/Events/K2Node_ComboAction.h index 6b85c2a..08a221c 100644 --- a/Source/ComboInput/Public/Events/K2Node_ComboAction.h +++ b/Source/ComboInput/Public/Events/K2Node_ComboAction.h @@ -24,7 +24,7 @@ class COMBOINPUT_API UK2Node_ComboAction : public UK2Node, public IK2Node_EventN GENERATED_BODY() public: - UK2Node_ComboAction(const FObjectInitializer &ObjectInitializer); + UK2Node_ComboAction(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer){} UPROPERTY() TObjectPtr ComboAction;