Replication for GAS Target Data not working

Recently I started working on a personal project to flesh out some ideas, but I have hit some issue with multiplayer replication.

I am using GAS (Gameplay Ability System), which is for the sake of multiple abilities across different players. Currently, I have a skill that requires clients to input their mouse location, basically left-clicking wherever it is and sending the coordinate to the server and only initiating the ability. Unfortunately, it does not work for the server. The coordinate doesn’t replicate to the server, not sure if I missed anything.

PC_GATA_MouseLocation.h

#pragma once

#include "CoreMinimal.h"
#include "Abilities/GameplayAbilityTargetActor.h"
#include "PC_GATA_MouseLocation.generated.h"

/** Target data with a the client mouse location */
USTRUCT(BlueprintType)
struct PROJECTCARRIAGE_API FGameplayAbilityTargetData_MouseLocation : public FGameplayAbilityTargetData
{
	GENERATED_USTRUCT_BODY()

	FGameplayAbilityTargetData_MouseLocation()
	{ }

	FGameplayAbilityTargetData_MouseLocation(FVector InMouseLocation, FVector InMouseDirection)
	{ 
		MouseLocation = InMouseLocation;
		MouseDirection = InMouseDirection;
	}

	/** Client mouse location */
	UPROPERTY()
	FVector_NetQuantize	MouseLocation;

	/** Client mouse location direction */
	UPROPERTY()
	FVector_NetQuantize	MouseDirection;

	bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);

	virtual UScriptStruct* GetScriptStruct() const override
	{
		return FGameplayAbilityTargetData_MouseLocation::StaticStruct();
	}
};

template<> struct TIsPODType<FGameplayAbilityTargetData_MouseLocation> { enum { Value = true }; };

template<>
struct TStructOpsTypeTraits<FGameplayAbilityTargetData_MouseLocation> : public TStructOpsTypeTraitsBase2<FGameplayAbilityTargetData_MouseLocation>
{
	enum
	{
		WithNetSerializer = true	// For now this is REQUIRED for FGameplayAbilityTargetDataHandle net serialization to work
	};
};

UCLASS()
class PROJECTCARRIAGE_API APC_GATA_MouseLocation : public AGameplayAbilityTargetActor
{
	GENERATED_BODY()
public:

	APC_GATA_MouseLocation();

	UPROPERTY(BlueprintReadOnly, Category = Targeting)
	FVector_NetQuantize MouseLocation;

	UPROPERTY(BlueprintReadOnly, Category = Targeting)
	FVector_NetQuantize MouseDirection;

	virtual void StartTargeting(UGameplayAbility* Ability) override;

	virtual bool IsConfirmTargetingAllowed() { return true; };

	virtual void ConfirmTargetingAndContinue() override;
};

PC_GATA_MouseLocation.cpp

#include "Game/Abilities/TargetData/PC_GATA_MouseLocation.h"
#include "Game/GAS/PC_GameplayAbility.h"
#include "Kismet/GameplayStatics.h"
#include "Player/PC_PlayerCharacter.h"
#include "Utils/PC_GameUtils.h"

bool FGameplayAbilityTargetData_MouseLocation::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
{
	MouseLocation.NetSerialize(Ar, Map, bOutSuccess);
	MouseDirection.NetSerialize(Ar, Map, bOutSuccess);
	return bOutSuccess;
}

APC_GATA_MouseLocation::APC_GATA_MouseLocation()
{
	PrimaryActorTick.bCanEverTick = true;
	ShouldProduceTargetDataOnServer = true;
}

void APC_GATA_MouseLocation::StartTargeting(UGameplayAbility* InAbility)
{
	Super::StartTargeting(InAbility);
	APlayerController* PC = OwningAbility->GetActorInfo().PlayerController.Get();
	check(PC);
	FVector CurrentMouseLocation;
	FVector CurrentMouseDirection;
	UE_LOG(LogTemp, Warning, TEXT("PlayerController: %s"), *GetNameSafe(PC));
	UE_LOG(LogTemp, Warning, TEXT("MouseLoc: %s"), *MouseLocation.ToString());
	UE_LOG(LogTemp, Warning, TEXT("MouseDirection: %s"), *MouseDirection.ToString());
	if (GetLocalRole() != ROLE_Authority || (MouseLocation.IsZero() && MouseDirection.IsZero()))
	{
		UPC_GameUtils::GetMouseWorldLocation(PC, MouseLocation, MouseDirection);
	}
}

void APC_GATA_MouseLocation::ConfirmTargetingAndContinue()
{
	check(ShouldProduceTargetData());
	FGameplayAbilityTargetData_MouseLocation* MouseInfo = new FGameplayAbilityTargetData_MouseLocation(MouseLocation, MouseDirection);
	FGameplayAbilityTargetDataHandle Handle;
	Handle.Add(MouseInfo);
	UE_LOG(LogTemp, Warning, TEXT("PostLoc"));
	UE_LOG(LogTemp, Warning, TEXT("MouseLoc: %s"), *MouseLocation.ToString());
	UE_LOG(LogTemp, Warning, TEXT("MouseDirection: %s"), *MouseDirection.ToString());
	TargetDataReadyDelegate.Broadcast(Handle);
}



image
image

image

Of course, in server calling the ability works fine, but not for clients. Any ideas?

Maybe i am not following properly, but if this stuff needs to be done on server, then the RPC is not needed as both client and server will call the RemoveBlocks event.

I am not sure why your target data is not replicating? And you didn’t mention any crashes… But would like to clarify you are claling InitGlobalData on the AbilitySystemGlobals?

1 Like

The reason why it needs data from the client is the cursor position needs to be replicated for the server, then only remove the blocks with that position data. (The remove blocks function needs a position to remove exactly where it is)

I am not sure what is InitGlobalData and AbilitySystemGlobals? Do they have impact on GAS replication stuff?

Did you ever figure this out? Stuck on a similar problem :confused:

Hi, I think I have the answer. If you go to Tranek’s documentation, scroll down to the section about “ability system globals”. there is a function called initGlobalData() that must be called in order to use target data. Section 4.9

To further expand on this, you need to create a c++ class based on the assetmanager class. in this class you need to add this to your header: virtual void StartInitialLoading() override;

in your implementation, call
Super::StartInitialLoading();
UAbilitySystemGlobals::Get().InitGlobalData();

after doing this, it worked for me!