第一次提交

This commit is contained in:
不明不惑
2026-03-03 01:23:02 +08:00
commit 3e434877e8
1053 changed files with 102411 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utility/GCS_AttackDefinitionFunctionLibrary.h"
#include "CombatFlow/GCS_AttackDefinition.h"
#if WITH_EDITOR
void UGCS_AttackDefinitionFunctionLibrary::MigrateAttackDefinitionTable(UDataTable* InTable)
{
if (InTable && InTable->GetRowStruct()->IsChildOf(FGCS_AttackDefinition::StaticStruct()))
{
TArray<FGCS_AttackDefinition*> Rows;
InTable->GetAllRows<FGCS_AttackDefinition>(TEXT("Migration"),Rows);
InTable->MarkPackageDirty();
}
}
#endif

View File

@@ -0,0 +1,473 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utility/GCS_CombatFunctionLibrary.h"
#include "Components/SkeletalMeshComponent.h"
#include "GCS_CombatEntityInterface.h"
#include "GCS_CombatSystemSettings.h"
#include "Team/GCS_CombatTeamAgentInterface.h"
#include "GCS_LogChannels.h"
#include "GGA_GameplayEffectContext.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/Controller.h"
#include "AbilitySystem/GCS_GameplayEffectContext.h"
#include "CombatFlow/GCS_AttackRequest.h"
#include "GameFramework/Character.h"
#include "Kismet/KismetMathLibrary.h"
#include "Utilities/GGA_GameplayEffectFunctionLibrary.h"
#include "Weapon/GCS_WeaponInterface.h"
TScriptInterface<IGCS_CombatTeamAgentInterface> UGCS_CombatFunctionLibrary::GetCombatTeamAgentInterface(AActor* Actor)
{
if (IsValid(Actor))
{
if (Actor->GetClass()->ImplementsInterface(UGCS_CombatTeamAgentInterface::StaticClass()))
{
return Actor;
}
TArray<UActorComponent*> Components = Actor->GetComponentsByInterface(UGCS_CombatTeamAgentInterface::StaticClass());
return Components.IsValidIndex(0) ? Components[0] : nullptr;
}
return nullptr;
}
bool UGCS_CombatFunctionLibrary::FindCombatTeamAgentInterface(AActor* Actor, TScriptInterface<IGCS_CombatTeamAgentInterface>& OutInterface)
{
OutInterface = GetCombatTeamAgentInterface(Actor);
return OutInterface != nullptr;
}
TScriptInterface<IGCS_CombatEntityInterface> UGCS_CombatFunctionLibrary::GetCombatEntityInterface(AActor* Actor)
{
if (IsValid(Actor))
{
if (Actor->GetClass()->ImplementsInterface(UGCS_CombatEntityInterface::StaticClass()))
{
return Actor;
}
TArray<UActorComponent*> Components = Actor->GetComponentsByInterface(UGCS_CombatEntityInterface::StaticClass());
return Components.IsValidIndex(0) ? Components[0] : nullptr;
}
return nullptr;
}
UObject* UGCS_CombatFunctionLibrary::GetCombatEntity(AActor* Actor)
{
if (IsValid(Actor))
{
if (Actor->GetClass()->ImplementsInterface(UGCS_CombatEntityInterface::StaticClass()))
{
return Actor;
}
TArray<UActorComponent*> Components = Actor->GetComponentsByInterface(UGCS_CombatEntityInterface::StaticClass());
return Components.IsValidIndex(0) ? Components[0] : nullptr;
}
return nullptr;
}
TScriptInterface<IGCS_WeaponInterface> UGCS_CombatFunctionLibrary::GetWeaponInterface(AActor* Actor)
{
if (IsValid(Actor))
{
if (Actor->GetClass()->ImplementsInterface(UGCS_WeaponInterface::StaticClass()))
{
return Actor;
}
TArray<UActorComponent*> Components = Actor->GetComponentsByInterface(UGCS_WeaponInterface::StaticClass());
return Components.IsValidIndex(0) ? Components[0] : nullptr;
}
return nullptr;
}
USkeletalMeshComponent* UGCS_CombatFunctionLibrary::GetMainCharacterMeshComponent(AActor* Actor, FName OverrideMeshLookupTag)
{
if (IsValid(Actor))
{
if (OverrideMeshLookupTag != NAME_None)
{
TArray<UActorComponent*> Components = Actor->GetComponentsByTag(USkeletalMeshComponent::StaticClass(), OverrideMeshLookupTag);
if (Components.IsValidIndex(0))
{
return Cast<USkeletalMeshComponent>(Components[0]);
}
}
else if (const UGCS_CombatSystemSettings* Settings = UGCS_CombatSystemSettings::Get())
{
TArray<UActorComponent*> Components = Actor->GetComponentsByTag(USkeletalMeshComponent::StaticClass(), Settings->CharacterMeshLookupTag);
if (Components.IsValidIndex(0))
{
return Cast<USkeletalMeshComponent>(Components[0]);
}
}
if (ACharacter* Char = Cast<ACharacter>(Actor))
{
return Char->GetMesh();
}
if (USkeletalMeshComponent* Component = Cast<USkeletalMeshComponent>(Actor->GetComponentByClass(USkeletalMeshComponent::StaticClass())))
{
return Component;
}
UE_LOG(LogGCS, Warning, TEXT("Failed to find main character mesh component on actor class:%s"), *Actor->GetClass()->GetName());
}
return nullptr;
}
UMeshComponent* UGCS_CombatFunctionLibrary::GetMainMeshComponent(AActor* Actor, FName OverrideMeshLookupTag)
{
if (IsValid(Actor))
{
if (OverrideMeshLookupTag != NAME_None)
{
if (UActorComponent* Component = Actor->FindComponentByTag(UMeshComponent::StaticClass(), OverrideMeshLookupTag))
{
return Cast<UMeshComponent>(Component);
}
}
else if (const UGCS_CombatSystemSettings* Settings = UGCS_CombatSystemSettings::Get())
{
TArray<UActorComponent*> Components = Actor->GetComponentsByTag(UMeshComponent::StaticClass(), Settings->CharacterMeshLookupTag);
if (Components.IsValidIndex(0))
{
return Cast<UMeshComponent>(Components[0]);
}
}
if (UMeshComponent* Component = Cast<UMeshComponent>(Actor->GetComponentByClass(UMeshComponent::StaticClass())))
{
return Component;
}
UE_LOG(LogGCS, Warning, TEXT("Failed to find main mesh component on actor class:%s"), *Actor->GetClass()->GetName());
}
return nullptr;
}
TArray<FName> UGCS_CombatFunctionLibrary::GetSocketNamesWithPrefix(const USceneComponent* Component, FString Prefix, ESearchCase::Type SearchCase)
{
if (IsValid(Component))
{
return Component->GetAllSocketNames().FilterByPredicate([&](const FName& SocketName)
{
return SocketName.ToString().StartsWith(Prefix, SearchCase);
});
}
return {};
}
bool UGCS_CombatFunctionLibrary::FindCombatInterface(AActor* Actor, TScriptInterface<IGCS_CombatEntityInterface>& OutInterface)
{
OutInterface = GetCombatEntityInterface(Actor);
return OutInterface.GetObject() != nullptr;
}
bool UGCS_CombatFunctionLibrary::FindWeaponInterface(AActor* Actor, TScriptInterface<IGCS_WeaponInterface>& OutInterface)
{
OutInterface = GetWeaponInterface(Actor);
return OutInterface.GetObject() != nullptr;
}
FRotator UGCS_CombatFunctionLibrary::CalculateAngleBetweenActors(const AActor* From, const AActor* To)
{
if (IsValid(From) && IsValid(To))
{
return UKismetMathLibrary::NormalizedDeltaRotator(UKismetMathLibrary::FindLookAtRotation(From->GetActorLocation(), To->GetActorLocation()), From->GetActorRotation());
}
// TODO Warning.
return FRotator::ZeroRotator;
}
bool UGCS_CombatFunctionLibrary::IsSameCombatTeam(const AActor* A, const AActor* B)
{
return GetCombatTeamId(A) == GetCombatTeamId(B);
}
FGenericTeamId UGCS_CombatFunctionLibrary::GetCombatTeamId(const AActor* Actor)
{
return QueryCombatTeamId(Actor, true, true);
}
FGenericTeamId UGCS_CombatFunctionLibrary::QueryCombatTeamId(const AActor* Actor, bool bCombatAgent, bool bGenericAgent)
{
if (!IsValid(Actor))
{
return FGenericTeamId::NoTeam;
}
if (bCombatAgent)
{
if (Actor->GetClass()->ImplementsInterface(UGCS_CombatTeamAgentInterface::StaticClass()))
{
return IGCS_CombatTeamAgentInterface::Execute_GetCombatTeamId(Actor);
}
TArray<UActorComponent*> Components = Actor->GetComponentsByInterface(UGCS_CombatTeamAgentInterface::StaticClass());
if (Components.IsValidIndex(0))
{
return IGCS_CombatTeamAgentInterface::Execute_GetCombatTeamId(Components[0]);
}
if (const APawn* Pawn = Cast<APawn>(Actor))
{
if (Pawn->GetController() && Pawn->GetController()->GetClass()->ImplementsInterface(UGCS_CombatTeamAgentInterface::StaticClass()))
{
return IGCS_CombatTeamAgentInterface::Execute_GetCombatTeamId(Pawn->GetController());
}
}
}
if (bGenericAgent)
{
if (const IGenericTeamAgentInterface* GenericTeamAgentInterface = Cast<IGenericTeamAgentInterface>(Actor))
{
return GenericTeamAgentInterface->GetGenericTeamId();
}
if (const APawn* Pawn = Cast<APawn>(Actor))
{
if (const IGenericTeamAgentInterface* GenericTeamAgentInterface = Cast<IGenericTeamAgentInterface>(Pawn->GetController()))
{
return GenericTeamAgentInterface->GetGenericTeamId();
}
}
}
return FGenericTeamId::NoTeam;
}
EGCS_Direction UGCS_CombatFunctionLibrary::CalculateDirectionFromAngle(const float Angle)
{
if (UKismetMathLibrary::InRange_FloatFloat(Angle, -45.0f, 45.0f))
{
return EGCS_Direction::Forward;
}
if (UKismetMathLibrary::InRange_FloatFloat(Angle, 45.0f, 135.f))
{
return EGCS_Direction::Right;
}
if (UKismetMathLibrary::InRange_FloatFloat(Angle, -135.f, -45.f))
{
return EGCS_Direction::Left;
}
return EGCS_Direction::Backward;
}
TSoftObjectPtr<UAnimMontage> UGCS_CombatFunctionLibrary::SelectMontageByDirection(EGCS_Direction Direction, TArray<TSoftObjectPtr<UAnimMontage>> Montages)
{
switch (Direction)
{
case EGCS_Direction::Forward:
return Montages.IsValidIndex(0) ? Montages[0] : nullptr;
case EGCS_Direction::Backward:
return Montages.IsValidIndex(1) ? Montages[1] : nullptr;
case EGCS_Direction::Left:
return Montages.IsValidIndex(2) ? Montages[2] : nullptr;
case EGCS_Direction::Right:
return Montages.IsValidIndex(3) ? Montages[3] : nullptr;
}
return nullptr;
}
void UGCS_CombatFunctionLibrary::AddTaggedValue(TArray<FGCS_TaggedValue>& TaggedValues, FGameplayTag Tag, float ValueToAdd)
{
bool bFound = false;
for (FGCS_TaggedValue& TaggedValue : TaggedValues)
{
if (TaggedValue.Attribute == Tag)
{
TaggedValue.Value += ValueToAdd;
bFound = true;
break;
}
}
if (!bFound)
{
FGCS_TaggedValue Temp;
Temp.Attribute = Tag;
Temp.Value = ValueToAdd;
TaggedValues.Add(Temp);
}
}
float UGCS_CombatFunctionLibrary::GetTaggedValue(const TArray<FGCS_TaggedValue> TaggedValues, FGameplayTag Tag)
{
for (const FGCS_TaggedValue& TaggedValue : TaggedValues)
{
if (TaggedValue.Attribute == Tag)
{
return TaggedValue.Value;
}
}
return 0;
}
FGameplayTagContainer UGCS_CombatFunctionLibrary::FilterGameplayTagContainer(const FGameplayTagContainer& TagContainer, FGameplayTagContainer OtherContainer)
{
return TagContainer.Filter(OtherContainer);
}
FGameplayEffectSpecHandle UGCS_CombatFunctionLibrary::AddAttackHandleToGameplayEffectSpec(FGameplayEffectSpecHandle SpecHandle, FDataTableRowHandle AttackHandle)
{
if (SpecHandle.IsValid() && !AttackHandle.IsNull())
{
if (FGCS_AttackDefinition* AtkDef = AttackHandle.GetRow<FGCS_AttackDefinition>(TEXT("AddAttackHandleToGameplayEffectSpec")))
{
AddAttackDefinitionToGameplayEffectSpec(SpecHandle, *AtkDef);
}
FGameplayEffectContextHandle ContextHandle = SpecHandle.Data->GetEffectContext();
EffectContextSetAttackDefinitionHandle(ContextHandle, AttackHandle);
}
return SpecHandle;
}
FGameplayEffectSpecHandle UGCS_CombatFunctionLibrary::AddAttackDefinitionToGameplayEffectSpec(FGameplayEffectSpecHandle SpecHandle, const FGCS_AttackDefinition& AtkDefinition)
{
if (SpecHandle.IsValid())
{
SpecHandle.Data->AppendDynamicAssetTags(AtkDefinition.AttackTags);
// apply set by callers from atk definition.
for (const TTuple<FGameplayTag, float>& ByCallerMagnitude : AtkDefinition.SetByCallerMagnitudes)
{
if (ByCallerMagnitude.Key.IsValid() && ByCallerMagnitude.Value > 0)
{
SpecHandle.Data->SetSetByCallerMagnitude(ByCallerMagnitude.Key, ByCallerMagnitude.Value);
}
}
}
return SpecHandle;
}
void UGCS_CombatFunctionLibrary::AddAttackHandleToGameplayEffectContainerSpec(FGGA_GameplayEffectContainerSpec ContainerSpec, FDataTableRowHandle AttackHandle)
{
if (!AttackHandle.IsNull())
{
if (FGCS_AttackDefinition* AtkDef = AttackHandle.GetRow<FGCS_AttackDefinition>(TEXT("AddAttackHandleToGameplayEffectSpec")))
{
for (const FGameplayEffectSpecHandle& SpecHandle : ContainerSpec.TargetGameplayEffectSpecs)
{
AddAttackDefinitionToGameplayEffectSpec(SpecHandle, *AtkDef);
FGameplayEffectContextHandle ContextHandle = SpecHandle.Data->GetEffectContext();
EffectContextSetAttackDefinitionHandle(ContextHandle, AttackHandle);
}
}
}
}
void UGCS_CombatFunctionLibrary::EffectContextSetAttackDefinitionHandle(FGameplayEffectContextHandle EffectContext, FDataTableRowHandle Handle)
{
if (FGCS_ContextPayload_Combat* Payload = EffectContextGetMutableCombatPayload(EffectContext))
{
Payload->AtkDataTable = Handle.DataTable;
Payload->AtkRowName = Handle.RowName;
}
else
{
UE_LOG(LogGCS, Error, TEXT("Can't access GCS_GameplayEffectContext! You need to setup GCS_AbilitySystemGlobals as AbilitySystemGlobalsClassName."))
}
}
FGCS_ContextPayload_Combat UGCS_CombatFunctionLibrary::EffectContextGetCombatPayload(FGameplayEffectContextHandle EffectContext)
{
if (FGGA_GameplayEffectContext* Context = UGGA_GameplayEffectFunctionLibrary::GetEffectContextPtr(EffectContext))
{
if (FGCS_ContextPayload_Combat* CombatPayload = Context->FindMutablePayloadByType<FGCS_ContextPayload_Combat>())
{
return *CombatPayload;
}
}
return FGCS_ContextPayload_Combat();
}
FGCS_ContextPayload_Combat* UGCS_CombatFunctionLibrary::EffectContextGetMutableCombatPayload(const FGameplayEffectContextHandle& EffectContext)
{
if (FGGA_GameplayEffectContext* Context = UGGA_GameplayEffectFunctionLibrary::GetEffectContextPtr(EffectContext))
{
if (FGCS_ContextPayload_Combat* CombatPayload = Context->FindOrAddMutablePayloadPtr<FGCS_ContextPayload_Combat>())
{
return CombatPayload;
}
}
return nullptr;
}
void UGCS_CombatFunctionLibrary::EffectContextAddTagToCombatPayload(FGameplayEffectContextHandle EffectContext, FGameplayTag TagToAdd)
{
if (TagToAdd.IsValid())
{
if (FGCS_ContextPayload_Combat* Payload = EffectContextGetMutableCombatPayload(EffectContext))
{
Payload->DynamicTags.AddTagFast(TagToAdd);
}
}
}
void UGCS_CombatFunctionLibrary::EffectContextSetTaggedValueToCombatPayload(FGameplayEffectContextHandle EffectContext, FGameplayTag Tag, float NewValue)
{
if (FGCS_ContextPayload_Combat* Payload = EffectContextGetMutableCombatPayload(EffectContext))
{
Payload->SetTaggedValue(Tag, NewValue);
}
}
float UGCS_CombatFunctionLibrary::EffectContextGetTaggedValueFromCombatPayload(FGameplayEffectContextHandle EffectContext, FGameplayTag Tag)
{
if (FGCS_ContextPayload_Combat* Payload = EffectContextGetMutableCombatPayload(EffectContext))
{
return Payload->GetTaggedValue(Tag);
}
return 0;
}
void UGCS_CombatFunctionLibrary::EffectContextGetDynamicTagsFromCombatPayload(FGameplayEffectContextHandle EffectContext, FGameplayTagContainer& OutTags)
{
if (FGCS_ContextPayload_Combat* Payload = EffectContextGetMutableCombatPayload(EffectContext))
{
OutTags.Reset();
OutTags = Payload->DynamicTags;
}
}
FDataTableRowHandle UGCS_CombatFunctionLibrary::EffectContextGetAttackDefinitionHandle(FGameplayEffectContextHandle EffectContext)
{
if (FGCS_ContextPayload_Combat* Payload = EffectContextGetMutableCombatPayload(EffectContext))
{
FDataTableRowHandle Handle;
Handle.DataTable = Payload->AtkDataTable;
Handle.RowName = Payload->AtkRowName;
return Handle;
}
return FDataTableRowHandle();
}
bool UGCS_CombatFunctionLibrary::EffectContextGetIsPredictingContext(FGameplayEffectContextHandle EffectContext)
{
if (FGCS_ContextPayload_Combat* Payload = EffectContextGetMutableCombatPayload(EffectContext))
{
return Payload->bIsPredictingContext;
}
return false;
}
FGCS_AttackDefinition UGCS_CombatFunctionLibrary::EffectContextGetAttackDefinition(FGameplayEffectContextHandle EffectContext)
{
FDataTableRowHandle Handle = EffectContextGetAttackDefinitionHandle(EffectContext);
if (FGCS_AttackDefinition* Def = Handle.GetRow<FGCS_AttackDefinition>(TEXT("EffectContextGetAttackDefinition")))
{
return *Def;
}
return FGCS_AttackDefinition();
}