diff --git a/Source/ols/Private/AbilitySystem/Abilities/OLSGameplayAbility.cpp b/Source/ols/Private/AbilitySystem/Abilities/OLSGameplayAbility.cpp index 25a1cb8..857bbc9 100644 --- a/Source/ols/Private/AbilitySystem/Abilities/OLSGameplayAbility.cpp +++ b/Source/ols/Private/AbilitySystem/Abilities/OLSGameplayAbility.cpp @@ -2,3 +2,549 @@ #include "AbilitySystem/Abilities/OLSGameplayAbility.h" + +#include "OLSLog.h" +#include "AbilitySystem/OLSAbilitySimpleFailureMessage.h" +#include "AbilitySystem/OLSAbilitySystemComponent.h" +#include "AbilitySystem/Abilities/OLSAbilityCost.h" +#include "AbilitySystemBlueprintLibrary.h" +#include "AbilitySystemGlobals.h" +#include "AbilitySystem/OLSGameplayEffectContext.h" +#include "AbilitySystem/Interfaces/OLSAbilitySourceInterface.h" +#include "Components/OLSHeroComponent.h" +#include "GameFramework/GameplayMessageSubsystem.h" +#include "Physics/OLSPhysicalMaterialWithTags.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(OLSGameplayAbility) + +DEFINE_LOG_CATEGORY(LogOLSGameplayAbility); + +#define ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(FunctionName, ReturnValue) \ +{ \ + if (!ensure(IsInstantiated())) \ + { \ + OLS_LOG(LogOLSGameplayAbility, Error, TEXT("%s: " #FunctionName " cannot be called on a non-instanced ability. Check the instancing policy."), *GetPathName()); \ + return ReturnValue; \ + } \ +} + +UE_DEFINE_GAMEPLAY_TAG(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE, "Ability.UserFacingSimpleActivateFail.Message"); +UE_DEFINE_GAMEPLAY_TAG(TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE, "Ability.PlayMontageOnActivateFail.Message"); + +UOLSGameplayAbility::UOLSGameplayAbility(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ + ReplicationPolicy = EGameplayAbilityReplicationPolicy::ReplicateNo; + InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor; + NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted; + NetSecurityPolicy = EGameplayAbilityNetSecurityPolicy::ClientOrServer; + + ActivationPolicy = EOLSAbilityActivationPolicy::OnInputTriggered; + ActivationGroup = EOLSAbilityActivationGroup::Independent; + + bShouldLogCancellation = false; + + // @TODO: Implement OLSCameraMode. + // ActiveCameraMode = nullptr; +} + +bool UOLSGameplayAbility::CanActivateAbility(const FGameplayAbilitySpecHandle handle, + const FGameplayAbilityActorInfo* actorInfo, + const FGameplayTagContainer* sourceTags, + const FGameplayTagContainer* targetTags, + FGameplayTagContainer* optionalRelevantTags) const +{ + if (!actorInfo || !actorInfo->AbilitySystemComponent.IsValid()) + { + return false; + } + + if (!Super::CanActivateAbility(handle, actorInfo, sourceTags, targetTags, optionalRelevantTags)) + { + return false; + } + + //@TODO Possibly remove after setting up tag relationships + UOLSAbilitySystemComponent* asc = CastChecked(actorInfo->AbilitySystemComponent.Get()); + if (asc->IsActivationGroupBlocked(ActivationGroup)) + { + if (optionalRelevantTags) + { + // @TODO: Implement LyraGameplayTags::Ability_ActivateFail_ActivationGroup. + // optionalRelevantTags->AddTag(LyraGameplayTags::Ability_ActivateFail_ActivationGroup); + } + return false; + } + + return true; +} + +void UOLSGameplayAbility::SetCanBeCanceled(bool canBeCanceled) +{ + // The ability can not block canceling if it's replaceable. + if (!canBeCanceled && (ActivationGroup == EOLSAbilityActivationGroup::Exclusive_Replaceable)) + { + OLS_LOG(LogOLSGameplayAbility, Error, + TEXT( + "Ability [%s] can not block canceling because its activation group is replaceable." + ), *GetName()); + return; + } + + Super::SetCanBeCanceled(canBeCanceled); +} + +void UOLSGameplayAbility::OnGiveAbility(const FGameplayAbilityActorInfo* actorInfo, const FGameplayAbilitySpec& spec) +{ + Super::OnGiveAbility(actorInfo, spec); + + K2_OnAbilityAdded(); + + TryActivateAbilityOnSpawn(actorInfo, spec); +} + +void UOLSGameplayAbility::OnRemoveAbility(const FGameplayAbilityActorInfo* actorInfo, const FGameplayAbilitySpec& spec) +{ + K2_OnAbilityRemoved(); + + Super::OnRemoveAbility(actorInfo, spec); +} + +void UOLSGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, + const FGameplayAbilityActorInfo* ActorInfo, + const FGameplayAbilityActivationInfo ActivationInfo, + const FGameplayEventData* TriggerEventData) +{ + Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData); +} + +void UOLSGameplayAbility::EndAbility(const FGameplayAbilitySpecHandle Handle, + const FGameplayAbilityActorInfo* ActorInfo, + const FGameplayAbilityActivationInfo ActivationInfo, + bool bReplicateEndAbility, bool bWasCancelled) +{ + // @TODO: Implement UOLSCameraMode. + // ClearCameraMode(); + Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled); +} + +bool UOLSGameplayAbility::CheckCost(const FGameplayAbilitySpecHandle handle, + const FGameplayAbilityActorInfo* actorInfo, + FGameplayTagContainer* optionalRelevantTags) const +{ + if (!Super::CheckCost(handle, actorInfo, optionalRelevantTags) || !actorInfo) + { + return false; + } + + // Verify we can afford any additional costs + for (const TObjectPtr& additionalCost : AdditionalCosts) + { + if (additionalCost) + { + if (!additionalCost->CheckCost(this, handle, actorInfo, /*inout*/ optionalRelevantTags)) + { + return false; + } + } + } + + return true; +} + +void UOLSGameplayAbility::ApplyCost(const FGameplayAbilitySpecHandle handle, + const FGameplayAbilityActorInfo* actorInfo, + const FGameplayAbilityActivationInfo activationInfo) const +{ + check(actorInfo); + + // Used to determine if the ability actually hit a target (as some costs are only spent on successful attempts) + auto determineIfAbilityHitTarget = [&]() + { + if (actorInfo->IsNetAuthority()) + { + if (UOLSAbilitySystemComponent* ASC = Cast(actorInfo->AbilitySystemComponent.Get())) + { + FGameplayAbilityTargetDataHandle targetData; + ASC->GetAbilityTargetData(handle, activationInfo, targetData); + for (int32 targetDataIdx = 0; targetDataIdx < targetData.Data.Num(); ++targetDataIdx) + { + if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(targetData, targetDataIdx)) + { + return true; + } + } + } + } + + return false; + }; + + // Pay any additional costs + bool hasAbilityHitTarget = false; + bool hasDeterminedIfAbilityHitTarget = false; + for (const TObjectPtr& additionalCost : AdditionalCosts) + { + if (additionalCost) + { + if (additionalCost->ShouldOnlyApplyCostOnHit()) + { + if (!hasDeterminedIfAbilityHitTarget) + { + hasAbilityHitTarget = determineIfAbilityHitTarget(); + hasDeterminedIfAbilityHitTarget = true; + } + + if (!hasAbilityHitTarget) + { + continue; + } + } + + additionalCost->ApplyCost(this, handle, actorInfo, activationInfo); + } + } +} + +FGameplayEffectContextHandle UOLSGameplayAbility::MakeEffectContext(const FGameplayAbilitySpecHandle handle, + const FGameplayAbilityActorInfo* actorInfo) const +{ + FGameplayEffectContextHandle contextHandle = Super::MakeEffectContext(handle, actorInfo); + + FOLSGameplayEffectContext* effectContext = FOLSGameplayEffectContext::ExtractEffectContext(contextHandle); + check(effectContext); + + check(actorInfo); + + AActor* effectCauser = nullptr; + const IOLSAbilitySourceInterface* abilitySource = nullptr; + float sourceLevel = 0.0f; + GetAbilitySource(handle, actorInfo, /*out*/ sourceLevel, /*out*/ abilitySource, /*out*/ effectCauser); + + UObject* sourceObject = GetSourceObject(handle, actorInfo); + + AActor* instigator = actorInfo ? actorInfo->OwnerActor.Get() : nullptr; + + effectContext->SetAbilitySource(abilitySource, sourceLevel); + effectContext->AddInstigator(instigator, effectCauser); + effectContext->AddSourceObject(sourceObject); + + return contextHandle; +} + +void UOLSGameplayAbility::ApplyAbilityTagsToGameplayEffectSpec(FGameplayEffectSpec& spec, + FGameplayAbilitySpec* abilitySpec) const +{ + Super::ApplyAbilityTagsToGameplayEffectSpec(spec, abilitySpec); + + if (const FHitResult* hitResult = spec.GetContext().GetHitResult()) + { + if (const UOLSPhysicalMaterialWithTags* physMatWithTags = Cast(hitResult->PhysMaterial.Get())) + { + spec.CapturedTargetTags.GetSpecTags().AppendTags(physMatWithTags->Tags); + } + } +} + +bool UOLSGameplayAbility::DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent& abilitySystemComponent, + const FGameplayTagContainer* sourceTags, + const FGameplayTagContainer* targetTags, + FGameplayTagContainer* optionalRelevantTags) const +{ +// Specialized version to handle death exclusion and AbilityTags expansion via ASC + + bool isBlocked = false; + bool isMissing = false; + + UAbilitySystemGlobals& abilitySystemGlobals = UAbilitySystemGlobals::Get(); + const FGameplayTag& blockedTag = abilitySystemGlobals.ActivateFailTagsBlockedTag; + const FGameplayTag& missingTag = abilitySystemGlobals.ActivateFailTagsMissingTag; + + // Check if any of this ability's tags are currently blocked + if (abilitySystemComponent.AreAbilityTagsBlocked(GetAssetTags())) + { + isBlocked = true; + } + + const UOLSAbilitySystemComponent* asc = Cast(&abilitySystemComponent); + static FGameplayTagContainer allRequiredTags; + static FGameplayTagContainer allBlockedTags; + + allRequiredTags = ActivationRequiredTags; + allBlockedTags = ActivationBlockedTags; + + // Expand our ability tags to add additional required/blocked tags + if (asc) + { + asc->GetAdditionalActivationTagRequirements(GetAssetTags(), allRequiredTags, allBlockedTags); + } + + // Check to see the required/blocked tags for this ability + if (allBlockedTags.Num() || allRequiredTags.Num()) + { + static FGameplayTagContainer abilitySystemComponentTags; + + abilitySystemComponentTags.Reset(); + abilitySystemComponent.GetOwnedGameplayTags(abilitySystemComponentTags); + + if (abilitySystemComponentTags.HasAny(allBlockedTags)) + { + // @TODO: Implement LyraGameplayTags::Status_Death. + // @TODO: Implement LyraGameplayTags::Ability_ActivateFail_IsDead. + // if (optionalRelevantTags && abilitySystemComponentTags.HasTag(LyraGameplayTags::Status_Death)) + // { + // // If player is dead and was rejected due to blocking tags, give that feedback + // optionalRelevantTags->AddTag(LyraGameplayTags::Ability_ActivateFail_IsDead); + // } + + isBlocked = true; + } + + if (!abilitySystemComponentTags.HasAll(allRequiredTags)) + { + isMissing = true; + } + } + + if (sourceTags != nullptr) + { + if (SourceBlockedTags.Num() || SourceRequiredTags.Num()) + { + if (sourceTags->HasAny(SourceBlockedTags)) + { + isBlocked = true; + } + + if (!sourceTags->HasAll(SourceRequiredTags)) + { + isMissing = true; + } + } + } + + if (targetTags != nullptr) + { + if (TargetBlockedTags.Num() || TargetRequiredTags.Num()) + { + if (targetTags->HasAny(TargetBlockedTags)) + { + isBlocked = true; + } + + if (!targetTags->HasAll(TargetRequiredTags)) + { + isMissing = true; + } + } + } + + if (isBlocked) + { + if (optionalRelevantTags && blockedTag.IsValid()) + { + optionalRelevantTags->AddTag(blockedTag); + } + return false; + } + if (isMissing) + { + if (optionalRelevantTags && missingTag.IsValid()) + { + optionalRelevantTags->AddTag(missingTag); + } + return false; + } + + return true; +} + +UOLSAbilitySystemComponent* UOLSGameplayAbility::GetOLSAbilitySystemComponentFromActorInfo() const +{ + return (CurrentActorInfo ? Cast(CurrentActorInfo->AbilitySystemComponent.Get()) : nullptr); +} + +AController* UOLSGameplayAbility::GetControllerFromActorInfo() const +{ + if (CurrentActorInfo) + { + if (AController* controller = CurrentActorInfo->PlayerController.Get()) + { + return controller; + } + + // Look for a player controller or pawn in the owner chain. + AActor* testActor = CurrentActorInfo->OwnerActor.Get(); + while (testActor) + { + if (AController* controller = Cast(testActor)) + { + return controller; + } + + if (APawn* pawn = Cast(testActor)) + { + return pawn->GetController(); + } + + testActor = testActor->GetOwner(); + } + } + + return nullptr; +} + +UOLSHeroComponent* UOLSGameplayAbility::GetHeroComponentFromActorInfo() const +{ + return (CurrentActorInfo ? UOLSHeroComponent::FindHeroComponent(CurrentActorInfo->AvatarActor.Get()) : nullptr); +} + +bool UOLSGameplayAbility::CanChangeActivationGroup(EOLSAbilityActivationGroup newGroup) const +{ + if (!IsInstantiated() || !IsActive()) + { + return false; + } + + if (ActivationGroup == newGroup) + { + return true; + } + + UOLSAbilitySystemComponent* asc = GetOLSAbilitySystemComponentFromActorInfo(); + check(asc); + + if ((ActivationGroup != EOLSAbilityActivationGroup::Exclusive_Blocking) && asc->IsActivationGroupBlocked(newGroup)) + { + // This ability can't change groups if it's blocked (unless it is the one doing the blocking). + return false; + } + + if ((newGroup == EOLSAbilityActivationGroup::Exclusive_Replaceable) && !CanBeCanceled()) + { + // This ability can't become replaceable if it can't be canceled. + return false; + } + + return true; +} + +bool UOLSGameplayAbility::ChangeActivationGroup(EOLSAbilityActivationGroup newGroup) +{ + ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(ChangeActivationGroup, false); + + if (!CanChangeActivationGroup(newGroup)) + { + return false; + } + + if (ActivationGroup != newGroup) + { + UOLSAbilitySystemComponent* asc = GetOLSAbilitySystemComponentFromActorInfo(); + check(asc); + + asc->RemoveAbilityFromActivationGroup(ActivationGroup, this); + asc->AddAbilityToActivationGroup(newGroup, this); + + ActivationGroup = newGroup; + } + + return true; +} + +EOLSAbilityActivationPolicy UOLSGameplayAbility::GetActivationPolicy() const +{ + return ActivationPolicy; +} + +EOLSAbilityActivationGroup UOLSGameplayAbility::GetActivationGroup() const +{ + return ActivationGroup; +} + +void UOLSGameplayAbility::TryActivateAbilityOnSpawn(const FGameplayAbilityActorInfo* actorInfo, + const FGameplayAbilitySpec& spec) const +{ + // Try to activate if activation policy is on spawn. + if (actorInfo && !spec.IsActive() && (ActivationPolicy == EOLSAbilityActivationPolicy::OnSpawn)) + { + UAbilitySystemComponent* asc = actorInfo->AbilitySystemComponent.Get(); + const AActor* avatarActor = actorInfo->AvatarActor.Get(); + + // If avatar actor is torn off or about to die, don't try to activate until we get the new one. + if (asc && avatarActor && !avatarActor->GetTearOff() && (avatarActor->GetLifeSpan() <= 0.0f)) + { + const bool isLocalExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalPredicted) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalOnly); + const bool iServerExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerOnly) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerInitiated); + + const bool shouldClientActivate = actorInfo->IsLocallyControlled() && isLocalExecution; + const bool shouldServerActivate = actorInfo->IsNetAuthority() && iServerExecution; + + if (shouldClientActivate || shouldServerActivate) + { + asc->TryActivateAbility(spec.Handle); + } + } + } +} + +void UOLSGameplayAbility::OnAbilityFailedToActivate(const FGameplayTagContainer& failedReason) const +{ + NativeOnAbilityFailedToActivate(failedReason); + K2_OnAbilityFailedToActivate(failedReason); +} + +void UOLSGameplayAbility::OnPawnAvatarSet() +{ + K2_OnPawnAvatarSet(); +} + +void UOLSGameplayAbility::GetAbilitySource(FGameplayAbilitySpecHandle handle, + const FGameplayAbilityActorInfo* actorInfo, + float& outSourceLevel, + const IOLSAbilitySourceInterface*& outAbilitySource, + AActor*& outEffectCauser) const +{ + outSourceLevel = 0.0f; + outAbilitySource = nullptr; + outEffectCauser = nullptr; + + outEffectCauser = actorInfo->AvatarActor.Get(); + + // If we were added by something that's an ability info source, use it + UObject* sourceObject = GetSourceObject(handle, actorInfo); + + outAbilitySource = Cast(sourceObject); +} + +void UOLSGameplayAbility::NativeOnAbilityFailedToActivate(const FGameplayTagContainer& failedReason) const +{ + bool simpleFailureFound = false; + for (FGameplayTag reason : failedReason) + { + if (!simpleFailureFound) + { + if (const FText* pUserFacingMessage = FailureTagToUserFacingMessages.Find(reason)) + { + FOLSAbilitySimpleFailureMessage message; + message.PlayerController = GetActorInfo().PlayerController.Get(); + message.FailureTags = failedReason; + message.UserFacingReason = *pUserFacingMessage; + + UGameplayMessageSubsystem& messageSystem = UGameplayMessageSubsystem::Get(GetWorld()); + messageSystem.BroadcastMessage(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE, message); + simpleFailureFound = true; + } + } + + if (UAnimMontage* montage = FailureTagToAnimMontage.FindRef(reason)) + { + FOLSAbilityMontageFailureMessage message; + message.PlayerController = GetActorInfo().PlayerController.Get(); + message.AvatarActor = GetActorInfo().AvatarActor.Get(); + message.FailureTags = failedReason; + message.FailureMontage = montage; + + UGameplayMessageSubsystem& messageSystem = UGameplayMessageSubsystem::Get(GetWorld()); + messageSystem.BroadcastMessage(TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE, message); + } + } +} diff --git a/Source/ols/Private/AbilitySystem/Interfaces/OLSAbilitySourceInterface.cpp b/Source/ols/Private/AbilitySystem/Interfaces/OLSAbilitySourceInterface.cpp new file mode 100644 index 0000000..66b8ea9 --- /dev/null +++ b/Source/ols/Private/AbilitySystem/Interfaces/OLSAbilitySourceInterface.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/Interfaces/OLSAbilitySourceInterface.h" + + +// Add default functionality here for any IOLSAbilitySourceInterface functions that are not pure virtual. diff --git a/Source/ols/Private/AbilitySystem/OLSAbilitySimpleFailureMessage.cpp b/Source/ols/Private/AbilitySystem/OLSAbilitySimpleFailureMessage.cpp new file mode 100644 index 0000000..1189d31 --- /dev/null +++ b/Source/ols/Private/AbilitySystem/OLSAbilitySimpleFailureMessage.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 "AbilitySystem/OLSAbilitySimpleFailureMessage.h" diff --git a/Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp b/Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp index 4fb8f5b..4f9c9f2 100644 --- a/Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp +++ b/Source/ols/Private/AbilitySystem/OLSAbilitySystemComponent.cpp @@ -661,6 +661,89 @@ void UOLSAbilitySystemComponent::ClearAbilityInput() InputHeldSpecHandles.Reset(); } +bool UOLSAbilitySystemComponent::IsActivationGroupBlocked(EOLSAbilityActivationGroup Group) const +{ + bool isBlocked = false; + + switch (Group) + { + case EOLSAbilityActivationGroup::Independent: + // Independent abilities are never blocked. + isBlocked = false; + break; + + case EOLSAbilityActivationGroup::Exclusive_Replaceable: + case EOLSAbilityActivationGroup::Exclusive_Blocking: + // Exclusive abilities can activate if nothing is blocking. + isBlocked = (ActivationGroupCounts[(uint8)EOLSAbilityActivationGroup::Exclusive_Blocking] > 0); + break; + + default: + checkf(false, TEXT("IsActivationGroupBlocked: Invalid ActivationGroup [%d]\n"), (uint8)Group); + break; + } + + return isBlocked; +} + +void UOLSAbilitySystemComponent::AddAbilityToActivationGroup(EOLSAbilityActivationGroup group, + UOLSGameplayAbility* ability) +{ + check(ability); + check(ActivationGroupCounts[(uint8)group] < INT32_MAX); + + ActivationGroupCounts[(uint8)group]++; + + constexpr bool shouldReplicateCancelAbility = false; + + switch (group) + { + case EOLSAbilityActivationGroup::Independent: + // Independent abilities do not cancel any other abilities. + break; + + case EOLSAbilityActivationGroup::Exclusive_Replaceable: + case EOLSAbilityActivationGroup::Exclusive_Blocking: + CancelActivationGroupAbilities(EOLSAbilityActivationGroup::Exclusive_Replaceable, ability, shouldReplicateCancelAbility); + break; + + default: + checkf(false, TEXT("AddAbilityToActivationGroup: Invalid ActivationGroup [%d]\n"), (uint8)group); + break; + } + + const int32 exclusiveCount = ActivationGroupCounts[static_cast( + EOLSAbilityActivationGroup::Exclusive_Replaceable)] + ActivationGroupCounts[static_cast( + EOLSAbilityActivationGroup::Exclusive_Blocking)]; + if (!ensure(exclusiveCount <= 1)) + { + OLS_LOG(LogOLSAbilitySystemComponent, Error, + TEXT("Multiple exclusive abilities are running.")); + } +} + +void UOLSAbilitySystemComponent::RemoveAbilityFromActivationGroup(EOLSAbilityActivationGroup group, + UOLSGameplayAbility* ability) +{ + check(ability); + check(ActivationGroupCounts[(uint8)group] > 0); + + ActivationGroupCounts[(uint8)group]--; +} + +void UOLSAbilitySystemComponent::CancelActivationGroupAbilities(EOLSAbilityActivationGroup group, + UOLSGameplayAbility* ignoreAbility, + bool shouldReplicateCancelAbility) +{ + auto shouldCancelFunc = [this, group, ignoreAbility](const UOLSGameplayAbility* ability, + FGameplayAbilitySpecHandle handle) + { + return ((ability->GetActivationGroup() == group) && (ability != ignoreAbility)); + }; + + CancelAbilitiesByFunc(shouldCancelFunc, shouldReplicateCancelAbility); +} + void UOLSAbilitySystemComponent::AddDynamicTagGameplayEffect(const FGameplayTag& tag) { const TSubclassOf dynamicTagGE = UOLSAssetManager::GetSubclass(UOLSGameDataAsset::Get().DynamicTagGameplayEffect); @@ -724,11 +807,13 @@ void UOLSAbilitySystemComponent::SetTagRelationshipMapping(UOLSAbilityTagRelatio void UOLSAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags, FGameplayTagContainer& outActivationRequired, - FGameplayTagContainer& outActivationBlocked) const + FGameplayTagContainer& outActivationBlocked) +const { if (TagRelationshipMapping) { - TagRelationshipMapping->GetRequiredAndBlockedActivationTags(abilityTags, &outActivationRequired, &outActivationBlocked); + TagRelationshipMapping->GetRequiredAndBlockedActivationTags(abilityTags, &outActivationRequired, + &outActivationBlocked); } } diff --git a/Source/ols/Private/AbilitySystem/OLSGameplayEffectContext.cpp b/Source/ols/Private/AbilitySystem/OLSGameplayEffectContext.cpp new file mode 100644 index 0000000..5852b5a --- /dev/null +++ b/Source/ols/Private/AbilitySystem/OLSGameplayEffectContext.cpp @@ -0,0 +1,66 @@ +// © 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/OLSGameplayEffectContext.h" + +#if UE_WITH_IRIS +#include "Iris/ReplicationState/PropertyNetSerializerInfoRegistry.h" +#include "Serialization/GameplayEffectContextNetSerializer.h" +#endif + +#include "AbilitySystem/Interfaces/OLSAbilitySourceInterface.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(OLSGameplayEffectContext) + +FOLSGameplayEffectContext* FOLSGameplayEffectContext::ExtractEffectContext(FGameplayEffectContextHandle handle) +{ + FGameplayEffectContext* baseEffectContext = handle.Get(); + if ((baseEffectContext != nullptr) && baseEffectContext->GetScriptStruct()->IsChildOf(StaticStruct())) + { + return static_cast(baseEffectContext); + } + + return nullptr; +} + +void FOLSGameplayEffectContext::SetAbilitySource(const IOLSAbilitySourceInterface* object, float sourceLevel) +{ + AbilitySourceObject = MakeWeakObjectPtr(Cast(object)); + //SourceLevel = sourceLevel; +} + +const IOLSAbilitySourceInterface* FOLSGameplayEffectContext::GetAbilitySource() const +{ + return Cast(AbilitySourceObject.Get()); +} + +FGameplayEffectContext* FOLSGameplayEffectContext::Duplicate() const +{ + FOLSGameplayEffectContext* newContext = new FOLSGameplayEffectContext(); + *newContext = *this; + if (GetHitResult()) + { + // Does a deep copy of the hit result + newContext->AddHitResult(*GetHitResult(), true); + } + return newContext; +} + +UScriptStruct* FOLSGameplayEffectContext::GetScriptStruct() const +{ + return FOLSGameplayEffectContext::StaticStruct(); +} + +bool FOLSGameplayEffectContext::NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess) +{ + return FGameplayEffectContext::NetSerialize(Ar, Map, bOutSuccess); +} + +const UPhysicalMaterial* FOLSGameplayEffectContext::GetPhysicalMaterial() const +{ + if (const FHitResult* hitResultPtr = GetHitResult()) + { + return hitResultPtr->PhysMaterial.Get(); + } + return nullptr; +} diff --git a/Source/ols/Private/Components/OLSHeroComponent.cpp b/Source/ols/Private/Components/OLSHeroComponent.cpp index 08f324d..78df7e4 100644 --- a/Source/ols/Private/Components/OLSHeroComponent.cpp +++ b/Source/ols/Private/Components/OLSHeroComponent.cpp @@ -194,6 +194,11 @@ void UOLSHeroComponent::CheckDefaultInitialization() // ContinueInitStateChain(stateChain); } +UOLSHeroComponent* UOLSHeroComponent::FindHeroComponent(const AActor* actor) +{ + return (actor ? actor->FindComponentByClass() : nullptr); +} + void UOLSHeroComponent::ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& owningSpecHandle) { if (AbilityCameraModeOwningSpecHandle == owningSpecHandle) diff --git a/Source/ols/Private/Physics/OLSPhysicalMaterialWithTags.cpp b/Source/ols/Private/Physics/OLSPhysicalMaterialWithTags.cpp new file mode 100644 index 0000000..0b0efe7 --- /dev/null +++ b/Source/ols/Private/Physics/OLSPhysicalMaterialWithTags.cpp @@ -0,0 +1,8 @@ +// © 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 "Physics/OLSPhysicalMaterialWithTags.h" + +UOLSPhysicalMaterialWithTags::UOLSPhysicalMaterialWithTags(const FObjectInitializer& objectInitializer) : Super(objectInitializer) +{ +} diff --git a/Source/ols/Public/AbilitySystem/Abilities/OLSGameplayAbility.h b/Source/ols/Public/AbilitySystem/Abilities/OLSGameplayAbility.h index afbdc5f..dff546f 100644 --- a/Source/ols/Public/AbilitySystem/Abilities/OLSGameplayAbility.h +++ b/Source/ols/Public/AbilitySystem/Abilities/OLSGameplayAbility.h @@ -6,6 +6,8 @@ #include "Abilities/GameplayAbility.h" #include "OLSGameplayAbility.generated.h" +DECLARE_LOG_CATEGORY_EXTERN(LogOLSGameplayAbility, Verbose, All); + /** * ELyraAbilityActivationPolicy * @@ -78,9 +80,88 @@ class OLS_API UOLSGameplayAbility : public UGameplayAbility GENERATED_BODY() public: - + UOLSGameplayAbility(const FObjectInitializer& objectInitializer); +protected: + + //~UGameplayAbility interface + virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle handle, const FGameplayAbilityActorInfo* actorInfo, const FGameplayTagContainer* sourceTags, const FGameplayTagContainer* targetTags, FGameplayTagContainer* optionalRelevantTags) const override; + virtual void SetCanBeCanceled(bool canBeCanceled) override; + virtual void OnGiveAbility(const FGameplayAbilityActorInfo* actorInfo, const FGameplayAbilitySpec& spec) override; + virtual void OnRemoveAbility(const FGameplayAbilityActorInfo* actorInfo, const FGameplayAbilitySpec& spec) override; + virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override; + virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override; + virtual bool CheckCost(const FGameplayAbilitySpecHandle handle, const FGameplayAbilityActorInfo* actorInfo, OUT FGameplayTagContainer* optionalRelevantTags = nullptr) const override; + virtual void ApplyCost(const FGameplayAbilitySpecHandle handle, const FGameplayAbilityActorInfo* actorInfo, const FGameplayAbilityActivationInfo activationInfo) const override; + virtual FGameplayEffectContextHandle MakeEffectContext(const FGameplayAbilitySpecHandle handle, const FGameplayAbilityActorInfo* actorInfo) const override; + virtual void ApplyAbilityTagsToGameplayEffectSpec(FGameplayEffectSpec& spec, FGameplayAbilitySpec* abilitySpec) const override; + virtual bool DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent& abilitySystemComponent, const FGameplayTagContainer* sourceTags = nullptr, const FGameplayTagContainer* targetTags = nullptr, OUT FGameplayTagContainer* optionalRelevantTags = nullptr) const override; + //~End of UGameplayAbility interface + +public: + + UFUNCTION(BlueprintCallable, Category = "OLS|Ability") + class UOLSAbilitySystemComponent* GetOLSAbilitySystemComponentFromActorInfo() const; + + UFUNCTION(BlueprintCallable, Category = "OLS|Ability") + AController* GetControllerFromActorInfo() const; + + UFUNCTION(BlueprintCallable, Category = "Lyra|Ability") + class UOLSHeroComponent* GetHeroComponentFromActorInfo() const; + + // Returns true if the requested activation group is a valid transition. + UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "OLS|Ability", Meta = (ExpandBoolAsExecs = "ReturnValue")) + bool CanChangeActivationGroup(EOLSAbilityActivationGroup newGroup) const; + + // Tries to change the activation group. Returns true if it successfully changed. + UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "OLS|Ability", Meta = (ExpandBoolAsExecs = "ReturnValue")) + bool ChangeActivationGroup(EOLSAbilityActivationGroup newGroup); + + // @TODO: Implement OLSCameraMode. + // // Sets the ability's camera mode. + // UFUNCTION(BlueprintCallable, Category = "Lyra|Ability") + // void SetCameraMode(TSubclassOf CameraMode); + // + // // Clears the ability's camera mode. Automatically called if needed when the ability ends. + // UFUNCTION(BlueprintCallable, Category = "Lyra|Ability") + // void ClearCameraMode(); + +public: + + EOLSAbilityActivationPolicy GetActivationPolicy() const; + EOLSAbilityActivationGroup GetActivationGroup() const; + + void TryActivateAbilityOnSpawn(const FGameplayAbilityActorInfo* actorInfo, const FGameplayAbilitySpec& spec) const; + + void OnAbilityFailedToActivate(const FGameplayTagContainer& failedReason) const; + +protected: + virtual void OnPawnAvatarSet(); + + virtual void GetAbilitySource(FGameplayAbilitySpecHandle handle, const FGameplayAbilityActorInfo* actorInfo, + float& outSourceLevel, const class IOLSAbilitySourceInterface*& outAbilitySource, + AActor*& outEffectCauser) const; + + // Called when the ability fails to activate + virtual void NativeOnAbilityFailedToActivate(const FGameplayTagContainer& failedReason) const; + + // Called when the ability fails to activate + UFUNCTION(BlueprintImplementableEvent, DisplayName = "OnAbilityFailedToActivate") + void K2_OnAbilityFailedToActivate(const FGameplayTagContainer& FailedReason) const; + + /** Called when this ability is granted to the ability system component. */ + UFUNCTION(BlueprintImplementableEvent, Category = Ability, DisplayName = "OnAbilityAdded") + void K2_OnAbilityAdded(); + + /** Called when this ability is removed from the ability system component. */ + UFUNCTION(BlueprintImplementableEvent, Category = Ability, DisplayName = "OnAbilityRemoved") + void K2_OnAbilityRemoved(); + + /** Called when the ability system is initialized with a pawn avatar. */ + UFUNCTION(BlueprintImplementableEvent, Category = Ability, DisplayName = "OnPawnAvatarSet") + void K2_OnPawnAvatarSet(); + protected: // Defines how this ability is meant to activate. @@ -107,6 +188,7 @@ protected: UPROPERTY(EditDefaultsOnly, Category = "Advanced") uint8 bShouldLogCancellation : 1 = false; + // @TODO: Implement OLSCameraMode // Current camera mode set by the ability. - // TSubclassOf ActiveCameraMode; + // TSubclassOf ActiveCameraMode; }; diff --git a/Source/ols/Public/AbilitySystem/Interfaces/OLSAbilitySourceInterface.h b/Source/ols/Public/AbilitySystem/Interfaces/OLSAbilitySourceInterface.h new file mode 100644 index 0000000..11371b0 --- /dev/null +++ b/Source/ols/Public/AbilitySystem/Interfaces/OLSAbilitySourceInterface.h @@ -0,0 +1,37 @@ +// © 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 "GameplayTagContainer.h" +#include "OLSAbilitySourceInterface.generated.h" + +// This class does not need to be modified. +UINTERFACE() +class UOLSAbilitySourceInterface : public UInterface +{ + GENERATED_BODY() +}; + +/** + * + */ +class OLS_API IOLSAbilitySourceInterface +{ + GENERATED_IINTERFACE_BODY() + /** + * Compute the multiplier for effect falloff with distance + * ABILITY_LOG + * @param distance Distance from source to target for ability calculations (distance bullet traveled for a gun, etc...) + * @param sourceTags Aggregated Tags from the source + * @param targetTags Aggregated Tags currently on the target + * + * @return Multiplier to apply to the base attribute value due to distance + */ + virtual float GetDistanceAttenuation(float distance, const FGameplayTagContainer* sourceTags = nullptr, + const FGameplayTagContainer* targetTags = nullptr) const = 0; + + virtual float GetPhysicalMaterialAttenuation(const UPhysicalMaterial* physicalMaterial, + const FGameplayTagContainer* sourceTags = nullptr, + const FGameplayTagContainer* targetTags = nullptr) const = 0; +}; diff --git a/Source/ols/Public/AbilitySystem/OLSAbilitySimpleFailureMessage.h b/Source/ols/Public/AbilitySystem/OLSAbilitySimpleFailureMessage.h new file mode 100644 index 0000000..465402d --- /dev/null +++ b/Source/ols/Public/AbilitySystem/OLSAbilitySimpleFailureMessage.h @@ -0,0 +1,28 @@ +// © 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 "NativeGameplayTags.h" +#include "GameplayTagContainer.h" + +#include "OLSAbilitySimpleFailureMessage.generated.h" + +UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE); + +USTRUCT(BlueprintType) +struct FOLSAbilitySimpleFailureMessage +{ + GENERATED_BODY() + +public: + + UPROPERTY(BlueprintReadWrite) + TObjectPtr PlayerController = nullptr; + + UPROPERTY(BlueprintReadWrite) + FGameplayTagContainer FailureTags; + + UPROPERTY(BlueprintReadWrite) + FText UserFacingReason; +}; diff --git a/Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h b/Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h index 36a8848..aa54e6f 100644 --- a/Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h +++ b/Source/ols/Public/AbilitySystem/OLSAbilitySystemComponent.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "AbilitySystemComponent.h" #include "NativeGameplayTags.h" +#include "Abilities/OLSGameplayAbility.h" #include "OLSAbilitySystemComponent.generated.h" DECLARE_LOG_CATEGORY_EXTERN(LogOLSAbilitySystemComponent, Verbose, All); @@ -157,17 +158,17 @@ protected: virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& spec) override; virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& spec) override; - virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle handle, UGameplayAbility* ability) override; - virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle handle, UGameplayAbility* ability, const FGameplayTagContainer& failureReason) override; - virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle handle, UGameplayAbility* Ability, bool bWasCancelled) override; - virtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& abilityTags, UGameplayAbility* requestingAbility, bool shouldEnableBlockTags, const FGameplayTagContainer& blockTags, bool shouldExecuteCancelTags, const FGameplayTagContainer& cancelTags) override; - virtual void HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& abilityTags, UGameplayAbility* requestingAbility, bool canBeCanceled) override; + virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle handle, class UGameplayAbility* ability) override; + virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle handle, class UGameplayAbility* ability, const FGameplayTagContainer& failureReason) override; + virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle handle, class UGameplayAbility* Ability, bool bWasCancelled) override; + virtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& abilityTags, class UGameplayAbility* requestingAbility, bool shouldEnableBlockTags, const FGameplayTagContainer& blockTags, bool shouldExecuteCancelTags, const FGameplayTagContainer& cancelTags) override; + virtual void HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& abilityTags, class UGameplayAbility* requestingAbility, bool canBeCanceled) override; /** Notify client that an ability failed to activate */ UFUNCTION(Client, Unreliable) - void ClientNotifyAbilityFailed(const UGameplayAbility* ability, const FGameplayTagContainer& failureReason); + void ClientNotifyAbilityFailed(const class UGameplayAbility* ability, const FGameplayTagContainer& failureReason); - void HandleAbilityFailed(const UGameplayAbility* ability, const FGameplayTagContainer& failureReason); + void HandleAbilityFailed(const class UGameplayAbility* ability, const FGameplayTagContainer& failureReason); /** * Conveniently separates the code that sets the animation to replicate, so it can be further modified. @@ -176,7 +177,7 @@ protected: public: - typedef TFunctionRef TShouldCancelAbilityFunc; + typedef TFunctionRef TShouldCancelAbilityFunc; void CancelAbilitiesByFunc(TShouldCancelAbilityFunc shouldCancelFunc, bool shouldReplicateCancelAbility); void CancelInputActivatedAbilities(bool shouldReplicateCancelAbility); @@ -187,11 +188,10 @@ public: void ProcessAbilityInput(float deltaTime, bool shouldGamePaused); void ClearAbilityInput(); - // @TODO: Implement UOLSGameplayAbility. - // bool IsActivationGroupBlocked(ELyraAbilityActivationGroup Group) const; - // void AddAbilityToActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility); - // void RemoveAbilityFromActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility); - // void CancelActivationGroupAbilities(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* IgnoreLyraAbility, bool bReplicateCancelAbility); + bool IsActivationGroupBlocked(EOLSAbilityActivationGroup Group) const; + void AddAbilityToActivationGroup(EOLSAbilityActivationGroup group, UOLSGameplayAbility* ability); + void RemoveAbilityFromActivationGroup(EOLSAbilityActivationGroup group, UOLSGameplayAbility* ability); + void CancelActivationGroupAbilities(EOLSAbilityActivationGroup group, UOLSGameplayAbility* ignoreAbility, bool shouldReplicateCancelAbility); // Uses a gameplay effect to add the specified dynamic granted tag. void AddDynamicTagGameplayEffect(const FGameplayTag& tag); @@ -208,8 +208,6 @@ public: /** Looks at ability tags and gathers additional required and blocking tags */ void GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags, FGameplayTagContainer& outActivationRequired, FGameplayTagContainer& outActivationBlocked) const; - - private: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "OLS Ability System", DisplayName = "Enable Ability Batch RPCs", meta = (AllowPrivateAccess = true)) @@ -229,4 +227,7 @@ protected: // Handles to abilities that have their input held. TArray InputHeldSpecHandles; + + // Number of abilities running in each activation group. + int32 ActivationGroupCounts[(uint8)EOLSAbilityActivationGroup::MAX]; }; diff --git a/Source/ols/Public/AbilitySystem/OLSGameplayEffectContext.h b/Source/ols/Public/AbilitySystem/OLSGameplayEffectContext.h new file mode 100644 index 0000000..2a286d5 --- /dev/null +++ b/Source/ols/Public/AbilitySystem/OLSGameplayEffectContext.h @@ -0,0 +1,63 @@ +// © 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 "GameplayEffectTypes.h" +#include "OLSGameplayEffectContext.generated.h" + +USTRUCT() +struct FOLSGameplayEffectContext : public FGameplayEffectContext +{ + GENERATED_BODY() + + FOLSGameplayEffectContext() + : FGameplayEffectContext() + { + } + + FOLSGameplayEffectContext(AActor* InInstigator, AActor* InEffectCauser) + : FGameplayEffectContext(InInstigator, InEffectCauser) + { + } + + /** Returns the wrapped FLyraGameplayEffectContext from the handle, or nullptr if it doesn't exist or is the wrong type */ + static OLS_API FOLSGameplayEffectContext* ExtractEffectContext(struct FGameplayEffectContextHandle handle); + + /** Sets the object used as the ability source */ + void SetAbilitySource(const class IOLSAbilitySourceInterface* object, float sourceLevel); + + /** Returns the ability source interface associated with the source object. Only valid on the authority. */ + const IOLSAbilitySourceInterface* GetAbilitySource() const; + + virtual FGameplayEffectContext* Duplicate() const override; + + virtual UScriptStruct* GetScriptStruct() const override; + + /** Overridden to serialize new fields */ + virtual bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) override; + + /** Returns the physical material from the hit result if there is one */ + const UPhysicalMaterial* GetPhysicalMaterial() const; + +public: + + /** ID to allow the identification of multiple bullets that were part of the same cartridge */ + UPROPERTY() + int32 CartridgeID = -1; + +protected: + + /** Ability Source object (should implement ILyraAbilitySourceInterface). NOT replicated currently */ + UPROPERTY() + TWeakObjectPtr AbilitySourceObject; +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithNetSerializer = true, + WithCopy = true + }; +}; \ No newline at end of file diff --git a/Source/ols/Public/Components/OLSHeroComponent.h b/Source/ols/Public/Components/OLSHeroComponent.h index ea32913..dbe7e51 100644 --- a/Source/ols/Public/Components/OLSHeroComponent.h +++ b/Source/ols/Public/Components/OLSHeroComponent.h @@ -39,6 +39,11 @@ public: /** The name of this component-implemented feature */ static const FName NAME_ActorFeatureName; + /** Returns the hero component if one exists on the specified actor. */ + UFUNCTION(BlueprintPure, Category = "Lyra|Hero") + static UOLSHeroComponent* FindHeroComponent(const AActor* actor); + + /** Overrides the camera from an active gameplay ability */ //@TODO: implement UOLSCameraMode. // void SetAbilityCameraMode(TSubclassOf CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle); diff --git a/Source/ols/Public/Physics/OLSCollisionChannels.h b/Source/ols/Public/Physics/OLSCollisionChannels.h new file mode 100644 index 0000000..961ed43 --- /dev/null +++ b/Source/ols/Public/Physics/OLSCollisionChannels.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 + +/** + * when you modify this, please note that this information can be saved with instances + * also DefaultEngine.ini [/Script/Engine.CollisionProfile] should match with this list + **/ + +// Trace against Actors/Components which provide interactions. +#define OLS_TraceChannel_Interaction ECC_GameTraceChannel1 + +// Trace used by weapons, will hit physics assets instead of capsules +#define OLS_TraceChannel_Weapon ECC_GameTraceChannel2 + +// Trace used by by weapons, will hit pawn capsules instead of physics assets +#define OLS_TraceChannel_Weapon_Capsule ECC_GameTraceChannel3 + +// Trace used by by weapons, will trace through multiple pawns rather than stopping on the first hit +#define OLS_TraceChannel_Weapon_Multi ECC_GameTraceChannel4 + +// Allocated to aim assist by the ShooterCore game feature +// ECC_GameTraceChannel5 \ No newline at end of file diff --git a/Source/ols/Public/Physics/OLSPhysicalMaterialWithTags.h b/Source/ols/Public/Physics/OLSPhysicalMaterialWithTags.h new file mode 100644 index 0000000..969fa27 --- /dev/null +++ b/Source/ols/Public/Physics/OLSPhysicalMaterialWithTags.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 "GameplayTagContainer.h" +#include "PhysicalMaterials/PhysicalMaterial.h" +#include "OLSPhysicalMaterialWithTags.generated.h" + +/** + * + */ +UCLASS() +class OLS_API UOLSPhysicalMaterialWithTags : public UPhysicalMaterial +{ + GENERATED_BODY() + +public: + + UOLSPhysicalMaterialWithTags(const FObjectInitializer& objectInitializer); + + // A container of gameplay tags that game code can use to reason about this physical material + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=PhysicalProperties) + FGameplayTagContainer Tags; +}; diff --git a/Source/ols/ols.Build.cs b/Source/ols/ols.Build.cs index 0e067f6..ab2cd24 100644 --- a/Source/ols/ols.Build.cs +++ b/Source/ols/ols.Build.cs @@ -19,7 +19,11 @@ public class ols : ModuleRules "GameFeatures", "ModularGameplay", "EnhancedInput", - "OLSAnimation", "AIModule", "CommonLoadingScreen", "CommonUser" + "OLSAnimation", + "AIModule", + "CommonLoadingScreen", + "CommonUser", + "PhysicsCore" }); PrivateDependencyModuleNames.AddRange(new[]