第一次提交

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,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);
}