Implemented OLSGameplayAbility.

Implemented OLSCollisionChannels.
Implemented OLSGameplayEffectContext.
Implemented OLSPhysicalMaterialWithTags.
This commit is contained in:
LongLy 2025-01-20 11:59:57 -07:00
parent 2c4a71b343
commit c0b033fb22
16 changed files with 1009 additions and 20 deletions

View File

@ -2,3 +2,549 @@
#include "AbilitySystem/Abilities/OLSGameplayAbility.h" #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<UOLSAbilitySystemComponent>(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<UOLSAbilityCost>& 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<UOLSAbilitySystemComponent>(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<UOLSAbilityCost>& 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<const UOLSPhysicalMaterialWithTags>(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<UOLSAbilitySystemComponent>(&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<UOLSAbilitySystemComponent>(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<AController>(testActor))
{
return controller;
}
if (APawn* pawn = Cast<APawn>(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<IOLSAbilitySourceInterface>(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);
}
}
}

View File

@ -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.

View File

@ -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"

View File

@ -661,6 +661,89 @@ void UOLSAbilitySystemComponent::ClearAbilityInput()
InputHeldSpecHandles.Reset(); 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<uint8>(
EOLSAbilityActivationGroup::Exclusive_Replaceable)] + ActivationGroupCounts[static_cast<uint8>(
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) void UOLSAbilitySystemComponent::AddDynamicTagGameplayEffect(const FGameplayTag& tag)
{ {
const TSubclassOf<UGameplayEffect> dynamicTagGE = UOLSAssetManager::GetSubclass(UOLSGameDataAsset::Get().DynamicTagGameplayEffect); const TSubclassOf<UGameplayEffect> dynamicTagGE = UOLSAssetManager::GetSubclass(UOLSGameDataAsset::Get().DynamicTagGameplayEffect);
@ -724,11 +807,13 @@ void UOLSAbilitySystemComponent::SetTagRelationshipMapping(UOLSAbilityTagRelatio
void UOLSAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags, void UOLSAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags,
FGameplayTagContainer& outActivationRequired, FGameplayTagContainer& outActivationRequired,
FGameplayTagContainer& outActivationBlocked) const FGameplayTagContainer& outActivationBlocked)
const
{ {
if (TagRelationshipMapping) if (TagRelationshipMapping)
{ {
TagRelationshipMapping->GetRequiredAndBlockedActivationTags(abilityTags, &outActivationRequired, &outActivationBlocked); TagRelationshipMapping->GetRequiredAndBlockedActivationTags(abilityTags, &outActivationRequired,
&outActivationBlocked);
} }
} }

View File

@ -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<FOLSGameplayEffectContext*>(baseEffectContext);
}
return nullptr;
}
void FOLSGameplayEffectContext::SetAbilitySource(const IOLSAbilitySourceInterface* object, float sourceLevel)
{
AbilitySourceObject = MakeWeakObjectPtr(Cast<const UObject>(object));
//SourceLevel = sourceLevel;
}
const IOLSAbilitySourceInterface* FOLSGameplayEffectContext::GetAbilitySource() const
{
return Cast<IOLSAbilitySourceInterface>(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;
}

View File

@ -194,6 +194,11 @@ void UOLSHeroComponent::CheckDefaultInitialization()
// ContinueInitStateChain(stateChain); // ContinueInitStateChain(stateChain);
} }
UOLSHeroComponent* UOLSHeroComponent::FindHeroComponent(const AActor* actor)
{
return (actor ? actor->FindComponentByClass<UOLSHeroComponent>() : nullptr);
}
void UOLSHeroComponent::ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& owningSpecHandle) void UOLSHeroComponent::ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& owningSpecHandle)
{ {
if (AbilityCameraModeOwningSpecHandle == owningSpecHandle) if (AbilityCameraModeOwningSpecHandle == owningSpecHandle)

View File

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

View File

@ -6,6 +6,8 @@
#include "Abilities/GameplayAbility.h" #include "Abilities/GameplayAbility.h"
#include "OLSGameplayAbility.generated.h" #include "OLSGameplayAbility.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogOLSGameplayAbility, Verbose, All);
/** /**
* ELyraAbilityActivationPolicy * ELyraAbilityActivationPolicy
* *
@ -78,9 +80,88 @@ class OLS_API UOLSGameplayAbility : public UGameplayAbility
GENERATED_BODY() GENERATED_BODY()
public: 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<ULyraCameraMode> 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: protected:
// Defines how this ability is meant to activate. // Defines how this ability is meant to activate.
@ -107,6 +188,7 @@ protected:
UPROPERTY(EditDefaultsOnly, Category = "Advanced") UPROPERTY(EditDefaultsOnly, Category = "Advanced")
uint8 bShouldLogCancellation : 1 = false; uint8 bShouldLogCancellation : 1 = false;
// @TODO: Implement OLSCameraMode
// Current camera mode set by the ability. // Current camera mode set by the ability.
// TSubclassOf<ULyraCameraMode> ActiveCameraMode; // TSubclassOf<OLSCameraMode> ActiveCameraMode;
}; };

View File

@ -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;
};

View File

@ -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<class APlayerController> PlayerController = nullptr;
UPROPERTY(BlueprintReadWrite)
FGameplayTagContainer FailureTags;
UPROPERTY(BlueprintReadWrite)
FText UserFacingReason;
};

View File

@ -5,6 +5,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "AbilitySystemComponent.h" #include "AbilitySystemComponent.h"
#include "NativeGameplayTags.h" #include "NativeGameplayTags.h"
#include "Abilities/OLSGameplayAbility.h"
#include "OLSAbilitySystemComponent.generated.h" #include "OLSAbilitySystemComponent.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogOLSAbilitySystemComponent, Verbose, All); DECLARE_LOG_CATEGORY_EXTERN(LogOLSAbilitySystemComponent, Verbose, All);
@ -157,17 +158,17 @@ protected:
virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& spec) override; virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& spec) override;
virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& spec) override; virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& spec) override;
virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle handle, UGameplayAbility* ability) override; virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle handle, class UGameplayAbility* ability) override;
virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle handle, UGameplayAbility* ability, const FGameplayTagContainer& failureReason) override; virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle handle, class UGameplayAbility* ability, const FGameplayTagContainer& failureReason) override;
virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle handle, UGameplayAbility* Ability, bool bWasCancelled) override; virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle handle, class 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 ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& abilityTags, class 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 HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& abilityTags, class UGameplayAbility* requestingAbility, bool canBeCanceled) override;
/** Notify client that an ability failed to activate */ /** Notify client that an ability failed to activate */
UFUNCTION(Client, Unreliable) 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. * Conveniently separates the code that sets the animation to replicate, so it can be further modified.
@ -176,7 +177,7 @@ protected:
public: public:
typedef TFunctionRef<bool(const class UOLSGameplayAbility* ability, FGameplayAbilitySpecHandle handle)> TShouldCancelAbilityFunc; typedef TFunctionRef<bool(const UOLSGameplayAbility* ability, FGameplayAbilitySpecHandle handle)> TShouldCancelAbilityFunc;
void CancelAbilitiesByFunc(TShouldCancelAbilityFunc shouldCancelFunc, bool shouldReplicateCancelAbility); void CancelAbilitiesByFunc(TShouldCancelAbilityFunc shouldCancelFunc, bool shouldReplicateCancelAbility);
void CancelInputActivatedAbilities(bool shouldReplicateCancelAbility); void CancelInputActivatedAbilities(bool shouldReplicateCancelAbility);
@ -187,11 +188,10 @@ public:
void ProcessAbilityInput(float deltaTime, bool shouldGamePaused); void ProcessAbilityInput(float deltaTime, bool shouldGamePaused);
void ClearAbilityInput(); void ClearAbilityInput();
// @TODO: Implement UOLSGameplayAbility. bool IsActivationGroupBlocked(EOLSAbilityActivationGroup Group) const;
// bool IsActivationGroupBlocked(ELyraAbilityActivationGroup Group) const; void AddAbilityToActivationGroup(EOLSAbilityActivationGroup group, UOLSGameplayAbility* ability);
// void AddAbilityToActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility); void RemoveAbilityFromActivationGroup(EOLSAbilityActivationGroup group, UOLSGameplayAbility* ability);
// void RemoveAbilityFromActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility); void CancelActivationGroupAbilities(EOLSAbilityActivationGroup group, UOLSGameplayAbility* ignoreAbility, bool shouldReplicateCancelAbility);
// void CancelActivationGroupAbilities(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* IgnoreLyraAbility, bool bReplicateCancelAbility);
// Uses a gameplay effect to add the specified dynamic granted tag. // Uses a gameplay effect to add the specified dynamic granted tag.
void AddDynamicTagGameplayEffect(const FGameplayTag& tag); void AddDynamicTagGameplayEffect(const FGameplayTag& tag);
@ -208,8 +208,6 @@ public:
/** Looks at ability tags and gathers additional required and blocking tags */ /** Looks at ability tags and gathers additional required and blocking tags */
void GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags, FGameplayTagContainer& outActivationRequired, FGameplayTagContainer& outActivationBlocked) const; void GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags, FGameplayTagContainer& outActivationRequired, FGameplayTagContainer& outActivationBlocked) const;
private: private:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "OLS Ability System", DisplayName = "Enable Ability Batch RPCs", meta = (AllowPrivateAccess = true)) 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. // Handles to abilities that have their input held.
TArray<FGameplayAbilitySpecHandle> InputHeldSpecHandles; TArray<FGameplayAbilitySpecHandle> InputHeldSpecHandles;
// Number of abilities running in each activation group.
int32 ActivationGroupCounts[(uint8)EOLSAbilityActivationGroup::MAX];
}; };

View File

@ -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<const UObject> AbilitySourceObject;
};
template<>
struct TStructOpsTypeTraits<FOLSGameplayEffectContext> : public TStructOpsTypeTraitsBase2<FOLSGameplayEffectContext>
{
enum
{
WithNetSerializer = true,
WithCopy = true
};
};

View File

@ -39,6 +39,11 @@ public:
/** The name of this component-implemented feature */ /** The name of this component-implemented feature */
static const FName NAME_ActorFeatureName; 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 */ /** Overrides the camera from an active gameplay ability */
//@TODO: implement UOLSCameraMode. //@TODO: implement UOLSCameraMode.
// void SetAbilityCameraMode(TSubclassOf<ULyraCameraMode> CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle); // void SetAbilityCameraMode(TSubclassOf<ULyraCameraMode> CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle);

View File

@ -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

View File

@ -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;
};

View File

@ -19,7 +19,11 @@ public class ols : ModuleRules
"GameFeatures", "GameFeatures",
"ModularGameplay", "ModularGameplay",
"EnhancedInput", "EnhancedInput",
"OLSAnimation", "AIModule", "CommonLoadingScreen", "CommonUser" "OLSAnimation",
"AIModule",
"CommonLoadingScreen",
"CommonUser",
"PhysicsCore"
}); });
PrivateDependencyModuleNames.AddRange(new[] PrivateDependencyModuleNames.AddRange(new[]