// Copyright 2025 https://yuewu.dev/en All Rights Reserved. #include "CombatFlow/GCS_CombatFlow.h" #include "AbilitySystemBlueprintLibrary.h" #include "GameFramework/Pawn.h" #include "Utilities/GGA_AbilitySystemFunctionLibrary.h" #include "GCS_CombatSystemComponent.h" #include "GCS_LogChannels.h" #include "CombatFlow/GCS_AttackResultProcessor.h" #include "Utility/GCS_CombatFunctionLibrary.h" UGCS_CombatFlow::UGCS_CombatFlow() { Owner = nullptr; } void UGCS_CombatFlow::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); } void UGCS_CombatFlow::Initialize(AActor* NewOwner) { Owner = NewOwner; // ProcessedAttacks.SetCombatFlow(this); CombatComponent = UGCS_CombatSystemComponent::GetCombatSystemComponent(Owner); } void UGCS_CombatFlow::HandlePreGameplayEffectSpecApply_Implementation(const FGameplayEffectSpec& Spec, UAbilitySystemComponent* AbilitySystemComponent, FGameplayTagContainer& OutDynamicTagsAppendToSpec) { } void UGCS_CombatFlow::HandleGameplayEffectExecute_Implementation(const FGGA_GameplayEffectModCallbackData& Payload) { } void UGCS_CombatFlow::HandleAttackResult_Implementation(const FGCS_AttackResult& InPayload) { FGCS_AttackResult ModifiedPayload = InPayload; bool bPredictingContext = UGCS_CombatFunctionLibrary::EffectContextGetIsPredictingContext(InPayload.EffectContextHandle); const FGCS_ContextPayload_Combat* CombatPayload = UGCS_CombatFunctionLibrary::EffectContextGetMutableCombatPayload(ModifiedPayload.EffectContextHandle); if (CombatPayload) { ModifiedPayload.AggregatedSourceTags.AppendTags(CombatPayload->DynamicTags); } CombatComponent->SetLastProcessedAttackResult(ModifiedPayload); for (int32 i = 0; i < AttackResultProcessors.Num(); i++) { auto& Processor = AttackResultProcessors[i]; if (!IsValid(Processor)) { continue; } bool bShouldExecute = Processor->GetExecutePolicy() == EGCS_AttackResultProcessorPolicy::Default && !bPredictingContext; if (Processor->GetExecutePolicy() == EGCS_AttackResultProcessorPolicy::LocalPredicted) { bShouldExecute = bPredictingContext || !InPayload.bWasPredicated; if (!bShouldExecute) { GCS_OWNED_CLOG(GetFlowOwner(), VeryVerbose, "Skipped local predicted processor at idx(%d) of type(%s)", i, *Processor->GetClass()->GetName()) } } if (Processor->GetExecutePolicy() == EGCS_AttackResultProcessorPolicy::ServerOnly) { bShouldExecute = !bPredictingContext && !InPayload.bWasReplicated; if (!bShouldExecute) { GCS_OWNED_CLOG(GetFlowOwner(), VeryVerbose, "Skipped server only processor at idx(%d) of type(%s)", i, *Processor->GetClass()->GetName()) } } if (bShouldExecute) { #if WITH_EDITOR // Debugging says not enabled. if (!Processor->GetEditorEnableState()) { continue; } #endif if (Processor->ProcessIncomingAttackResult(ModifiedPayload)) { GCS_OWNED_CLOG(GetFlowOwner(), VeryVerbose, "%sExecuted processor at idx(%d) of type(%s)", bPredictingContext?TEXT("Predicate "):TEXT(""), i, *Processor->GetClass()->GetName()) } } } }