- Release triggers only fire if one is available in the current node's children.

- Crashes related to PreviousNode occasionally becoming null have been fixed.
This commit is contained in:
Jamie Greunbaum 2023-10-07 19:41:23 -04:00
parent 08b89b9d84
commit b77a9bd2ed

View File

@ -28,18 +28,19 @@ void UComboManagerComponent::InitializeComponent()
Super::InitializeComponent(); Super::InitializeComponent();
checkf(this->ComboGraph, TEXT("No combo graph is set for %s in actor %s"), *UComboManagerComponent::StaticClass()->GetName(), *this->GetOwner()->GetName()); 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) void UComboManagerComponent::SetComboGraph(const UComboActionGraph *Graph)
{ {
checkf(Graph, TEXT("Attempting to set a null combo graph."));
this->ComboGraph = Graph; this->ComboGraph = Graph;
this->FoundInputsCache.Empty(); this->FoundInputsCache.Empty();
this->FindAllUsedInputs(); this->FindAllUsedInputs();
this->ActiveNode = this->ComboGraph->StartNode; this->ResetCombo();
this->PreviousNode = nullptr;
} }
@ -123,11 +124,40 @@ void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtr<const UComboInputAss
void UComboManagerComponent::ReleaseComboAction(const class UComboInputAsset *Input) void UComboManagerComponent::ReleaseComboAction(const class UComboInputAsset *Input)
{ {
if (this->LastComboAction) if (this->LastComboAction && this->ActiveNode)
{ {
this->BroadcastDelegates(this->LastComboAction, EComboActionTriggerEvent::Released); // See if we have a fallback we can release.
this->LastComboAction = nullptr; const TObjectPtr<const UComboAction> *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<const UComboActionGraphNode_ActionNode *>(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() void UComboManagerComponent::ResetCombo()
{ {
this->GetWorld()->GetTimerManager().ClearTimer(this->DEBUG__ResetComboTimer); this->GetWorld()->GetTimerManager().ClearTimer(this->DEBUG__ResetComboTimer);
this->PreviousNode = this->ActiveNode; this->PreviousNode = this->ActiveNode = this->ComboGraph->StartNode;
this->ActiveNode = this->ComboGraph->StartNode;
APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0);
if (UInputBufferComponent *InputComponent = Cast<UInputBufferComponent>(Controller->InputComponent))
{
for (const UComboInputAsset *Unlock : this->FoundInputsCache)
{
InputComponent->UnlockComboInput(Unlock);
}
}
} }
@ -179,13 +217,13 @@ TSet<const UComboInputAsset *> &UComboManagerComponent::FindAllUsedInputs()
} }
void UComboManagerComponent::FindAllUsedInputs_RecurseGraph(const UComboActionGraphNode *CurrentNode, TSet<const UComboInputAsset *> &FoundInputs) void UComboManagerComponent::FindAllUsedInputs_RecurseGraph(const UComboActionGraphNode *CurrentNode, TSet<const UComboInputAsset *> &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 // 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 // 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. // 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.")); checkf(NextNode->GetClass() == UComboActionGraphNode_ActionNode::StaticClass(), TEXT("This graph contains non-action nodes. The cast in this function will fail."));
FoundInputs.Add(static_cast<const UComboActionGraphNode_ActionNode *>(NextNode)->GetComboInput()); FoundInputs.Add(StaticCast<const UComboActionGraphNode_ActionNode *>(NextNode)->GetComboInput());
this->FindAllUsedInputs_RecurseGraph(NextNode, FoundInputs); 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. // Find a node that matches both the combo input and the trigger action.
const UComboActionGraphNode *NextNode = nullptr; const UComboActionGraphNode *NextNode = nullptr;
for (const UComboActionGraphNode *GraphNode : CurrentNode->ChildrenNodes) for (const UComboActionGraphNode *GraphNode : CurrentNode->ChildNodes)
{ {
if (const UComboActionGraphNode_ActionNode *ActionNode = Cast<UComboActionGraphNode_ActionNode>(GraphNode)) if (const UComboActionGraphNode_ActionNode *ActionNode = Cast<UComboActionGraphNode_ActionNode>(GraphNode))
{ {