189 lines
5.3 KiB
C++
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
|