I am trying to create a basic melee ability combo, it simply uses an array of montages that play in order, the combo resets if the ability is not reactivated within 0.5 seconds, the ability works completely fine on the server, but doesn’t work correctly on the client.
Instead, it seems to reset the combo prematurely, and my character glitches and teleports while performing the combo, I’ve attached a video, detailing the issue. (Server: left, Client: right).
I’ll also share my MeleeAttack cpp file
// Fill out your copyright notice in the Description page of Project Settings.
#include "GameplayAbility_MeleeAttack.h"
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
#include "FactorySurvivalGame/AbilitySystem/CombatInterface.h"
#include "Net/UnrealNetwork.h"
UGameplayAbility_MeleeAttack::UGameplayAbility_MeleeAttack()
{
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
bReplicateInputDirectly = true;
//TODO Add tags here when we work that out
}
void UGameplayAbility_MeleeAttack::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
if(!HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo))
{
return;
}
if(ICombatInterface* CombatInterface = Cast<ICombatInterface>(ActorInfo->AvatarActor))
{
AttackCombo = CombatInterface->GetMeleeAttackCombo();
if(!IsValid(AttackCombo))
{
// This is probably not needed
return EndAbility(Handle, ActorInfo, ActivationInfo, true, true);
}
}
if(GetWorld()->TimeSeconds - LastActivate > 0.5)
{
CurrentAttackIndex = 0;
}
UE_LOG(LogTemp, Warning, TEXT("CurrentAttackIndex %i"), CurrentAttackIndex);
UAbilityTask_PlayMontageAndWait* Task = UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(this, NAME_None, GetCurrent().Animation);
Task->OnBlendOut.AddDynamic(this, &UGameplayAbility_MeleeAttack::OnAnimationFinished);
Task->ReadyForActivation();
}
void UGameplayAbility_MeleeAttack::ProgressCombo_Implementation()
{
LastActivate = GetWorld()->TimeSeconds;
CurrentAttackIndex++;
if(CurrentAttackIndex >= AttackCombo->Attacks.Num())
{
CurrentAttackIndex = 0;
}
}
void UGameplayAbility_MeleeAttack::OnAnimationFinished()
{
ProgressCombo();
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, true, false);
}
void UGameplayAbility_MeleeAttack::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UGameplayAbility_MeleeAttack, CurrentAttackIndex)
DOREPLIFETIME(UGameplayAbility_MeleeAttack, LastActivate)
DOREPLIFETIME(UGameplayAbility_MeleeAttack, AttackCombo)
}