My Gameplay Ability melee combo is not replicating correctly

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)
}

the glitchy movements seems like the character is trying to fix its position, meaning something is setting the position and something else is setting it again. My guess is that your animation montage moves the character via root motion and the server and client are arguing about where character should be. Check out this post where they implemented root motion movement without and hitches Root Motion Over Network - How Its Done - #26 by OptimisticMonkey