From 799cfa4303aff76ca0127f016d84d265b6b0b400 Mon Sep 17 00:00:00 2001 From: LongLy Date: Sat, 4 Jan 2025 09:41:49 -0700 Subject: [PATCH] Initial commit of ability system --- Source/OLSAnimation/OLSAnimation.Build.cs | 5 +- .../OLSBaseLayerAnimInstance.cpp | 16 + .../AnimInstances/OLSBaseLayerAnimInstance.h | 19 + .../OLSAnimationEditor.Build.cs | 2 - .../OLSAbilitySystemComponent.cpp | 332 ++++++++++++++++++ .../OLSBatchGameplayAbilityInterface.cpp | 7 + .../OLSGlobaAbilitySubsystem.cpp | 110 ++++++ .../OLSModularAIController.cpp | 24 ++ .../ModularGameplayActors/OLSModularActor.cpp | 100 ++++++ .../OLSModularCharacter.cpp | 98 ++++++ .../OLSModularDefaultPawn.cpp | 100 ++++++ .../OLSModularGameMode.cpp | 20 ++ .../OLSModularGameState.cpp | 55 +++ .../ModularGameplayActors/OLSModularPawn.cpp | 90 +++++ .../OLSModularPlayerController.cpp | 46 +++ .../OLSModularPlayerState.cpp | 80 +++++ .../OLSModularPlayerStateCharacter.cpp | 121 +++++++ .../Private/Player/OLSPlayerController.cpp | 4 + Source/ols/Private/Player/OLSPlayerState.cpp | 40 +++ .../AbilitySystem/OLSAbilitySystemComponent.h | 162 +++++++++ .../OLSBatchGameplayAbilityInterface.h | 30 ++ .../AbilitySystem/OLSGlobaAbilitySubsystem.h | 64 ++++ .../OLSModularAIController.h | 23 ++ .../ModularGameplayActors/OLSModularActor.h | 62 ++++ .../OLSModularCharacter.h | 65 ++++ .../OLSModularDefaultPawn.h | 61 ++++ .../OLSModularGameMode.h | 30 ++ .../OLSModularGameState.h | 43 +++ .../ModularGameplayActors/OLSModularPawn.h | 61 ++++ .../OLSModularPlayerController.h | 25 ++ .../OLSModularPlayerState.h | 60 ++++ .../OLSModularPlayerStateCharacter.h | 73 ++++ .../ols/Public/Player/OLSPlayerController.h | 16 + Source/ols/Public/Player/OLSPlayerState.h | 35 ++ Source/ols/ols.Build.cs | 13 +- ols.uproject | 8 + 36 files changed, 2094 insertions(+), 6 deletions(-) create mode 100644 Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp create mode 100644 Source/ols/Private/AbilitySystem/OLSBatchGameplayAbilityInterface.cpp create mode 100644 Source/ols/Private/AbilitySystem/OLSGlobaAbilitySubsystem.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularAIController.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularActor.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularCharacter.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularDefaultPawn.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularGameMode.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularGameState.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularPawn.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularPlayerController.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularPlayerState.cpp create mode 100644 Source/ols/Private/ModularGameplayActors/OLSModularPlayerStateCharacter.cpp create mode 100644 Source/ols/Private/Player/OLSPlayerController.cpp create mode 100644 Source/ols/Private/Player/OLSPlayerState.cpp create mode 100644 Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h create mode 100644 Source/ols/Public/AbilitySystem/OLSBatchGameplayAbilityInterface.h create mode 100644 Source/ols/Public/AbilitySystem/OLSGlobaAbilitySubsystem.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularAIController.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularActor.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularCharacter.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularDefaultPawn.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularGameMode.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularGameState.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularPawn.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularPlayerController.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularPlayerState.h create mode 100644 Source/ols/Public/ModularGameplayActors/OLSModularPlayerStateCharacter.h create mode 100644 Source/ols/Public/Player/OLSPlayerController.h create mode 100644 Source/ols/Public/Player/OLSPlayerState.h diff --git a/Source/OLSAnimation/OLSAnimation.Build.cs b/Source/OLSAnimation/OLSAnimation.Build.cs index aca3fbd..3fe35a8 100644 --- a/Source/OLSAnimation/OLSAnimation.Build.cs +++ b/Source/OLSAnimation/OLSAnimation.Build.cs @@ -9,7 +9,7 @@ public class OLSAnimation : ModuleRules PublicDependencyModuleNames.AddRange( new string[] { - "Core", + "Core" } ); @@ -21,7 +21,8 @@ public class OLSAnimation : ModuleRules "Slate", "SlateCore", "AnimGraphRuntime", - "GameplayTags" + "GameplayTags", + "GameplayAbilities", } ); } diff --git a/Source/OLSAnimation/Private/AnimInstances/OLSBaseLayerAnimInstance.cpp b/Source/OLSAnimation/Private/AnimInstances/OLSBaseLayerAnimInstance.cpp index cee5a56..fbc5526 100644 --- a/Source/OLSAnimation/Private/AnimInstances/OLSBaseLayerAnimInstance.cpp +++ b/Source/OLSAnimation/Private/AnimInstances/OLSBaseLayerAnimInstance.cpp @@ -17,6 +17,22 @@ static TAutoConsoleVariable CVarAnimInstanceLocomotionDebug(TEXT("a.AnimInstance.Locomotion.Debug"), false, TEXT("Turn on visualization debugging for Locomotion")); #endif +void UOLSBaseLayerAnimInstance::InitializeWithAbilitySystem(UAbilitySystemComponent* asc) +{ + check(asc); + + GameplayTagPropertyMap.Initialize(this, asc); +} + +EDataValidationResult UOLSBaseLayerAnimInstance::IsDataValid(FDataValidationContext& context) const +{ + Super::IsDataValid(context); + + GameplayTagPropertyMap.IsDataValid(this, context); + + return ((context.GetNumErrors() > 0) ? EDataValidationResult::Invalid : EDataValidationResult::Valid); +} + void UOLSBaseLayerAnimInstance::NativeInitializeAnimation() { // Super::NativeInitializeAnimation(); diff --git a/Source/OLSAnimation/Public/AnimInstances/OLSBaseLayerAnimInstance.h b/Source/OLSAnimation/Public/AnimInstances/OLSBaseLayerAnimInstance.h index 7395536..85ffc7a 100644 --- a/Source/OLSAnimation/Public/AnimInstances/OLSBaseLayerAnimInstance.h +++ b/Source/OLSAnimation/Public/AnimInstances/OLSBaseLayerAnimInstance.h @@ -8,6 +8,7 @@ #include "Kismet/KismetMathLibrary.h" #include "Data/OLSAnimationData.h" #include "Data/OLSLocomotionData.h" +#include "GameplayEffectTypes.h" #include "OLSBaseLayerAnimInstance.generated.h" #if ENABLE_ANIM_DEBUG && ENABLE_VISUAL_LOG @@ -24,6 +25,16 @@ class OLSANIMATION_API UOLSBaseLayerAnimInstance : public UAnimInstance { GENERATED_BODY() +public: + + virtual void InitializeWithAbilitySystem(class UAbilitySystemComponent* asc); + +protected: + +#if WITH_EDITOR + virtual EDataValidationResult IsDataValid(class FDataValidationContext& context) const override; +#endif // WITH_EDITOR + protected: //~ Begin UAnimInstance overrides @@ -432,6 +443,14 @@ protected: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Settings|GameplayTagBindings") FGameplayTag MeleeGameplayTag = FGameplayTag::EmptyTag; +protected: + + // Gameplay tags that can be mapped to blueprint variables. The variables will automatically update as the tags are added or removed. + // These should be used instead of manually querying for the gameplay tags. + UPROPERTY(EditDefaultsOnly, Category = "GameplayTags") + FGameplayTagBlueprintPropertyMap GameplayTagPropertyMap; + + protected: UPROPERTY(BlueprintReadOnly) diff --git a/Source/OLSAnimationEditor/OLSAnimationEditor.Build.cs b/Source/OLSAnimationEditor/OLSAnimationEditor.Build.cs index 2e4b684..784527e 100644 --- a/Source/OLSAnimationEditor/OLSAnimationEditor.Build.cs +++ b/Source/OLSAnimationEditor/OLSAnimationEditor.Build.cs @@ -15,7 +15,5 @@ public class OLSAnimationEditor : ModuleRules PrivateDependencyModuleNames.AddRange(new string[] { "MessageLog" }); - - PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public/Nodes")); } } \ No newline at end of file diff --git a/Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp b/Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp new file mode 100644 index 0000000..f81f926 --- /dev/null +++ b/Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp @@ -0,0 +1,332 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "AbilitySystem/OLSAbilitySystemComponent.h" + +#include "AbilitySystemGlobals.h" +#include "GameplayCueManager.h" +#include "AbilitySystem/OLSBatchGameplayAbilityInterface.h" +#include "AbilitySystem/OLSGlobaAbilitySubsystem.h" +#include "AnimInstances/OLSBaseLayerAnimInstance.h" + + +// Sets default values for this component's properties +UOLSAbilitySystemComponent::UOLSAbilitySystemComponent() +{ + static constexpr bool isReplicated = true; + SetIsReplicatedByDefault(isReplicated); + + bShouldEnableBatchRPC = true; +} + +void UOLSAbilitySystemComponent::InitAbilityActorInfo(AActor* ownerActor, AActor* avatarActor) +{ + FGameplayAbilityActorInfo* actorInfo = AbilityActorInfo.Get(); + check(actorInfo); + check(ownerActor); + + // Guard condition to ensure we should clear/init for this new Avatar Actor. + const bool hasAvatarChanged = avatarActor && Cast(avatarActor) && (avatarActor != actorInfo->AvatarActor); + + Super::InitAbilityActorInfo(ownerActor, avatarActor); + + // Apply the new defaults obtained from the owner's interface. + if (hasAvatarChanged) + { + if (const TObjectPtr globalAbilitySystem = UWorld::GetSubsystem(GetWorld())) + { + globalAbilitySystem->RegisterASC(this); + } + + if (const TObjectPtr animInstance = Cast(GetAnimInstanceFromActorInfo())) + { + animInstance->InitializeWithAbilitySystem(this); + } + + TryActivateAbilitiesOnSpawn(); + } +} + +bool UOLSAbilitySystemComponent::ShouldDoServerAbilityRPCBatch() const +{ + return bShouldEnableBatchRPC; +} + +float UOLSAbilitySystemComponent::PlayMontage( + UGameplayAbility* animatingAbility, + FGameplayAbilityActivationInfo activationInfo, + UAnimMontage* montage, + float playRate, + FName startSectionName, + float startTimeSeconds) +{ + if (GEnableDefaultPlayMontage) + { + // Always useful to still allow the default flow, if there are some meaningful changes in the core system + // that were not yet reflect in this custom implementation. Can be enabled with CVar "GEnableDefaultPlayMontage". + // + return Super::PlayMontage(animatingAbility, activationInfo, montage, playRate, startSectionName, startTimeSeconds); + } + + float duration = -1.f; + + // This method was re-written just to ensure that the Animation Instance is retrieved from the Actor Info + // by default, but also, other scenarios can be supported. Biggest example being an IK Runtime Retarget. + // + // This virtual "GetAnimInstanceFromActorInfo" provides some flexibility on how the Anim Instance is + // retrieved. It can be extended in projects that should support IK Runtime Retargets and also traditional + // Anim Instances set in the Actor Info. + // + const TObjectPtr animInstance = GetAnimInstanceFromActorInfo(); + if (animInstance && montage) + { + duration = animInstance->Montage_Play( + montage, + playRate, + EMontagePlayReturnType::MontageLength, + startTimeSeconds); + if (duration > 0.f) + { + if (montage->HasRootMotion() && animInstance->GetOwningActor()) + { + UE_LOG(LogRootMotion, Log, TEXT("UAbilitySystemComponent::PlayMontage %s, Role: %s") + , *GetNameSafe(montage) + , *UEnum::GetValueAsString(TEXT("Engine.ENetRole"), animInstance->GetOwningActor()->GetLocalRole()) + ); + } + + LocalAnimMontageInfo.AnimMontage = montage; + LocalAnimMontageInfo.AnimatingAbility = animatingAbility; + LocalAnimMontageInfo.PlayInstanceId = (LocalAnimMontageInfo.PlayInstanceId < UINT8_MAX ? LocalAnimMontageInfo.PlayInstanceId + 1 : 0); + + if (animatingAbility) + { + animatingAbility->SetCurrentMontage(montage); + } + + // Start at a given Section. + if (startSectionName != NAME_None) + { + animInstance->Montage_JumpToSection(startSectionName, montage); + } + + // Replicate for non-owners and for replay recordings + // The data we set from GetRepAnimMontageInfo_Mutable() is used both by the server to replicate to clients and by clients to record replays. + // We need to set this data for recording clients because there exists network configurations where an abilities montage data will not replicate to some clients (for example: if the client is an autonomous proxy.) + if (ShouldRecordMontageReplication()) + { + FGameplayAbilityRepAnimMontage& mutableRepAnimMontageInfo = GetRepAnimMontageInfo_Mutable(); + SetReplicatedMontageInfo(mutableRepAnimMontageInfo, montage, startSectionName); + + // Update parameters that change during Montage lifetime. + AnimMontage_UpdateReplicatedData(); + } + + // Replicate to non-owners + if (IsOwnerActorAuthoritative()) + { + // Force net update on our avatar actor. + if (AbilityActorInfo->AvatarActor != nullptr) + { + AbilityActorInfo->AvatarActor->ForceNetUpdate(); + } + } + else + { + // If this prediction key is rejected, we need to end the preview + FPredictionKey predictionKey = GetPredictionKeyForNewAction(); + if (predictionKey.IsValidKey()) + { + predictionKey.NewRejectedDelegate().BindUObject(this, &ThisClass::OnPredictiveMontageRejected, montage); + } + } + } + } + + return duration; +} + +UAnimInstance* UOLSAbilitySystemComponent::GetAnimInstanceFromActorInfo() const +{ + if (!AbilityActorInfo.IsValid()) + { + return nullptr; + } + + const FGameplayAbilityActorInfo* actorInfo = AbilityActorInfo.Get(); + if (actorInfo->AnimInstance.IsValid() && actorInfo->AnimInstance->IsValidLowLevelFast()) + { + // Return the one that was deliberately set in the Actor Info. + return actorInfo->AnimInstance.Get(); + } + + // Otherwise, let the getter method try to figure out the animation instance. + return actorInfo->GetAnimInstance(); +} + +FActiveGameplayEffectHandle UOLSAbilitySystemComponent::ApplyGameplayEffectClassToSelf( + TSubclassOf effectClass, + float level) +{ + FActiveGameplayEffectHandle handle; + + if (IsValid(effectClass)) + { + FGameplayEffectContextHandle contextHandle = MakeEffectContext(); + contextHandle.AddSourceObject(GetOwner()); + + const FGameplayEffectSpecHandle specHandle = MakeOutgoingSpec(effectClass, level, contextHandle); + if (specHandle.IsValid()) + { + handle = ApplyGameplayEffectSpecToSelf(*specHandle.Data.Get()); + + //@Todo: replace this with our custom log. + UE_LOG(LogAbilitySystemComponent, Verbose, TEXT("[%s] Effect '%s' granted at level %f."), + *GetNameSafe(GetAvatarActor()), *GetNameSafe(effectClass), level); + } + } + + return handle; +} + +FGameplayAbilitySpecHandle UOLSAbilitySystemComponent::GiveAbilityFromClass( + const TSubclassOf abilityClass, + int32 level, + int32 input) +{ + FGameplayAbilitySpecHandle handle; + + if (IsValid(abilityClass)) + { + const FGameplayAbilitySpec newAbilitySpec(FGameplayAbilitySpec(abilityClass, level, input, GetOwner())); + handle = GiveAbility(newAbilitySpec); + + //@Todo: replace this with our custom log. + UE_LOG(LogAbilitySystemComponent, Log, TEXT("[%s] Ability '%s' %s at level %d."), + *GetNameSafe(GetAvatarActor()), *GetNameSafe(abilityClass), + handle.IsValid() ? TEXT("successfully granted") : TEXT("failed to be granted"), level); + } + + return handle; +} + +bool UOLSAbilitySystemComponent::TryBatchActivateAbility( + FGameplayAbilitySpecHandle abilityHandle, + bool shouldEndAbilityImmediately) +{ + bool isAbilityActivated = false; + if (abilityHandle.IsValid()) + { + //@Todo: replace this with our custom log. + // GAS_LOG(Warning, "Ability handle is invalid!"); + return isAbilityActivated; + } + + FScopedServerAbilityRPCBatcher batch(this, abilityHandle); + isAbilityActivated = TryActivateAbility(abilityHandle, true); + + if (!shouldEndAbilityImmediately) + { + const FGameplayAbilitySpec* abilitySpec = FindAbilitySpecFromHandle(abilityHandle); + if (abilitySpec != nullptr) + { + UGameplayAbility* ability = abilitySpec->GetPrimaryInstance(); + if (IsValid(ability) && ability->Implements()) + { + IOLSBatchGameplayAbilityInterface::Execute_EndAbilityFromBatch(ability); + } + else + { + // @Todo: replace this with our custom log. + // const FString Message = IsValid(Ability) ? FString::Printf(TEXT("%s does not implement Batch Gameplay Ability Interface"), *GetNameSafe(Ability)) : "is invalid"; + // GAS_LOG_ARGS(Error, "Ability %s!", *Message); + } + } + } + + return isAbilityActivated; +} + +void UOLSAbilitySystemComponent::CancelAbilitiesByTags( + FGameplayTagContainer abilityTags, + FGameplayTagContainer cancelFilterTags) +{ + CancelAbilities(&abilityTags, &cancelFilterTags); +} + +void UOLSAbilitySystemComponent::ExecuteGameplayCueLocal( + const FGameplayTag gameplayCueTag, + const FGameplayCueParameters& gameplayCueParameters) const +{ + const TObjectPtr cueManager = UAbilitySystemGlobals::Get().GetGameplayCueManager(); + cueManager->HandleGameplayCue( + GetOwner(), + gameplayCueTag, + EGameplayCueEvent::Type::Executed, + gameplayCueParameters); +} + +void UOLSAbilitySystemComponent::AddGameplayCueLocally( + const FGameplayTag gameplayCueTag, + const FGameplayCueParameters& gameplayCueParameters) const +{ + const TObjectPtr cueManager = UAbilitySystemGlobals::Get().GetGameplayCueManager(); + cueManager->HandleGameplayCue( + GetOwner(), + gameplayCueTag, + EGameplayCueEvent::Type::OnActive, + gameplayCueParameters); + cueManager->HandleGameplayCue( + GetOwner(), + gameplayCueTag, + EGameplayCueEvent::Type::WhileActive, + gameplayCueParameters); +} + +void UOLSAbilitySystemComponent::RemoveGameplayCueLocally( + const FGameplayTag gameplayCueTag, + const FGameplayCueParameters& gameplayCueParameters) const +{ + const TObjectPtr cueManager = UAbilitySystemGlobals::Get().GetGameplayCueManager(); + cueManager->HandleGameplayCue(GetOwner(), gameplayCueTag, EGameplayCueEvent::Type::Removed, gameplayCueParameters); +} + +void UOLSAbilitySystemComponent::TryActivateAbilitiesOnSpawn() +{ + ABILITYLIST_SCOPE_LOCK(); + + for (const FGameplayAbilitySpec& abilitySpec : GetActivatableAbilities()) + { + // if (const UOLS) + } +} + +void UOLSAbilitySystemComponent::SetReplicatedMontageInfo( + FGameplayAbilityRepAnimMontage& mutableRepAnimMontageInfo, + UAnimMontage* newMontageToPlay, + const FName& startSectionName) +{ + const uint8 playInstanceId = mutableRepAnimMontageInfo.PlayInstanceId < UINT8_MAX ? mutableRepAnimMontageInfo.PlayInstanceId + 1 : 0; + const uint8 sectionIdToPlay = newMontageToPlay->GetSectionIndex(startSectionName) + 1; + + TObjectPtr animation = newMontageToPlay; + if (newMontageToPlay->IsDynamicMontage()) + { + animation = newMontageToPlay->GetFirstAnimReference(); + + check(!newMontageToPlay->SlotAnimTracks.IsEmpty()); + mutableRepAnimMontageInfo.SlotName = newMontageToPlay->SlotAnimTracks[0].SlotName; + mutableRepAnimMontageInfo.BlendOutTime = newMontageToPlay->GetDefaultBlendInTime(); + } + + mutableRepAnimMontageInfo.Animation = animation; + mutableRepAnimMontageInfo.PlayInstanceId = playInstanceId; + + mutableRepAnimMontageInfo.SectionIdToPlay = 0; + if (mutableRepAnimMontageInfo.Animation && startSectionName != NAME_None) + { + mutableRepAnimMontageInfo.SectionIdToPlay = sectionIdToPlay; + } +} + + diff --git a/Source/ols/Private/AbilitySystem/OLSBatchGameplayAbilityInterface.cpp b/Source/ols/Private/AbilitySystem/OLSBatchGameplayAbilityInterface.cpp new file mode 100644 index 0000000..b7ed238 --- /dev/null +++ b/Source/ols/Private/AbilitySystem/OLSBatchGameplayAbilityInterface.cpp @@ -0,0 +1,7 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "AbilitySystem/OLSBatchGameplayAbilityInterface.h" + + +// Add default functionality here for any IOLSBatchGameplayAbilityInterface functions that are not pure virtual. diff --git a/Source/ols/Private/AbilitySystem/OLSGlobaAbilitySubsystem.cpp b/Source/ols/Private/AbilitySystem/OLSGlobaAbilitySubsystem.cpp new file mode 100644 index 0000000..7b27d19 --- /dev/null +++ b/Source/ols/Private/AbilitySystem/OLSGlobaAbilitySubsystem.cpp @@ -0,0 +1,110 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "AbilitySystem/OLSGlobaAbilitySubsystem.h" + +#include "Abilities/GameplayAbility.h" +#include "AbilitySystem/OLSAbilitySystemComponent.h" + +void FOLSGlobalAppliedAbilityList::AddToASC(TSubclassOf ability, UOLSAbilitySystemComponent* asc) +{ + if (FGameplayAbilitySpecHandle* specHandle = Handles.Find(asc)) + { + RemoveFromASC(asc); + } + + UGameplayAbility* abilityCDO = ability->GetDefaultObject(); + FGameplayAbilitySpec abilitySpec(abilityCDO); + const FGameplayAbilitySpecHandle abilitySpecHandle = asc->GiveAbility(abilitySpec); + Handles.Add(asc, abilitySpecHandle); +} + +void FOLSGlobalAppliedAbilityList::RemoveFromASC(UOLSAbilitySystemComponent* asc) +{ + if (FGameplayAbilitySpecHandle* specHandle = Handles.Find(asc)) + { + asc->ClearAbility(*specHandle); + Handles.Remove(asc); + } +} + +void FOLSGlobalAppliedAbilityList::RemoveFromAll() +{ + + for (TTuple, FGameplayAbilitySpecHandle>& handle : Handles) + { + if (handle.Key != nullptr) + { + handle.Key->ClearAbility(handle.Value); + } + } + + Handles.Empty(); +} + +void FOLSGlobalAppliedEffectList::AddToASC(const TSubclassOf& effect, UOLSAbilitySystemComponent* asc) +{ + if (FActiveGameplayEffectHandle* effectHandle = Handles.Find(asc)) + { + RemoveFromASC(asc); + } + + const UGameplayEffect* gameplayEffectCDO = effect->GetDefaultObject(); + const FActiveGameplayEffectHandle gameplayEffectHandle = asc->ApplyGameplayEffectToSelf(gameplayEffectCDO, /*Level=*/ 1, asc->MakeEffectContext()); + Handles.Add(asc, gameplayEffectHandle); +} + +void FOLSGlobalAppliedEffectList::RemoveFromASC(UOLSAbilitySystemComponent* asc) +{ + if (FActiveGameplayEffectHandle* effectHandle = Handles.Find(asc)) + { + asc->RemoveActiveGameplayEffect(*effectHandle); + Handles.Remove(asc); + } +} + +void FOLSGlobalAppliedEffectList::RemoveFromAll() +{ + for (TTuple, FActiveGameplayEffectHandle>& handle : Handles) + { + if (handle.Key != nullptr) + { + handle.Key->RemoveActiveGameplayEffect(handle.Value); + } + } + Handles.Empty(); +} + +void UOLSGlobaAbilitySubsystem::RegisterASC(UOLSAbilitySystemComponent* asc) +{ + check(asc); + + for (TTuple, FOLSGlobalAppliedAbilityList>& appliedAbility : AppliedAbilities) + { + appliedAbility.Value.AddToASC(appliedAbility.Key, asc); + } + + for (TTuple, FOLSGlobalAppliedEffectList>& appliedEffect : AppliedEffects) + { + appliedEffect.Value.AddToASC(appliedEffect.Key, asc); + } + + RegisteredASCs.AddUnique(asc); +} + +void UOLSGlobaAbilitySubsystem::UnregisterASC(UOLSAbilitySystemComponent* asc) +{ + check(asc); + + for (auto& appliedAbility : AppliedAbilities) + { + appliedAbility.Value.RemoveFromASC(asc); + } + + for (auto& appliedEffect : AppliedEffects) + { + appliedEffect.Value.RemoveFromASC(asc); + } + + RegisteredASCs.Remove(asc); +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularAIController.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularAIController.cpp new file mode 100644 index 0000000..7c73a91 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularAIController.cpp @@ -0,0 +1,24 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularAIController.h" + +#include "Components/GameFrameworkComponentManager.h" + +void AOLSModularAIController::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularAIController::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularAIController::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularActor.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularActor.cpp new file mode 100644 index 0000000..5450d59 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularActor.cpp @@ -0,0 +1,100 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularActor.h" + +#include "AbilitySystem/OLSAbilitySystemComponent.h" +#include "Components/GameFrameworkComponentManager.h" + +AOLSModularActor::AOLSModularActor(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ + // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + // Set this actor to replicate like a Pawn would + bReplicates = true; + + // Set Ability System Companion with GAS Companion subclass + AbilitySystemComponent = CreateDefaultSubobject(TEXT("AbilitySystemComponent")); + AbilitySystemComponent->SetIsReplicated(true); + + ReplicationMode = EGameplayEffectReplicationMode::Mixed; +} + +void AOLSModularActor::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularActor::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + + Super::BeginPlay(); +} + +void AOLSModularActor::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + + Super::EndPlay(endPlayReason); +} + +void AOLSModularActor::PostInitProperties() +{ + Super::PostInitProperties(); + + if (AbilitySystemComponent) + { + //@Todo replace this log by our custom log. + UE_LOG(LogTemp, Verbose, TEXT("PostInitProperties for %s - Setting up ASC Replication Mode to: %d"), *GetName(), ReplicationMode); + AbilitySystemComponent->SetReplicationMode(ReplicationMode); + } +} + +UAbilitySystemComponent* AOLSModularActor::GetAbilitySystemComponent() const +{ + return AbilitySystemComponent; +} + +void AOLSModularActor::GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const +{ + if (AbilitySystemComponent) + { + FGameplayTagContainer ownedTags; + AbilitySystemComponent->GetOwnedGameplayTags(ownedTags); + outTagContainer = MoveTemp(ownedTags); + } +} + +bool AOLSModularActor::HasMatchingGameplayTag(FGameplayTag tagToCheck) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasMatchingGameplayTag(tagToCheck); + } + + return false; +} + +bool AOLSModularActor::HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAllMatchingGameplayTags(tagContainer); + } + + return false; +} + +bool AOLSModularActor::HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAnyMatchingGameplayTags(tagContainer); + } + + return false; +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularCharacter.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularCharacter.cpp new file mode 100644 index 0000000..864c243 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularCharacter.cpp @@ -0,0 +1,98 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularCharacter.h" + +#include "AbilitySystem/OLSAbilitySystemComponent.h" +#include "Components/GameFrameworkComponentManager.h" + +AOLSModularCharacter::AOLSModularCharacter(const FObjectInitializer& objectInitializer) +{ + // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + // Set this actor to replicate like a Pawn would + bReplicates = true; + + // Set Ability System Companion with GAS Companion subclass + AbilitySystemComponent = CreateDefaultSubobject(TEXT("AbilitySystemComponent")); + AbilitySystemComponent->SetIsReplicated(true); + + ReplicationMode = EGameplayEffectReplicationMode::Mixed; +} + +void AOLSModularCharacter::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularCharacter::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent( + this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularCharacter::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} + +void AOLSModularCharacter::PostInitProperties() +{ + Super::PostInitProperties(); + + if (AbilitySystemComponent) + { + //@Todo replace this log by our custom log. + UE_LOG(LogTemp, Verbose, TEXT("PostInitProperties for %s - Setting up ASC Replication Mode to: %d"), *GetName(), ReplicationMode); + AbilitySystemComponent->SetReplicationMode(ReplicationMode); + } +} + +UAbilitySystemComponent* AOLSModularCharacter::GetAbilitySystemComponent() const +{ + return AbilitySystemComponent; +} + +void AOLSModularCharacter::GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const +{ + if (AbilitySystemComponent) + { + FGameplayTagContainer ownedTags; + AbilitySystemComponent->GetOwnedGameplayTags(ownedTags); + outTagContainer = MoveTemp(ownedTags); + } +} + +bool AOLSModularCharacter::HasMatchingGameplayTag(FGameplayTag tagToCheck) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasMatchingGameplayTag(tagToCheck); + } + + return false; +} + +bool AOLSModularCharacter::HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAllMatchingGameplayTags(tagContainer); + } + + return false; +} + +bool AOLSModularCharacter::HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAnyMatchingGameplayTags(tagContainer); + } + + return false; +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularDefaultPawn.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularDefaultPawn.cpp new file mode 100644 index 0000000..9849680 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularDefaultPawn.cpp @@ -0,0 +1,100 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularDefaultPawn.h" + +#include "AbilitySystem/OLSAbilitySystemComponent.h" +#include "Components/GameFrameworkComponentManager.h" + + +// Sets default values +AOLSModularDefaultPawn::AOLSModularDefaultPawn(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ + // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + // Set this actor to replicate like a Pawn would + bReplicates = true; + + // Set Ability System Companion with GAS Companion subclass + AbilitySystemComponent = CreateDefaultSubobject(TEXT("AbilitySystemComponent")); + AbilitySystemComponent->SetIsReplicated(true); + + ReplicationMode = EGameplayEffectReplicationMode::Mixed; +} + +void AOLSModularDefaultPawn::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularDefaultPawn::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent( + this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularDefaultPawn::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} + +void AOLSModularDefaultPawn::PostInitProperties() +{ + Super::PostInitProperties(); + if (AbilitySystemComponent) + { + //@Todo replace this log by our custom log. + UE_LOG(LogTemp, Verbose, TEXT("PostInitProperties for %s - Setting up ASC Replication Mode to: %d"), *GetName(), + ReplicationMode); + AbilitySystemComponent->SetReplicationMode(ReplicationMode); + } +} + +UAbilitySystemComponent* AOLSModularDefaultPawn::GetAbilitySystemComponent() const +{ + return AbilitySystemComponent; +} + +void AOLSModularDefaultPawn::GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const +{ + if (AbilitySystemComponent) + { + FGameplayTagContainer ownedTags; + AbilitySystemComponent->GetOwnedGameplayTags(ownedTags); + outTagContainer = MoveTemp(ownedTags); + } +} + +bool AOLSModularDefaultPawn::HasMatchingGameplayTag(FGameplayTag tagToCheck) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasMatchingGameplayTag(tagToCheck); + } + + return false; +} + +bool AOLSModularDefaultPawn::HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAllMatchingGameplayTags(tagContainer); + } + + return false; +} + +bool AOLSModularDefaultPawn::HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAnyMatchingGameplayTags(tagContainer); + } + + return false; +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularGameMode.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularGameMode.cpp new file mode 100644 index 0000000..67e856d --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularGameMode.cpp @@ -0,0 +1,20 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularGameMode.h" + +AOLSModularGameModeBase::AOLSModularGameModeBase() +{ + // GameStateClass = AGSCModularGameStateBase::StaticClass(); + // PlayerControllerClass = AGSCModularPlayerController::StaticClass(); + // PlayerStateClass = APlayerState::StaticClass(); + // DefaultPawnClass = AGSCModularCharacter::StaticClass(); +} + +AOLSModularGameMode::AOLSModularGameMode() +{ + // GameStateClass = AGSCModularGameState::StaticClass(); + // PlayerControllerClass = AGSCModularPlayerController::StaticClass(); + // PlayerStateClass = APlayerState::StaticClass(); + // DefaultPawnClass = AGSCModularCharacter::StaticClass(); +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularGameState.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularGameState.cpp new file mode 100644 index 0000000..8e18bd7 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularGameState.cpp @@ -0,0 +1,55 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularGameState.h" + +#include "Components/GameFrameworkComponentManager.h" +#include "Components/GameStateComponent.h" + +void AOLSModularGameStateBase::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularGameStateBase::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularGameStateBase::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} + +void AOLSModularGameState::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularGameState::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularGameState::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} + +void AOLSModularGameState::HandleMatchHasStarted() +{ + Super::HandleMatchHasStarted(); + + TArray modularComponents; + GetComponents(modularComponents); + for (UGameStateComponent* component : modularComponents) + { + component->HandleMatchHasStarted(); + } +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularPawn.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularPawn.cpp new file mode 100644 index 0000000..a39f704 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularPawn.cpp @@ -0,0 +1,90 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularPawn.h" + +#include "AbilitySystem/OLSAbilitySystemComponent.h" +#include "Components/GameFrameworkComponentManager.h" + +AOLSModularPawn::AOLSModularPawn(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ + AbilitySystemComponent = CreateDefaultSubobject(TEXT("AbilitySystemComponent")); + AbilitySystemComponent->SetIsReplicated(true); + + ReplicationMode = EGameplayEffectReplicationMode::Mixed; +} + +void AOLSModularPawn::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularPawn::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularPawn::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} + +void AOLSModularPawn::PostInitProperties() +{ + Super::PostInitProperties(); + + if (AbilitySystemComponent) + { + //@Todo replace this log by our custom log. + UE_LOG(LogTemp, Verbose, TEXT("PostInitProperties for %s - Setting up ASC Replication Mode to: %d"), *GetName(), ReplicationMode); + AbilitySystemComponent->SetReplicationMode(ReplicationMode); + } +} + +UAbilitySystemComponent* AOLSModularPawn::GetAbilitySystemComponent() const +{ + return AbilitySystemComponent; +} + +void AOLSModularPawn::GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const +{ + if (AbilitySystemComponent) + { + FGameplayTagContainer ownedTags; + AbilitySystemComponent->GetOwnedGameplayTags(ownedTags); + outTagContainer = MoveTemp(ownedTags); + } +} + +bool AOLSModularPawn::HasMatchingGameplayTag(FGameplayTag tagToCheck) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasMatchingGameplayTag(tagToCheck); + } + + return false; +} + +bool AOLSModularPawn::HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAllMatchingGameplayTags(tagContainer); + } + + return false; +} + +bool AOLSModularPawn::HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent) + { + return AbilitySystemComponent->HasAnyMatchingGameplayTags(tagContainer); + } + + return false; +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularPlayerController.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularPlayerController.cpp new file mode 100644 index 0000000..b797178 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularPlayerController.cpp @@ -0,0 +1,46 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularPlayerController.h" + +#include "Components/GameFrameworkComponentManager.h" +#include "Components/ControllerComponent.h" + +void AOLSModularPlayerController::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularPlayerController::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} + +void AOLSModularPlayerController::ReceivedPlayer() +{ + // Player controllers always get assigned a player and can't do much until then + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent( + this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::ReceivedPlayer(); + + TArray modularComponents; + GetComponents(modularComponents); + for (UControllerComponent* component : modularComponents) + { + component->ReceivedPlayer(); + } +} + +void AOLSModularPlayerController::PlayerTick(float deltaTime) +{ + Super::PlayerTick(deltaTime); + + TArray modularComponents; + GetComponents(modularComponents); + for (UControllerComponent* component : modularComponents) + { + component->PlayerTick(deltaTime); + } +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularPlayerState.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularPlayerState.cpp new file mode 100644 index 0000000..806d22b --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularPlayerState.cpp @@ -0,0 +1,80 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularPlayerState.h" + +#include "AbilitySystem/OLSAbilitySystemComponent.h" +#include "Components/GameFrameworkComponentManager.h" +#include "Components/PlayerStateComponent.h" + +AOLSModularPlayerState::AOLSModularPlayerState(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ + // Create ability system component, and set it to be explicitly replicated + AbilitySystemComponent = CreateDefaultSubobject(TEXT("AbilitySystemComponent")); + AbilitySystemComponent->SetIsReplicated(true); + + SetNetUpdateFrequency(100.f); +} + +void AOLSModularPlayerState::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularPlayerState::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularPlayerState::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(EndPlayReason); +} + +void AOLSModularPlayerState::PostInitProperties() +{ + Super::PostInitProperties(); + + if (AbilitySystemComponent) + { + //@Todo replace this log by our custom log. + UE_LOG(LogTemp, Verbose, TEXT("PostInitProperties for %s - Setting up ASC Replication Mode to: %d"), *GetName(), ReplicationMode); + AbilitySystemComponent->SetReplicationMode(ReplicationMode); + } +} + +void AOLSModularPlayerState::Reset() +{ + Super::Reset(); + + TArray modularComponents; + GetComponents(modularComponents); + for (UPlayerStateComponent* component : modularComponents) + { + component->Reset(); + } +} + +UAbilitySystemComponent* AOLSModularPlayerState::GetAbilitySystemComponent() const +{ + return AbilitySystemComponent; +} + +void AOLSModularPlayerState::CopyProperties(APlayerState* playerState) +{ + Super::CopyProperties(playerState); + + TInlineComponentArray playerStateComponents; + GetComponents(playerStateComponents); + for (UPlayerStateComponent* sourceComponent : playerStateComponents) + { + if (UPlayerStateComponent* targetComp = Cast(static_cast(FindObjectWithOuter(playerState, sourceComponent->GetClass(), sourceComponent->GetFName())))) + { + sourceComponent->CopyProperties(targetComp); + } + } +} diff --git a/Source/ols/Private/ModularGameplayActors/OLSModularPlayerStateCharacter.cpp b/Source/ols/Private/ModularGameplayActors/OLSModularPlayerStateCharacter.cpp new file mode 100644 index 0000000..082c033 --- /dev/null +++ b/Source/ols/Private/ModularGameplayActors/OLSModularPlayerStateCharacter.cpp @@ -0,0 +1,121 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "ModularGameplayActors/OLSModularPlayerStateCharacter.h" + +#include "AbilitySystemComponent.h" +#include "AbilitySystemGlobals.h" +#include "Components/GameFrameworkComponentManager.h" +#include "GameFramework/PlayerState.h" + +AOLSModularPlayerStateCharacter::AOLSModularPlayerStateCharacter(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ + SetMinNetUpdateFrequency(33.f); + SetNetUpdateFrequency(66.f); + + ReplicationMode = EGameplayEffectReplicationMode::Mixed; +} + +void AOLSModularPlayerStateCharacter::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this); +} + +void AOLSModularPlayerStateCharacter::BeginPlay() +{ + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + Super::BeginPlay(); +} + +void AOLSModularPlayerStateCharacter::EndPlay(const EEndPlayReason::Type endPlayReason) +{ + UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); + Super::EndPlay(endPlayReason); +} + +void AOLSModularPlayerStateCharacter::PostInitProperties() +{ + Super::PostInitProperties(); + + if (AbilitySystemComponent.IsValid()) + { + //@Todo replace this log by our custom log. + UE_LOG(LogTemp, Verbose, TEXT("PostInitProperties for %s - Setting up ASC Replication Mode to: %d"), *GetName(), ReplicationMode); + AbilitySystemComponent->SetReplicationMode(ReplicationMode); + } +} + +void AOLSModularPlayerStateCharacter::PossessedBy(AController* newController) +{ + Super::PossessedBy(newController); + + // For Player State ASC Pawns, initialize ASC on server in PossessedBy + if (TObjectPtr playerState = GetPlayerState()) + { + AbilitySystemComponent = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(playerState); + if (AbilitySystemComponent.IsValid()) + { + AbilitySystemComponent->InitAbilityActorInfo(playerState, this); + // TODO: Might consider sending GFC extension event in InitAbilityActorInfo instead + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); + + // Required for ability input binding to update itself when ability are granted again in case of a respawn + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(playerState, UGameFrameworkComponentManager::NAME_GameActorReady); + } + } +} + +void AOLSModularPlayerStateCharacter::OnRep_PlayerState() +{ + Super::OnRep_PlayerState(); +} + +UAbilitySystemComponent* AOLSModularPlayerStateCharacter::GetAbilitySystemComponent() const +{ + if (AbilitySystemComponent.IsValid()) + { + return AbilitySystemComponent.Get(); + } + return nullptr; +} + +void AOLSModularPlayerStateCharacter::GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const +{ + if (AbilitySystemComponent.IsValid()) + { + FGameplayTagContainer ownedTags; + AbilitySystemComponent->GetOwnedGameplayTags(ownedTags); + outTagContainer = MoveTemp(ownedTags); + } +} + +bool AOLSModularPlayerStateCharacter::HasMatchingGameplayTag(FGameplayTag tagToCheck) const +{ + if (AbilitySystemComponent.IsValid()) + { + return AbilitySystemComponent->HasMatchingGameplayTag(tagToCheck); + } + + return false; +} + +bool AOLSModularPlayerStateCharacter::HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent.IsValid()) + { + return AbilitySystemComponent->HasAllMatchingGameplayTags(tagContainer); + } + + return false; +} + +bool AOLSModularPlayerStateCharacter::HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const +{ + if (AbilitySystemComponent.IsValid()) + { + return AbilitySystemComponent->HasAnyMatchingGameplayTags(tagContainer); + } + + return false; +} diff --git a/Source/ols/Private/Player/OLSPlayerController.cpp b/Source/ols/Private/Player/OLSPlayerController.cpp new file mode 100644 index 0000000..ef4a381 --- /dev/null +++ b/Source/ols/Private/Player/OLSPlayerController.cpp @@ -0,0 +1,4 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "Player/OLSPlayerController.h" diff --git a/Source/ols/Private/Player/OLSPlayerState.cpp b/Source/ols/Private/Player/OLSPlayerState.cpp new file mode 100644 index 0000000..05aad1c --- /dev/null +++ b/Source/ols/Private/Player/OLSPlayerState.cpp @@ -0,0 +1,40 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + + +#include "Player/OLSPlayerState.h" + +#include "AbilitySystem/OLSAbilitySystemComponent.h" +#include "Player/OLSPlayerController.h" + +AOLSPlayerState::AOLSPlayerState(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ + // Create attribute sets here. +} + +void AOLSPlayerState::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + + check(AbilitySystemComponent); + AbilitySystemComponent->InitAbilityActorInfo(this, GetPawn()); + + const TObjectPtr world = GetWorld(); + if (world && world->IsGameWorld() && world->GetNetMode() != NM_Client) + { + const TObjectPtr gameState = GetWorld()->GetGameState(); + check(gameState); + // ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass(); + // check(ExperienceComponent); + // ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded)); + } +} + +AOLSPlayerController* AOLSPlayerState::GetOLSPlayerController() const +{ + return Cast(GetOwner()); +} + +UOLSAbilitySystemComponent* AOLSPlayerState::GetOLSAbilitySystemComponent() const +{ + return AbilitySystemComponent; +} diff --git a/Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h b/Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h new file mode 100644 index 0000000..1cf70c9 --- /dev/null +++ b/Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h @@ -0,0 +1,162 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "OLSAbilitySystemComponent.generated.h" + +/** + * CVAR to control the "Play Montage" flow. + * Example: OLS.EnableDefaultPlayMontage true + */ +static bool GEnableDefaultPlayMontage = false; +static FAutoConsoleVariableRef CVarEnableDefaultPlayMontage( + TEXT("OLS.EnableDefaultPlayMontage"), + GEnableDefaultPlayMontage, + TEXT("Enables or disables the PlayMontage default behavior."), + ECVF_Default +); + +UCLASS(ClassGroup=(OLS), meta=(BlueprintSpawnableComponent)) +class OLS_API UOLSAbilitySystemComponent : public UAbilitySystemComponent +{ + GENERATED_BODY() + +public: + + // Sets default values for this component's properties + UOLSAbilitySystemComponent(); + + // -- Begin Ability System Component implementation + virtual void InitAbilityActorInfo( + AActor* ownerActor, + AActor* avatarActor) override; + virtual bool ShouldDoServerAbilityRPCBatch() const override; + virtual float PlayMontage( + UGameplayAbility* animatingAbility, + FGameplayAbilityActivationInfo activationInfo, + UAnimMontage* montage, + float playRate, + FName startSectionName, + float startTimeSeconds) override; + // -- End Ability System Component implementation + + +public: + + /** + * Obtains the Anim Instance from the Actor Info. + * + * Takes into consideration the pointer in the Actor Info, before calling the + * Getter function that will always attempt to retrieve it from the mesh. + */ + UFUNCTION(BlueprintPure, Category = "OLS Ability System") + virtual UAnimInstance* GetAnimInstanceFromActorInfo() const; + + /** + * Grants a new effect to the owner. + * + * @param effectClass Effect class being granted to the owner. + * @param level Initial level for the effect. + * @return The handle that can be used for maintenance. + */ + UFUNCTION(BlueprintCallable, Category = "OLS Ability System") + FActiveGameplayEffectHandle ApplyGameplayEffectClassToSelf( + TSubclassOf effectClass, + float level = 1); + + /** + * Grants a new ability to the owner. + * + * @param abilityClass Ability class being granted to the owner. + * @param level Initial level for the ability. + * @param input An Input ID for the old input system. + * @return The handle that can be used for activation. + */ + UFUNCTION(BlueprintCallable, Category = "OLS Ability System") + FGameplayAbilitySpecHandle GiveAbilityFromClass( + const TSubclassOf abilityClass, + int32 level = 1, + int32 input = -1); + + /** + * Tries to activate the ability by the handle, aggregating all RPCs that happened in the same frame. + * + * @param abilityHandle + * Handle used to identify the ability. + * + * @param shouldEndAbilityImmediately + * Determines if the EndAbility is triggered right away or later, with its own RPC. This requires the Ability + * to either implement IBatchGameplayAbilityInterface or be a subclass of NinjaGASGameplayAbility. + */ + UFUNCTION(BlueprintCallable, Category = "OLS Ability System") + virtual bool TryBatchActivateAbility( + FGameplayAbilitySpecHandle abilityHandle, + bool shouldEndAbilityImmediately); + + /** + * Cancels Gameplay Abilities by their matching tags. + * + * @param abilityTags Gameplay Tags used to target abilities to cancel. + * @param cancelFilterTags A filter that excludes an ability from being cancelled. + */ + UFUNCTION(BlueprintCallable, Category = "OLS Ability System") + virtual void CancelAbilitiesByTags( + FGameplayTagContainer abilityTags, + FGameplayTagContainer cancelFilterTags); + + /** + * Locally executes a Static Gameplay Cue. + * + * @param gameplayCueTag Gameplay Tag for the Gameplay Cue. + * @param gameplayCueParameters Parameters for the Gameplay Cue. + */ + UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "OLS Ability System", meta = (AutoCreateRefTerm = "GameplayCueParameters", GameplayTagFilter = "GameplayCue")) + void ExecuteGameplayCueLocal( + const FGameplayTag gameplayCueTag, + const FGameplayCueParameters& gameplayCueParameters) const; + + /** + * Locally adds an Actor Gameplay Cue. + * + * When adding this Gameplay Cue locally, make sure to also remove it locally. + * + * @param gameplayCueTag Gameplay Tag for the Gameplay Cue. + * @param gameplayCueParameters Parameters for the Gameplay Cue. + */ + UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "OLS Ability System", meta = (AutoCreateRefTerm = "GameplayCueParameters")) + void AddGameplayCueLocally( + UPARAM(meta = (Categories = "GameplayCue")) const FGameplayTag gameplayCueTag, + const FGameplayCueParameters& gameplayCueParameters) const; + + /** + * Locally removes an Actor Gameplay Cue. + * + * @param gameplayCueTag Gameplay Tag for the Gameplay Cue. + * @param gameplayCueParameters Parameters for the Gameplay Cue. + */ + UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category = "OLS Ability System", meta = (AutoCreateRefTerm = "GameplayCueParameters")) + void RemoveGameplayCueLocally( + UPARAM(meta = (Categories = "GameplayCue")) const FGameplayTag gameplayCueTag, + const FGameplayCueParameters& gameplayCueParameters) const; + + +protected: + + /** + * Attempts to activate any abilities that are set to automatically trigger upon the actor's spawn. + * Typically used for gameplay abilities that need to be initialized or activated as soon as the actor is created. + */ + void TryActivateAbilitiesOnSpawn(); + + /** + * Conveniently separates the code that sets the animation to replicate, so it can be further modified. + */ + virtual void SetReplicatedMontageInfo(FGameplayAbilityRepAnimMontage& mutableRepAnimMontageInfo, UAnimMontage* newMontageToPlay, const FName& startSectionName); + +private: + + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "OLS Ability System", DisplayName = "Enable Ability Batch RPCs", meta = (AllowPrivateAccess = true)) + uint8 bShouldEnableBatchRPC : 1 = true; +}; diff --git a/Source/ols/Public/AbilitySystem/OLSBatchGameplayAbilityInterface.h b/Source/ols/Public/AbilitySystem/OLSBatchGameplayAbilityInterface.h new file mode 100644 index 0000000..198b481 --- /dev/null +++ b/Source/ols/Public/AbilitySystem/OLSBatchGameplayAbilityInterface.h @@ -0,0 +1,30 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Interface.h" +#include "OLSBatchGameplayAbilityInterface.generated.h" + +// This class does not need to be modified. +UINTERFACE(MinimalAPI) +class UOLSBatchGameplayAbilityInterface : public UInterface +{ + GENERATED_BODY() +}; + +/** + * + */ +class OLS_API IOLSBatchGameplayAbilityInterface +{ + GENERATED_BODY() + +public: + + /** + * Analogous to "K2_EndAbility" function, but exposed to identify that this is triggered by a batched RPC. + */ + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "OLS | Batch Gameplay Ability") + void EndAbilityFromBatch(); +}; diff --git a/Source/ols/Public/AbilitySystem/OLSGlobaAbilitySubsystem.h b/Source/ols/Public/AbilitySystem/OLSGlobaAbilitySubsystem.h new file mode 100644 index 0000000..eddabe9 --- /dev/null +++ b/Source/ols/Public/AbilitySystem/OLSGlobaAbilitySubsystem.h @@ -0,0 +1,64 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "Subsystems/WorldSubsystem.h" + +#include "GameplayAbilitySpecHandle.h" +#include "ActiveGameplayEffectHandle.h" +#include "OLSGlobaAbilitySubsystem.generated.h" + +USTRUCT() +struct FOLSGlobalAppliedAbilityList +{ + GENERATED_BODY() + + UPROPERTY() + TMap, FGameplayAbilitySpecHandle> Handles; + + void AddToASC(TSubclassOf ability, class UOLSAbilitySystemComponent* asc); + void RemoveFromASC(class UOLSAbilitySystemComponent* asc); + void RemoveFromAll(); +}; + +USTRUCT() +struct FOLSGlobalAppliedEffectList +{ + GENERATED_BODY() + + UPROPERTY() + TMap, FActiveGameplayEffectHandle> Handles; + + void AddToASC(const TSubclassOf& effect, class UOLSAbilitySystemComponent* asc); + void RemoveFromASC(class UOLSAbilitySystemComponent* asc); + void RemoveFromAll(); +}; + +/** + * + */ +UCLASS() +class OLS_API UOLSGlobaAbilitySubsystem : public UWorldSubsystem +{ + GENERATED_BODY() + +public: + + /** Register an ASC with global system and apply any active global effects/abilities. */ + void RegisterASC(class UOLSAbilitySystemComponent* asc); + + /** Removes an ASC from the global system, along with any active global effects/abilities. */ + void UnregisterASC(class UOLSAbilitySystemComponent* asc); + +private: + + UPROPERTY() + TMap, FOLSGlobalAppliedAbilityList> AppliedAbilities; + + UPROPERTY() + TMap, FOLSGlobalAppliedEffectList> AppliedEffects; + + UPROPERTY() + TArray> RegisteredASCs; +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularAIController.h b/Source/ols/Public/ModularGameplayActors/OLSModularAIController.h new file mode 100644 index 0000000..4f8746c --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularAIController.h @@ -0,0 +1,23 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "AIController.h" +#include "OLSModularAIController.generated.h" + +/** + * + */ +UCLASS(Blueprintable) +class OLS_API AOLSModularAIController : public AAIController +{ + GENERATED_BODY() + +public: + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + // -- End Actor Implementation +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularActor.h b/Source/ols/Public/ModularGameplayActors/OLSModularActor.h new file mode 100644 index 0000000..7422a13 --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularActor.h @@ -0,0 +1,62 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "AbilitySystemInterface.h" +#include "GameplayTagAssetInterface.h" +#include "GameFramework/Actor.h" +#include "OLSModularActor.generated.h" + +/** Minimal class that supports extension by game feature plugins, direct child of AActor */ +UCLASS(Blueprintable) +class OLS_API AOLSModularActor : public AActor, public IAbilitySystemInterface, public IGameplayTagAssetInterface +{ + GENERATED_BODY() + +public: + + // Sets default values for this actor's properties + AOLSModularActor(const FObjectInitializer& objectInitializer); + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + virtual void PostInitProperties() override; + // -- End Actor Implementation + + // -- Begin IAbilitySystemInterface implementation + virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override; + // -- End IAbilitySystemInterface implementation + + // -- Begin IGameplayTagAssetInterface + virtual void GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const override; + virtual bool HasMatchingGameplayTag(FGameplayTag tagToCheck) const override; + virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + // -- End IGameplayTagAssetInterface + +protected: + + /** + * Ability System Replication Mode: How gameplay effects will be replicated to clients + * + * - Full: Replicate full gameplay info to all. Every GameplayEffect is replicated to every client. + * (Recommended for Single Player games) + * - Mixed: Only replicate minimal gameplay effect info to simulated proxies but full info to owners and autonomous proxies. + * GameplayEffects are only replicated to the owning client. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on Player controlled Actors) + * - Minimal: Only replicate minimal gameplay effect info. Note: this does not work for Owned AbilitySystemComponents (Use Mixed instead). + * GameplayEffects are never replicated to anyone. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on AI controlled Actors) + * + * @See https://github.com/tranek/GASDocumentation#concepts-asc-rm for more information + */ + UPROPERTY(EditDefaultsOnly, Category = "OLS Ability System") + EGameplayEffectReplicationMode ReplicationMode; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OLS Ability System") + TObjectPtr AbilitySystemComponent = nullptr; +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularCharacter.h b/Source/ols/Public/ModularGameplayActors/OLSModularCharacter.h new file mode 100644 index 0000000..b761bcc --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularCharacter.h @@ -0,0 +1,65 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "AbilitySystemInterface.h" +#include "GameplayTagAssetInterface.h" +#include "GameFramework/Character.h" +#include "OLSModularCharacter.generated.h" + +/** + * Minimal class that supports extension by game feature plugins + * + * Intended to be used for ACharacters using AbilitySystemComponent living on Pawns + */ +UCLASS(Blueprintable) +class OLS_API AOLSModularCharacter : public ACharacter, public IAbilitySystemInterface, public IGameplayTagAssetInterface +{ + GENERATED_BODY() + +public: + // Sets default values for this character's properties + AOLSModularCharacter(const FObjectInitializer& objectInitializer); + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + virtual void PostInitProperties() override; + // -- End Actor Implementation + + // -- Begin IAbilitySystemInterface implementation + virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override; + // -- End IAbilitySystemInterface implementation + + // -- Begin IGameplayTagAssetInterface + virtual void GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const override; + virtual bool HasMatchingGameplayTag(FGameplayTag tagToCheck) const override; + virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + // -- End IGameplayTagAssetInterface + +protected: + + /** + * Ability System Replication Mode: How gameplay effects will be replicated to clients + * + * - Full: Replicate full gameplay info to all. Every GameplayEffect is replicated to every client. + * (Recommended for Single Player games) + * - Mixed: Only replicate minimal gameplay effect info to simulated proxies but full info to owners and autonomous proxies. + * GameplayEffects are only replicated to the owning client. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on Player controlled Actors) + * - Minimal: Only replicate minimal gameplay effect info. Note: this does not work for Owned AbilitySystemComponents (Use Mixed instead). + * GameplayEffects are never replicated to anyone. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on AI controlled Actors) + * + * @See https://github.com/tranek/GASDocumentation#concepts-asc-rm for more information + */ + UPROPERTY(EditDefaultsOnly, Category = "OLS Ability System") + EGameplayEffectReplicationMode ReplicationMode; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OLS Ability System") + TObjectPtr AbilitySystemComponent = nullptr; +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularDefaultPawn.h b/Source/ols/Public/ModularGameplayActors/OLSModularDefaultPawn.h new file mode 100644 index 0000000..6088f3c --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularDefaultPawn.h @@ -0,0 +1,61 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "AbilitySystemInterface.h" +#include "GameplayTagAssetInterface.h" +#include "GameFramework/DefaultPawn.h" +#include "OLSModularDefaultPawn.generated.h" + +/** Minimal class that supports extension by game feature plugins, direct child of ADefaultPawn */ +UCLASS(Blueprintable) +class OLS_API AOLSModularDefaultPawn : public ADefaultPawn, public IAbilitySystemInterface, public IGameplayTagAssetInterface +{ + GENERATED_BODY() + +public: + // Sets default values for this pawn's properties + AOLSModularDefaultPawn(const FObjectInitializer& objectInitializer); + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + virtual void PostInitProperties() override; + // -- End Actor Implementation + + // -- Begin IAbilitySystemInterface implementation + virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override; + // -- End IAbilitySystemInterface implementation + + // -- Begin IGameplayTagAssetInterface + virtual void GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const override; + virtual bool HasMatchingGameplayTag(FGameplayTag tagToCheck) const override; + virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + // -- End IGameplayTagAssetInterface + +protected: + + /** + * Ability System Replication Mode: How gameplay effects will be replicated to clients + * + * - Full: Replicate full gameplay info to all. Every GameplayEffect is replicated to every client. + * (Recommended for Single Player games) + * - Mixed: Only replicate minimal gameplay effect info to simulated proxies but full info to owners and autonomous proxies. + * GameplayEffects are only replicated to the owning client. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on Player controlled Actors) + * - Minimal: Only replicate minimal gameplay effect info. Note: this does not work for Owned AbilitySystemComponents (Use Mixed instead). + * GameplayEffects are never replicated to anyone. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on AI controlled Actors) + * + * @See https://github.com/tranek/GASDocumentation#concepts-asc-rm for more information + */ + UPROPERTY(EditDefaultsOnly, Category = "OLS Ability System") + EGameplayEffectReplicationMode ReplicationMode; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OLS Ability System") + TObjectPtr AbilitySystemComponent = nullptr; +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularGameMode.h b/Source/ols/Public/ModularGameplayActors/OLSModularGameMode.h new file mode 100644 index 0000000..3d24374 --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularGameMode.h @@ -0,0 +1,30 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/GameMode.h" +#include "GameFramework/GameModeBase.h" +#include "OLSModularGameMode.generated.h" + +/** Pair this with a ModularGameStateBase */ +UCLASS(Blueprintable) +class OLS_API AOLSModularGameModeBase : public AGameModeBase +{ + GENERATED_BODY() + +public: + + AOLSModularGameModeBase(); +}; + +/** Pair this with a ModularGameState */ +UCLASS(Blueprintable) +class OLS_API AOLSModularGameMode : public AGameMode +{ + GENERATED_BODY() + +public: + + AOLSModularGameMode(); +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularGameState.h b/Source/ols/Public/ModularGameplayActors/OLSModularGameState.h new file mode 100644 index 0000000..1ad3a6f --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularGameState.h @@ -0,0 +1,43 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/GameState.h" +#include "OLSModularGameState.generated.h" + +/** Pair this with a ModularGameModeBase */ +UCLASS(Blueprintable) +class OLS_API AOLSModularGameStateBase : public AGameStateBase +{ + GENERATED_BODY() + +public: + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + // -- End Actor Implementation +}; + +/** Pair this with a ModularGameState */ +UCLASS(Blueprintable) +class OLS_API AOLSModularGameState : public AGameState +{ + GENERATED_BODY() + +public: + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + // -- End Actor Implementation + +protected: + + // -- Begin Actor implementation + virtual void HandleMatchHasStarted() override; + // -- End Actor Implementation +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularPawn.h b/Source/ols/Public/ModularGameplayActors/OLSModularPawn.h new file mode 100644 index 0000000..f1f2c7b --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularPawn.h @@ -0,0 +1,61 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "AbilitySystemInterface.h" +#include "GameplayTagAssetInterface.h" +#include "GameFramework/Pawn.h" +#include "OLSModularPawn.generated.h" + +/** Minimal class that supports extension by game feature plugins, direct child of APawn */ +UCLASS(Blueprintable) +class OLS_API AOLSModularPawn : public APawn, public IAbilitySystemInterface, public IGameplayTagAssetInterface +{ + GENERATED_BODY() +public: + + // Sets default values for this actor's properties + AOLSModularPawn(const FObjectInitializer& objectInitializer); + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + virtual void PostInitProperties() override; + // -- End Actor Implementation + + // -- Begin IAbilitySystemInterface implementation + virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override; + // -- End IAbilitySystemInterface implementation + + // -- Begin IGameplayTagAssetInterface + virtual void GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const override; + virtual bool HasMatchingGameplayTag(FGameplayTag tagToCheck) const override; + virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + // -- End IGameplayTagAssetInterface + +protected: + + /** + * Ability System Replication Mode: How gameplay effects will be replicated to clients + * + * - Full: Replicate full gameplay info to all. Every GameplayEffect is replicated to every client. + * (Recommended for Single Player games) + * - Mixed: Only replicate minimal gameplay effect info to simulated proxies but full info to owners and autonomous proxies. + * GameplayEffects are only replicated to the owning client. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on Player controlled Actors) + * - Minimal: Only replicate minimal gameplay effect info. Note: this does not work for Owned AbilitySystemComponents (Use Mixed instead). + * GameplayEffects are never replicated to anyone. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on AI controlled Actors) + * + * @See https://github.com/tranek/GASDocumentation#concepts-asc-rm for more information + */ + UPROPERTY(EditDefaultsOnly, Category = "OLS Ability System") + EGameplayEffectReplicationMode ReplicationMode; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OLS Ability System") + TObjectPtr AbilitySystemComponent = nullptr; +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularPlayerController.h b/Source/ols/Public/ModularGameplayActors/OLSModularPlayerController.h new file mode 100644 index 0000000..f9d9e27 --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularPlayerController.h @@ -0,0 +1,25 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/PlayerController.h" +#include "OLSModularPlayerController.generated.h" + +/** Minimal class that supports extension by game feature plugins */ +UCLASS(Blueprintable) +class OLS_API AOLSModularPlayerController : public APlayerController +{ + GENERATED_BODY() + +public: + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + // -- End Actor implementation + + // -- Begin APlayerController implementation + virtual void ReceivedPlayer() override; + virtual void PlayerTick(float deltaTime) override; + // -- End APlayerController implementation +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularPlayerState.h b/Source/ols/Public/ModularGameplayActors/OLSModularPlayerState.h new file mode 100644 index 0000000..e1728da --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularPlayerState.h @@ -0,0 +1,60 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "AbilitySystemInterface.h" +#include "GameFramework/PlayerState.h" +#include "OLSModularPlayerState.generated.h" + +/** Minimal class that supports extension by game feature plugins */ +UCLASS(Blueprintable) +class OLS_API AOLSModularPlayerState : public APlayerState, public IAbilitySystemInterface +{ + GENERATED_BODY() + +public: + + AOLSModularPlayerState(const FObjectInitializer& objectInitializer); + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void PostInitProperties() override; + virtual void Reset() override; + // -- End Actor implementation + + // -- Begin IAbilitySystemInterface implementation + virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; + // -- End IAbilitySystemInterface implementation + +protected: + + // -- Begin APlayerState interface + virtual void CopyProperties(APlayerState* playerState) override; + // -- End APlayerState interface + +protected: + + /** + * Ability System Replication Mode: How gameplay effects will be replicated to clients + * + * - Full: Replicate full gameplay info to all. Every GameplayEffect is replicated to every client. + * (Recommended for Single Player games) + * - Mixed: Only replicate minimal gameplay effect info to simulated proxies but full info to owners and autonomous proxies. + * GameplayEffects are only replicated to the owning client. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on Player controlled Actors) + * - Minimal: Only replicate minimal gameplay effect info. Note: this does not work for Owned AbilitySystemComponents (Use Mixed instead). + * GameplayEffects are never replicated to anyone. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on AI controlled Actors) + * + * @See https://github.com/tranek/GASDocumentation#concepts-asc-rm for more information + */ + UPROPERTY(EditDefaultsOnly, Category = "OLS Ability System") + EGameplayEffectReplicationMode ReplicationMode; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OLS Ability System") + TObjectPtr AbilitySystemComponent = nullptr; +}; diff --git a/Source/ols/Public/ModularGameplayActors/OLSModularPlayerStateCharacter.h b/Source/ols/Public/ModularGameplayActors/OLSModularPlayerStateCharacter.h new file mode 100644 index 0000000..8db0a0f --- /dev/null +++ b/Source/ols/Public/ModularGameplayActors/OLSModularPlayerStateCharacter.h @@ -0,0 +1,73 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "AbilitySystemInterface.h" +#include "GameplayTagAssetInterface.h" +#include "GameFramework/Character.h" +#include "OLSModularPlayerStateCharacter.generated.h" + +/** + * Minimal class that supports extension by game feature plugins. + * + * Intended to be used for ACharacters using AbilitySystemComponent living on PlayerState. + */ +UCLASS(Blueprintable) +class OLS_API AOLSModularPlayerStateCharacter : public ACharacter, public IAbilitySystemInterface, public IGameplayTagAssetInterface +{ + GENERATED_BODY() + +public: + + AOLSModularPlayerStateCharacter(const FObjectInitializer& objectInitializer); + + // -- Begin Actor implementation + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override; + virtual void PostInitProperties() override; + // -- End Actor implementation + + // -- Begin APawn implementation + virtual void PossessedBy(AController* newController) override; + virtual void OnRep_PlayerState() override; + // -- End APawn implementation + + + // -- Begin IAbilitySystemInterface implementation + virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override; + // -- End IAbilitySystemInterface implementation + + // -- Begin IGameplayTagAssetInterface + virtual void GetOwnedGameplayTags(FGameplayTagContainer& outTagContainer) const override; + virtual bool HasMatchingGameplayTag(FGameplayTag tagToCheck) const override; + virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& tagContainer) const override; + // -- End IGameplayTagAssetInterface + +protected: + + /** + * Ability System Replication Mode: How gameplay effects will be replicated to clients + * + * - Full: Replicate full gameplay info to all. Every GameplayEffect is replicated to every client. + * (Recommended for Single Player games) + * - Mixed: Only replicate minimal gameplay effect info to simulated proxies but full info to owners and autonomous proxies. + * GameplayEffects are only replicated to the owning client. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on Player controlled Actors) + * - Minimal: Only replicate minimal gameplay effect info. Note: this does not work for Owned AbilitySystemComponents (Use Mixed instead). + * GameplayEffects are never replicated to anyone. Only GameplayTags and GameplayCues are replicated to everyone. + * (Recommended for Multiplayer on AI controlled Actors) + * + * @See https://github.com/tranek/GASDocumentation#concepts-asc-rm for more information + */ + UPROPERTY(EditDefaultsOnly, Category = "OLS Ability System") + EGameplayEffectReplicationMode ReplicationMode; + +protected: + + // Cached AbilitySystemComponent. Real owner is PlayerState, but pointer gets updated to use PlayerState's here in PossessedBy / OnRep_PlayerState + TWeakObjectPtr AbilitySystemComponent; +}; diff --git a/Source/ols/Public/Player/OLSPlayerController.h b/Source/ols/Public/Player/OLSPlayerController.h new file mode 100644 index 0000000..04f71c2 --- /dev/null +++ b/Source/ols/Public/Player/OLSPlayerController.h @@ -0,0 +1,16 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "ModularGameplayActors/OLSModularPlayerController.h" +#include "OLSPlayerController.generated.h" + +/** + * + */ +UCLASS() +class OLS_API AOLSPlayerController : public AOLSModularPlayerController +{ + GENERATED_BODY() +}; diff --git a/Source/ols/Public/Player/OLSPlayerState.h b/Source/ols/Public/Player/OLSPlayerState.h new file mode 100644 index 0000000..a01e5a2 --- /dev/null +++ b/Source/ols/Public/Player/OLSPlayerState.h @@ -0,0 +1,35 @@ +// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action. + +#pragma once + +#include "CoreMinimal.h" +#include "ModularGameplayActors/OLSModularPlayerState.h" +#include "OLSPlayerState.generated.h" + +/** + * AOLSPlayerState + * + * Base player state class used by this project. + */ +UCLASS(Config = Game) +class OLS_API AOLSPlayerState : public AOLSModularPlayerState +{ + GENERATED_BODY() + +public: + + AOLSPlayerState(const FObjectInitializer& objectInitializer); + + + //~ Begin AActor interface + virtual void PostInitializeComponents() override; + //~ End AActor interface + +public: + + UFUNCTION(BlueprintCallable, Category = "OLS|PlayerState") + class AOLSPlayerController* GetOLSPlayerController() const; + + UFUNCTION(BlueprintCallable, Category = "OLS|PlayerState") + class UOLSAbilitySystemComponent* GetOLSAbilitySystemComponent() const; +}; diff --git a/Source/ols/ols.Build.cs b/Source/ols/ols.Build.cs index 450b781..996c5e9 100644 --- a/Source/ols/ols.Build.cs +++ b/Source/ols/ols.Build.cs @@ -16,10 +16,19 @@ public class ols : ModuleRules "GameplayTags", "GameplayTasks", "GameplayAbilities", - "OLSAnimation", + "GameFeatures", + "ModularGameplay", + "EnhancedInput", + "OLSAnimation", "AIModule", }); - PrivateDependencyModuleNames.AddRange(new[] { "InputCore", "AnimGraphRuntime", "GameplayMessageRuntime" }); + PrivateDependencyModuleNames.AddRange(new[] + { + "InputCore", + "AnimGraphRuntime", + "GameplayMessageRuntime", + "NetCore" + }); // Uncomment if you are using Slate UI // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); diff --git a/ols.uproject b/ols.uproject index a5237b4..e018664 100644 --- a/ols.uproject +++ b/ols.uproject @@ -43,6 +43,14 @@ { "Name": "GameplayAbilities", "Enabled": true + }, + { + "Name": "ModularGameplay", + "Enabled": true + }, + { + "Name": "GameFeatures", + "Enabled": true } ] } \ No newline at end of file