Files
PHY/Plugins/GCS/Source/GenericCombatSystem/Private/Weapon/GCS_WeaponActor.cpp
2026-03-03 01:23:02 +08:00

189 lines
5.3 KiB
C++

// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Weapon/GCS_WeaponActor.h"
#include "Components/PrimitiveComponent.h"
#include "GameFramework/Pawn.h"
#include "GCS_LogChannels.h"
#include "Collision/GCS_TraceSystemComponent.h"
#include "Misc/DataValidation.h"
#include "Net/UnrealNetwork.h"
#include "Net/Core/PushModel/PushModel.h"
AGCS_WeaponActor::AGCS_WeaponActor(const FObjectInitializer& ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
bReplicates = true;
bWeaponActive = false;
}
APawn* AGCS_WeaponActor::GetWeaponOwner_Implementation() const
{
return Cast<APawn>(GetOwner());
}
const FGameplayTagContainer AGCS_WeaponActor::GetWeaponTags_Implementation() const
{
return WeaponTags;
}
void AGCS_WeaponActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
FDoRepLifetimeParams Parameters;
Parameters.bIsPushBased = true;
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, bWeaponActive, Parameters)
}
void AGCS_WeaponActor::SetWeaponActive_Implementation(bool bNewActive)
{
if (GetOwner()->HasAuthority())
{
const bool prev = bWeaponActive;
bWeaponActive = bNewActive;
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, bWeaponActive, this);
OnWeaponActiveStateChanged(prev);
}
}
bool AGCS_WeaponActor::IsWeaponActive_Implementation() const
{
return bWeaponActive;
}
UPrimitiveComponent* AGCS_WeaponActor::GetPrimitiveComponent_Implementation() const
{
if (WeaponMeshTagName.IsValid())
{
UPrimitiveComponent* Primitive = Cast<UPrimitiveComponent>(GetOwner()->FindComponentByTag(UPrimitiveComponent::StaticClass(), WeaponMeshTagName));
if (!IsValid(Primitive))
{
GCS_CLOG(Warning, "failed to find weapon mesh via tag (%s) as weapon primitive component. weapon owner:%s",
*WeaponMeshTagName.ToString(),
*GetOwner()->GetName());
return nullptr;
}
return Primitive;
}
GCS_CLOG(Warning, "no weapon primitive component provided. weapon owner:%s", *GetOwner()->GetName());
return nullptr;
}
void AGCS_WeaponActor::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const
{
TagContainer = Execute_GetWeaponTags(this);
}
void AGCS_WeaponActor::OnWeaponActiveStateChanged_Implementation(bool Prev)
{
OnWeaponActiveStateChangedEvent.Broadcast(bWeaponActive);
}
void AGCS_WeaponActor::BeginPlay()
{
Super::BeginPlay();
}
void AGCS_WeaponActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (Execute_IsWeaponActive(this))
{
bWeaponActive = false;
RefreshTraceInstance();
}
Super::EndPlay(EndPlayReason);
}
void AGCS_WeaponActor::RefreshTraceInstance_Implementation()
{
APawn* Pawn = Execute_GetWeaponOwner(this);
if (!IsValid(Pawn))
{
GCS_CLOG(Warning, "mising weapon owner!")
return;
}
UGCS_TraceSystemComponent* TSC = UGCS_TraceSystemComponent::GetTraceSystemComponent(Pawn);
if (!IsValid(TSC))
{
GCS_CLOG(Warning, "missing trace system on weapon owner(%s)!", *GetNameSafe(Pawn))
return;
}
if (bWeaponActive)
{
TraceHandles.Reset();
for (const FGCS_TraceDefinition& TraceDefinition : TraceDefinitions)
{
UPrimitiveComponent* Primitive = GetSourceComponentForTrace(TraceDefinition.TraceTag);
if (Primitive == nullptr)
{
GCS_CLOG(Error, "No SourceComponent provided for trace:%s,check your GetSourceComponentForTrace implementation.", *TraceDefinition.TraceTag.ToString());
continue;
}
FGCS_TraceHandle Handle = TSC->AddTrace(TraceDefinition, Primitive, GetSourceObjectForTrace());
if (Handle.IsValidHandle())
{
TraceHandles.Add(Handle);
}
}
TSC->OnTraceHitEvent.AddDynamic(this, &ThisClass::OnAnyTraceHit);
TSC->OnTraceStateChangedEvent.AddDynamic(this, &ThisClass::OnAnyTraceStateChanged);
}
else
{
TSC->OnTraceHitEvent.RemoveDynamic(this, &ThisClass::OnAnyTraceHit);
TSC->OnTraceStateChangedEvent.RemoveDynamic(this, &ThisClass::OnAnyTraceStateChanged);
for (const FGCS_TraceHandle& TraceHandle : TraceHandles)
{
TSC->RemoveTrace(TraceHandle);
}
}
}
UObject* AGCS_WeaponActor::GetSourceObjectForTrace_Implementation()
{
return this;
}
UPrimitiveComponent* AGCS_WeaponActor::GetSourceComponentForTrace_Implementation(const FGameplayTag& TraceTag) const
{
// Default Using weapon primitive as source component for trace
if (UPrimitiveComponent* PrimitiveComponent = Execute_GetPrimitiveComponent(this))
{
return PrimitiveComponent;
}
GCS_CLOG(Error, "Weapon(%s) didn't return return valid primitive component to be used as SourceComponent for traces, try implement this function to get properly SourceComponent For Trace.",
*GetNameSafe(this))
return nullptr;
}
void AGCS_WeaponActor::OnAnyTraceHit_Implementation(const FGCS_TraceHandle& TraceHandle, const FHitResult& HitResult)
{
}
void AGCS_WeaponActor::OnAnyTraceStateChanged_Implementation(const FGCS_TraceHandle& TraceHandle, bool NewState)
{
}
void AGCS_WeaponActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
#if WITH_EDITOR
EDataValidationResult AGCS_WeaponActor::IsDataValid(class FDataValidationContext& Context) const
{
for (int32 i = 0; i < TraceDefinitions.Num(); i++)
{
if (!TraceDefinitions[i].IsValidDefinition())
{
Context.AddWarning(FText::FromString(FString::Format(TEXT("Found invalid trace definition at index({0})"), {i})));
return EDataValidationResult::Invalid;
}
}
return Super::IsDataValid(Context);
}
#endif