diff --git a/Source/ComboInput/Private/Components/ComboManagerComponent.cpp b/Source/ComboInput/Private/Components/ComboManagerComponent.cpp index 7d39d3f..c73d6e5 100644 --- a/Source/ComboInput/Private/Components/ComboManagerComponent.cpp +++ b/Source/ComboInput/Private/Components/ComboManagerComponent.cpp @@ -28,18 +28,19 @@ void UComboManagerComponent::InitializeComponent() Super::InitializeComponent(); checkf(this->ComboGraph, TEXT("No combo graph is set for %s in actor %s"), *UComboManagerComponent::StaticClass()->GetName(), *this->GetOwner()->GetName()); - this->ActiveNode = this->ComboGraph->StartNode; + this->PreviousNode = this->ActiveNode = this->ComboGraph->StartNode; } void UComboManagerComponent::SetComboGraph(const UComboActionGraph *Graph) { + checkf(Graph, TEXT("Attempting to set a null combo graph.")); + this->ComboGraph = Graph; this->FoundInputsCache.Empty(); this->FindAllUsedInputs(); - this->ActiveNode = this->ComboGraph->StartNode; - this->PreviousNode = nullptr; + this->ResetCombo(); } @@ -123,11 +124,40 @@ void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtrLastComboAction) + if (this->LastComboAction && this->ActiveNode) { - this->BroadcastDelegates(this->LastComboAction, EComboActionTriggerEvent::Released); - this->LastComboAction = nullptr; + // See if we have a fallback we can release. + const TObjectPtr *FallbackAction = this->FallbackActions.Find(Input); + if (FallbackAction && *FallbackAction == this->LastComboAction) + { + this->ResetCombo(); + this->BroadcastDelegates(*FallbackAction, EComboActionTriggerEvent::Released); + UE_LOG(LogComboManagerComponent, Verbose, TEXT("Fallback action %s released"), *(*FallbackAction)->ActionName.ToString()); + } + else + { + // Find a node that matches the release action. + const UComboAction *ComboAction = nullptr; + for (const UComboActionGraphNode *Node : this->ActiveNode->ChildNodes) + { + if (const UComboActionGraphNode_ActionNode *ActionNode = StaticCast(Node)) + { + if (ActionNode->GetTriggerEvent() == EComboActionTriggerEvent::Released) + { + ComboAction = ActionNode->GetComboAction(); + break; + } + } + } + if (ComboAction) + { + this->BroadcastDelegates(ComboAction, EComboActionTriggerEvent::Released); + UE_LOG(LogComboManagerComponent, Verbose, TEXT("%s released"), *ComboAction->ActionName.ToString()); + } + } } + + this->LastComboAction = nullptr; } @@ -148,8 +178,16 @@ void UComboManagerComponent::FinishTransition() void UComboManagerComponent::ResetCombo() { this->GetWorld()->GetTimerManager().ClearTimer(this->DEBUG__ResetComboTimer); - this->PreviousNode = this->ActiveNode; - this->ActiveNode = this->ComboGraph->StartNode; + this->PreviousNode = this->ActiveNode = this->ComboGraph->StartNode; + + APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0); + if (UInputBufferComponent *InputComponent = Cast(Controller->InputComponent)) + { + for (const UComboInputAsset *Unlock : this->FoundInputsCache) + { + InputComponent->UnlockComboInput(Unlock); + } + } } @@ -179,13 +217,13 @@ TSet &UComboManagerComponent::FindAllUsedInputs() } void UComboManagerComponent::FindAllUsedInputs_RecurseGraph(const UComboActionGraphNode *CurrentNode, TSet &FoundInputs) { - for (const UComboActionGraphNode *NextNode : CurrentNode->ChildrenNodes) + for (const UComboActionGraphNode *NextNode : CurrentNode->ChildNodes) { // It should be safe to assume all of our nodes are action nodes. If at some point // this becomes less reliable, this should be changed. But just for the sake of // saving a bit of performance on start-up, we're doing this right now. checkf(NextNode->GetClass() == UComboActionGraphNode_ActionNode::StaticClass(), TEXT("This graph contains non-action nodes. The cast in this function will fail.")); - FoundInputs.Add(static_cast(NextNode)->GetComboInput()); + FoundInputs.Add(StaticCast(NextNode)->GetComboInput()); this->FindAllUsedInputs_RecurseGraph(NextNode, FoundInputs); } } @@ -196,7 +234,7 @@ const UComboActionGraphNode *UComboManagerComponent::FindActiveNodeData(const UC // Find a node that matches both the combo input and the trigger action. const UComboActionGraphNode *NextNode = nullptr; - for (const UComboActionGraphNode *GraphNode : CurrentNode->ChildrenNodes) + for (const UComboActionGraphNode *GraphNode : CurrentNode->ChildNodes) { if (const UComboActionGraphNode_ActionNode *ActionNode = Cast(GraphNode)) {