第一次提交
This commit is contained in:
@@ -0,0 +1,489 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
#include "Collision/GCS_TraceSystemComponent.h"
|
||||
#include "GCS_LogChannels.h"
|
||||
#include "Collision/DEPRECATED_GCS_CollisionTraceInstance.h"
|
||||
#include "Collision/GCS_TraceSubsystem.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "Components/PrimitiveComponent.h"
|
||||
#include "Utility/GCS_CombatFunctionLibrary.h"
|
||||
|
||||
UGCS_TraceSystemComponent::UGCS_TraceSystemComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
SetIsReplicatedByDefault(false);
|
||||
}
|
||||
|
||||
UGCS_TraceSystemComponent* UGCS_TraceSystemComponent::GetTraceSystemComponent(const AActor* Actor)
|
||||
{
|
||||
return IsValid(Actor) ? Actor->FindComponentByClass<UGCS_TraceSystemComponent>() : nullptr;
|
||||
}
|
||||
|
||||
bool UGCS_TraceSystemComponent::FindTraceSystemComponent(const AActor* Actor, UGCS_TraceSystemComponent*& Component)
|
||||
{
|
||||
Component = GetTraceSystemComponent(Actor);
|
||||
return Component != nullptr;
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::OnInitialize_Implementation()
|
||||
{
|
||||
if (UMeshComponent* PrimitiveComp = UGCS_CombatFunctionLibrary::GetMainMeshComponent(GetOwner()))
|
||||
{
|
||||
AddTraces(TraceDefinitions, PrimitiveComp, GetOwner());
|
||||
}
|
||||
|
||||
bInitialized = true;
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::OnDeinitialize_Implementation()
|
||||
{
|
||||
if (bInitialized)
|
||||
{
|
||||
RemoveAllTraces();
|
||||
bInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the game starts
|
||||
void UGCS_TraceSystemComponent::BeginPlay()
|
||||
{
|
||||
if (bAutoInitialize)
|
||||
{
|
||||
OnInitialize();
|
||||
}
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
Super::EndPlay(EndPlayReason);
|
||||
OnDeinitialize();
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::OnComponentDestroyed(bool bDestroyingHierarchy)
|
||||
{
|
||||
Super::OnComponentDestroyed(bDestroyingHierarchy);
|
||||
OnDestroyedEvent.Broadcast();
|
||||
|
||||
OnDeinitialize();
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::AddTraces(const TArray<FGCS_TraceDefinition>& Definitions, UPrimitiveComponent* SourceComponent, UObject* SourceObject)
|
||||
{
|
||||
TArray<FGCS_TraceHandle> Handles;
|
||||
for (const FGCS_TraceDefinition& Def : Definitions)
|
||||
{
|
||||
FGCS_TraceHandle Handle = AddTrace(Def, SourceComponent, SourceObject);
|
||||
if (Handle.IsValidHandle())
|
||||
{
|
||||
Handles.Add(Handle);
|
||||
}
|
||||
}
|
||||
return Handles;
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::AddTraces(const TArray<FDataTableRowHandle>& DefinitionHandles, UPrimitiveComponent* SourceComponent, UObject* SourceObject)
|
||||
{
|
||||
TArray<FGCS_TraceHandle> Handles;
|
||||
for (const FDataTableRowHandle& DefHandle : DefinitionHandles)
|
||||
{
|
||||
FGCS_TraceHandle Handle = AddTrace(DefHandle, SourceComponent, SourceObject);
|
||||
if (Handle.IsValidHandle())
|
||||
{
|
||||
Handles.Add(Handle);
|
||||
}
|
||||
}
|
||||
return Handles;
|
||||
}
|
||||
|
||||
FGCS_TraceHandle UGCS_TraceSystemComponent::AddTrace(const FGCS_TraceDefinition& TraceDefinition, UPrimitiveComponent* SourceComponent, UObject* SourceObject)
|
||||
{
|
||||
if (!TraceDefinition.IsValidDefinition())
|
||||
{
|
||||
GCS_CLOG(Warning, "Try adding invalid trace definition!")
|
||||
return FGCS_TraceHandle();
|
||||
}
|
||||
|
||||
if (!IsValid(SourceObject))
|
||||
{
|
||||
GCS_CLOG(Warning, "Missing source object for trace definition:%s", *TraceDefinition.ToString())
|
||||
return FGCS_TraceHandle();
|
||||
}
|
||||
|
||||
if (!IsValid(SourceComponent))
|
||||
{
|
||||
GCS_CLOG(Warning, "Missing source component for trace definition:%s", *TraceDefinition.ToString())
|
||||
return FGCS_TraceHandle();
|
||||
}
|
||||
|
||||
FInstancedStruct Shape = TraceDefinition.CollisionShape;
|
||||
bool bWasInitialized = Shape.GetMutable<FGCS_CollisionShape>().InitializeShape(SourceComponent);
|
||||
|
||||
if (!bWasInitialized)
|
||||
{
|
||||
return FGCS_TraceHandle();
|
||||
}
|
||||
|
||||
UWorld* World = GetWorld();
|
||||
if (!IsValid(World))
|
||||
{
|
||||
GCS_CLOG(Error, "Invalid world context!")
|
||||
return FGCS_TraceHandle();
|
||||
}
|
||||
|
||||
UGCS_TraceSubsystem* Subsystem = World->GetSubsystem<UGCS_TraceSubsystem>();
|
||||
if (!IsValid(Subsystem))
|
||||
{
|
||||
GCS_CLOG(Error, "Failed to get TraceSubsystem!")
|
||||
return FGCS_TraceHandle();
|
||||
}
|
||||
int32 StateIdx = Subsystem->AddTraceState();
|
||||
|
||||
FGCS_TraceHandle Handle = {TraceDefinition.TraceTag, FGuid::NewGuid(), SourceObject};
|
||||
|
||||
float TickInterval = 0;
|
||||
float AngleThreshold = TraceDefinition.AngleTickThreshold;
|
||||
if (TraceDefinition.TraceTickType == EGCS_TraceTickType::DistanceBased)
|
||||
{
|
||||
TickInterval = TraceDefinition.DistanceTickThreshold;
|
||||
}
|
||||
else if (TraceDefinition.TraceTickType == EGCS_TraceTickType::FixedFrameRate)
|
||||
{
|
||||
TickInterval = 1.0f / static_cast<float>(TraceDefinition.FixedTickFrameRate);
|
||||
}
|
||||
auto& TraceState = Subsystem->GetTraceStateAt(StateIdx);
|
||||
TraceState.World = GetWorld();
|
||||
TraceState.SourceComponent = SourceComponent;
|
||||
TraceState.OwningSystem = this;
|
||||
|
||||
TraceState.SweepSetting = TraceDefinition.SweepSetting;
|
||||
TraceState.Shape = Shape;
|
||||
|
||||
TraceState.Handle = Handle;
|
||||
TraceState.ExecutionState = EGCS_TraceExecutionState::Stopped;
|
||||
TraceState.TimeSinceLastTick = 0;
|
||||
TraceState.TimeSinceActive = 0;
|
||||
TraceState.TickPolicy = TraceDefinition.TraceTickType;
|
||||
TraceState.TickInterval = TickInterval;
|
||||
TraceState.AngleThreshold = AngleThreshold;
|
||||
TraceState.bShouldTickThisFrame = false;
|
||||
if (AActor* Owner = GetOwner())
|
||||
{
|
||||
TraceState.CollisionParams.AddIgnoredActor(Owner);
|
||||
}
|
||||
TraceState.CollisionParams.bTraceComplex = TraceDefinition.SweepSetting.bTraceComplex;
|
||||
TraceState.CollisionParams.bReturnPhysicalMaterial = true;
|
||||
for (const auto& ObjType : TraceDefinition.SweepSetting.ObjectTypes)
|
||||
{
|
||||
TraceState.ObjectQueryParams.AddObjectTypesToQuery(ObjType);
|
||||
}
|
||||
|
||||
HandleToStateIdx.Add(Handle, StateIdx);
|
||||
TagToHandles.Add(TraceDefinition.TraceTag, Handle);
|
||||
GCS_CLOG(Verbose, "Added trace(%s) with source component:%s", *Handle.ToDebugString(), *GetNameSafe(SourceComponent))
|
||||
return Handle;
|
||||
}
|
||||
|
||||
FGCS_TraceHandle UGCS_TraceSystemComponent::AddTrace(const FDataTableRowHandle& TraceDefinitionHandle, UPrimitiveComponent* SourceComponent, UObject* SourceObject)
|
||||
{
|
||||
if (!TraceDefinitionHandle.IsNull())
|
||||
{
|
||||
if (FGCS_TraceDefinition* TraceDefinition = TraceDefinitionHandle.GetRow<FGCS_TraceDefinition>(TEXT("AddTrace")))
|
||||
{
|
||||
AddTrace(*TraceDefinition, SourceComponent, SourceObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
GCS_CLOG(Warning, "definition handle doesn't point to valid TraceDefinition Table. %s", *TraceDefinitionHandle.ToDebugString())
|
||||
}
|
||||
}
|
||||
GCS_CLOG(Warning, "Passed in invalid trace definition handle! %s", *TraceDefinitionHandle.ToDebugString())
|
||||
return FGCS_TraceHandle();
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::RemoveTraces(const TArray<FGCS_TraceHandle>& TraceHandles)
|
||||
{
|
||||
for (const FGCS_TraceHandle& TraceHandle : TraceHandles)
|
||||
{
|
||||
RemoveTrace(TraceHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::RemoveTrace(const FGCS_TraceHandle& TraceHandle)
|
||||
{
|
||||
if (TraceHandle.IsValidHandle())
|
||||
{
|
||||
if (const int32* StateIdx = HandleToStateIdx.Find(TraceHandle))
|
||||
{
|
||||
UGCS_TraceSubsystem* Subsystem = GetWorld()->GetSubsystem<UGCS_TraceSubsystem>();
|
||||
if (IsValid(Subsystem) && Subsystem->IsValidStateIdx(*StateIdx))
|
||||
{
|
||||
auto& State = Subsystem->GetTraceStateAt(*StateIdx);
|
||||
State.ChangeExecutionState(false);
|
||||
OnTraceStateChanged(TraceHandle, false);
|
||||
Subsystem->RemoveTraceState(*StateIdx, TraceHandle.Guid);
|
||||
GCS_CLOG(Verbose, "Removed trace(%s)", *TraceHandle.ToDebugString())
|
||||
}
|
||||
HandleToStateIdx.Remove(TraceHandle);
|
||||
TagToHandles.RemoveSingle(TraceHandle.TraceTag, TraceHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::GetTraceHandlesBySource(const UObject* SourceObject) const
|
||||
{
|
||||
TArray<FGCS_TraceHandle> Handles;
|
||||
for (const auto& Pair : HandleToStateIdx)
|
||||
{
|
||||
if (Pair.Key.SourceObject == SourceObject)
|
||||
{
|
||||
Handles.Add(Pair.Key);
|
||||
}
|
||||
}
|
||||
return Handles;
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::GetTraceHandlesByTagsAndSource(const FGameplayTagContainer& TraceTags, const UObject* SourceObject) const
|
||||
{
|
||||
TArray<FGCS_TraceHandle> Handles;
|
||||
for (const FGameplayTag& Tag : TraceTags)
|
||||
{
|
||||
TArray<FGCS_TraceHandle> TagHandles;
|
||||
TagToHandles.MultiFind(Tag, TagHandles);
|
||||
for (const FGCS_TraceHandle& Handle : TagHandles)
|
||||
{
|
||||
if (!IsValid(SourceObject) || Handle.SourceObject == SourceObject)
|
||||
{
|
||||
Handles.AddUnique(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Handles;
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::StartTraces(const FGameplayTagContainer& TraceTags, const UObject* SourceObject)
|
||||
{
|
||||
TArray<FGCS_TraceHandle> Handles = GetTraceHandlesByTagsAndSource(TraceTags, SourceObject);
|
||||
for (const FGCS_TraceHandle& Handle : Handles)
|
||||
{
|
||||
StartTrace(Handle);
|
||||
}
|
||||
return Handles;
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StartTraces(const TArray<FGCS_TraceHandle>& TraceHandles)
|
||||
{
|
||||
for (const FGCS_TraceHandle& Handle : TraceHandles)
|
||||
{
|
||||
StartTrace(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StartTrace(const FGCS_TraceHandle& TraceHandle)
|
||||
{
|
||||
if (TraceHandle.IsValidHandle())
|
||||
{
|
||||
if (const int32* StateIdx = HandleToStateIdx.Find(TraceHandle))
|
||||
{
|
||||
auto& State = GetWorld()->GetSubsystem<UGCS_TraceSubsystem>()->GetTraceStateAt(*StateIdx);
|
||||
GCS_CLOG(Verbose, "Started trace(%s).", *TraceHandle.ToDebugString())
|
||||
State.ChangeExecutionState(true);
|
||||
OnTraceStateChanged(TraceHandle, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StopTraces(const TArray<FGCS_TraceHandle>& TraceHandles)
|
||||
{
|
||||
UGCS_TraceSubsystem* Subsystem = GetWorld()->GetSubsystem<UGCS_TraceSubsystem>();
|
||||
for (const FGCS_TraceHandle& TraceHandle : TraceHandles)
|
||||
{
|
||||
if (TraceHandle.IsValidHandle())
|
||||
{
|
||||
if (const int32* StateIdx = HandleToStateIdx.Find(TraceHandle))
|
||||
{
|
||||
auto& State = Subsystem->GetTraceStateAt(*StateIdx);
|
||||
GCS_CLOG(Verbose, "Stopped trace(%s).", *TraceHandle.ToDebugString())
|
||||
State.ChangeExecutionState(false);
|
||||
OnTraceStateChanged(TraceHandle, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StopTrace(const FGCS_TraceHandle& TraceHandle)
|
||||
{
|
||||
if (TraceHandle.IsValidHandle())
|
||||
{
|
||||
if (const int32* StateIdx = HandleToStateIdx.Find(TraceHandle))
|
||||
{
|
||||
auto& State = GetWorld()->GetSubsystem<UGCS_TraceSubsystem>()->GetTraceStateAt(*StateIdx);
|
||||
State.ChangeExecutionState(false);
|
||||
OnTraceStateChanged(TraceHandle, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::AddTracesByDefinitions(const TArray<FGCS_TraceDefinition>& Definitions, UPrimitiveComponent* SourceComponent,
|
||||
UObject* SourceObject)
|
||||
{
|
||||
return AddTraces(Definitions, SourceComponent, SourceObject);
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::AddTracesByDefinitionHandles(const TArray<FDataTableRowHandle>& DefinitionHandles, UPrimitiveComponent* SourceComponent,
|
||||
UObject* SourceObject)
|
||||
{
|
||||
return AddTraces(DefinitionHandles, SourceComponent, SourceObject);
|
||||
}
|
||||
|
||||
FGCS_TraceHandle UGCS_TraceSystemComponent::AddTraceByDefinition(const FGCS_TraceDefinition& Definition, UPrimitiveComponent* SourceComponent, UObject* SourceObject)
|
||||
{
|
||||
return AddTrace(Definition, SourceComponent, SourceObject);
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::StartTracesByTagsAndSource(const FGameplayTagContainer& TraceTags, const UObject* SourceObject)
|
||||
{
|
||||
return StartTraces(TraceTags, SourceObject);
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StartTracesByHandles(const TArray<FGCS_TraceHandle>& TraceHandles)
|
||||
{
|
||||
return StartTraces(TraceHandles);
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StartTraceByHandle(const FGCS_TraceHandle& TraceHandle)
|
||||
{
|
||||
return StartTrace(TraceHandle);
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StopTracesByHandles(const TArray<FGCS_TraceHandle>& TraceHandles)
|
||||
{
|
||||
StopTraces(TraceHandles);
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::StopTraceByHandle(const FGCS_TraceHandle& TraceHandle)
|
||||
{
|
||||
StopTrace(TraceHandle);
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::RemoveTraceByHandle(const FGCS_TraceHandle& TraceHandle)
|
||||
{
|
||||
RemoveTrace(TraceHandle);
|
||||
}
|
||||
|
||||
TArray<FGCS_TraceHandle> UGCS_TraceSystemComponent::GetTraceHandlesByTag(FGameplayTag TraceToFind) const
|
||||
{
|
||||
TArray<FGCS_TraceHandle> Handles;
|
||||
TagToHandles.MultiFind(TraceToFind, Handles);
|
||||
return Handles;
|
||||
}
|
||||
|
||||
AActor* UGCS_TraceSystemComponent::GetTraceSourceActor(const FGCS_TraceHandle& TraceHandle) const
|
||||
{
|
||||
if (UPrimitiveComponent* SourceComponent = GetTraceSourceComponent(TraceHandle))
|
||||
{
|
||||
return SourceComponent->GetOwner();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UPrimitiveComponent* UGCS_TraceSystemComponent::GetTraceSourceComponent(const FGCS_TraceHandle& TraceHandle) const
|
||||
{
|
||||
if (TraceHandle.IsValidHandle())
|
||||
{
|
||||
if (const int32* StateIdx = HandleToStateIdx.Find(TraceHandle))
|
||||
{
|
||||
FGCS_TraceState& State = GetWorld()->GetSubsystem<UGCS_TraceSubsystem>()->GetTraceStateAt(*StateIdx);
|
||||
return State.SourceComponent;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::RemoveAllTraces()
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
if (!IsValid(World))
|
||||
{
|
||||
return;
|
||||
}
|
||||
UGCS_TraceSubsystem* Subsystem = World->GetSubsystem<UGCS_TraceSubsystem>();
|
||||
if (!IsValid(Subsystem))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 新增:收集所有要移除的Idx和Guid,避免边遍历边修改
|
||||
TArray<TPair<int32, FGuid>> ToRemove;
|
||||
for (const TPair<FGCS_TraceHandle, int32>& Pair : HandleToStateIdx)
|
||||
{
|
||||
if (Pair.Key.IsValidHandle())
|
||||
{
|
||||
if (Subsystem->IsValidStateIdx(Pair.Value)) // 额外验证
|
||||
{
|
||||
const FGCS_TraceState& State = Subsystem->GetTraceStateAt(Pair.Value);
|
||||
ToRemove.Add(TPair<int32, FGuid>(Pair.Value, Pair.Key.Guid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 先停止所有状态
|
||||
for (const auto& Pending : ToRemove)
|
||||
{
|
||||
if (Subsystem->IsValidStateIdx(Pending.Key))
|
||||
{
|
||||
auto& State = Subsystem->GetTraceStateAt(Pending.Key);
|
||||
State.ChangeExecutionState(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 然后批量移除
|
||||
for (const auto& Pending : ToRemove)
|
||||
{
|
||||
Subsystem->RemoveTraceState(Pending.Key, Pending.Value);
|
||||
}
|
||||
|
||||
// 清空映射
|
||||
for (const TPair<FGCS_TraceHandle, int32>& Pair : HandleToStateIdx)
|
||||
{
|
||||
TagToHandles.RemoveSingle(Pair.Key.TraceTag, Pair.Key);
|
||||
}
|
||||
HandleToStateIdx.Empty();
|
||||
}
|
||||
|
||||
bool UGCS_TraceSystemComponent::IsTraceActive(const FGCS_TraceHandle& TraceHandle) const
|
||||
{
|
||||
if (const int32* StateIdx = HandleToStateIdx.Find(TraceHandle))
|
||||
{
|
||||
const FGCS_TraceState& State = GetWorld()->GetSubsystem<UGCS_TraceSubsystem>()->GetTraceStateAt(*StateIdx);
|
||||
return State.ExecutionState == EGCS_TraceExecutionState::InProgress;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::OnTraceHitDetected(const FGCS_TraceHandle& TraceHandle, const TArray<FHitResult>& HitResults, const float DeltaTime, const uint32 TickIdx)
|
||||
{
|
||||
DECLARE_SCOPE_CYCLE_COUNTER(TEXT("UGCS_TraceSystemComponent::OnTraceHitDetected"), UGCS_TraceSystemComponent_OnTraceHitDetected, STATGROUP_GCS)
|
||||
|
||||
FScopeLock ScopedLock(&TraceDoneScopeLock);
|
||||
|
||||
for (const FHitResult& HitResult : HitResults)
|
||||
{
|
||||
// GCS_CLOG(Verbose, "Trace(%s) hit:%s at location(%s)", *TraceHandle.ToDebugString(), *GetNameSafe(HitResult.GetActor()), *HitResult.Location.ToString())
|
||||
GCS_CLOG(Verbose, "Trace(%s) hit:%s", *TraceHandle.ToDebugString(), *HitResult.ToString())
|
||||
OnTraceHitEvent.Broadcast(TraceHandle, HitResult);
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TraceSystemComponent::OnTraceStateChanged(const FGCS_TraceHandle& TraceHandle, bool bNewState)
|
||||
{
|
||||
if (bNewState)
|
||||
{
|
||||
OnTraceStartedEvent.Broadcast(TraceHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnTraceStoppedEvent.Broadcast(TraceHandle);
|
||||
}
|
||||
OnTraceStateChangedEvent.Broadcast(TraceHandle, bNewState);
|
||||
}
|
||||
Reference in New Issue
Block a user