// Copyright (c) 2026 Reignance Studios. MIT License, see LICENSE. #pragma once #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "GameplayTagContainer.h" #include "GameplayEffectTypes.h" #include "RSAbilitySystemLibrary.generated.h" class UAbilitySystemComponent; class UGameplayEffect; /** Why an activate-by-tag call did or did not start an ability. */ UENUM(BlueprintType) enum class ERSActivateResult : uint8 { /** No ability system component was found on the actor. */ NoASC, /** The ASC has no granted ability whose tags match. */ NotGranted, /** A matching ability exists but could not activate (tags, cost, cooldown, net policy). */ Blocked, /** At least one matching ability was activated or sent to the server for activation. */ Activated }; /** * Blueprint and C++ helpers for the Gameplay Ability System in multiplayer games. * Each function has a matching tutorial at https://reignancestudios.com/tutorials */ UCLASS() class RSGASHELPERS_API URSAbilitySystemLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY() public: /** * Finds the ability system component for an actor, including the common * "ASC lives on the PlayerState" setup. Checks, in order: the actor itself, * its PlayerState (pawns), its controller's PlayerState, its owner. */ UFUNCTION(BlueprintPure, Category = "RS|GAS", meta = (DefaultToSelf = "Actor")) static UAbilitySystemComponent* FindAbilitySystemComponent(const AActor* Actor); /** * Activates abilities matching a tag and says why it failed when it does. * Call it on the owning client for predicted abilities; the ASC handles the server round trip. */ UFUNCTION(BlueprintCallable, Category = "RS|GAS", meta = (DefaultToSelf = "Actor")) static ERSActivateResult TryActivateAbilityByTag(AActor* Actor, FGameplayTag AbilityTag, bool bAllowRemoteActivation = true); /** * Adds a loose gameplay tag on the server and replicates it to every client. * Plain AddLooseGameplayTag never replicates. Does nothing without authority. * Returns true when the tag was added. */ UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "RS|GAS", meta = (DefaultToSelf = "Actor")) static bool AddReplicatedLooseTag(AActor* Actor, FGameplayTag Tag); /** Removes a tag added with AddReplicatedLooseTag, on the server and on every client. */ UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "RS|GAS", meta = (DefaultToSelf = "Actor")) static bool RemoveReplicatedLooseTag(AActor* Actor, FGameplayTag Tag); /** * Builds an outgoing effect spec and fills SetByCaller magnitudes in one call. * Missing SetByCaller values are the most common cause of "effect applied with 0". */ UFUNCTION(BlueprintCallable, Category = "RS|GAS") static FGameplayEffectSpecHandle MakeSpecWithSetByCaller( UAbilitySystemComponent* ASC, TSubclassOf EffectClass, float Level, const TMap& SetByCallerMagnitudes); /** * Returns a readable snapshot of an ASC: net role, owner and avatar, owned tags, * granted and active abilities, active effects and every attribute value. * Print it on the server and on a client side by side to find a desync. */ UFUNCTION(BlueprintCallable, Category = "RS|GAS|Debug", meta = (DefaultToSelf = "Actor")) static FString DumpAbilitySystemState(const AActor* Actor); };