// Copyright 2025 https://yuewu.dev/en All Rights Reserved. #include "Collision/GCS_TraceStructLibrary.h" #include "GCS_LogChannels.h" #include "Components/BoxComponent.h" #include "Components/CapsuleComponent.h" #include "Components/SphereComponent.h" #include "TargetingSystem/TargetingPreset.h" bool FGCS_CollisionShape::InitializeShape(const UPrimitiveComponent* SourceComponent) { GCS_OWNED_CLOG(SourceComponent, Warning, "Should never use this shape:%s", *FGCS_CollisionShape::StaticStruct()->GetName()); FDebug::DumpStackTraceToLog(ELogVerbosity::VeryVerbose); return false; } FTransform FGCS_CollisionShape::GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const { GCS_OWNED_CLOG(SourceComponent, Warning, "Should never use this shape:%s", *FGCS_CollisionShape::StaticStruct()->GetName()); FDebug::DumpStackTraceToLog(ELogVerbosity::VeryVerbose); return SourceComponent->GetComponentTransform(); } FCollisionShape FGCS_CollisionShape::GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const { GCS_OWNED_CLOG(SourceComponent, Warning, "Should never use this shape:%s", *FGCS_CollisionShape::StaticStruct()->GetName()); FDebug::DumpStackTraceToLog(ELogVerbosity::VeryVerbose); return FCollisionShape::MakeSphere(30); } bool FGCS_CollisionShape_Static::InitializeShape(const UPrimitiveComponent* SourceComponent) { return true; } FTransform FGCS_CollisionShape_Static::GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const { const auto ComponentCurrentTransform = SourceComponent->GetComponentTransform(); return FTransform(Orientation, Offset) * ComponentCurrentTransform; } FCollisionShape FGCS_CollisionShape_Static::GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const { switch (ShapeType) { case EGCS_CollisionShapeType::Sphere: { return FCollisionShape::MakeSphere(Radius); } case EGCS_CollisionShapeType::Box: { return FCollisionShape::MakeBox(HalfSize); } case EGCS_CollisionShapeType::Capsule: { return FCollisionShape::MakeCapsule(Radius, HalfHeight); } default: { return FCollisionShape::MakeSphere(Radius); } } } bool FGCS_CollisionShape_ShapeBased::InitializeShape(const UPrimitiveComponent* SourceComponent) { if (ShapeType == EGCS_CollisionShapeType::Sphere) { if (const auto SphereCollision = Cast(SourceComponent)) { Radius = SphereCollision->GetScaledSphereRadius(); return true; } GCS_OWNED_CLOG(SourceComponent->GetOwner(), Warning, "No compatible shape component was found! Requires SphereComponent, Got %s(%s)", *GetNameSafe(SourceComponent), *SourceComponent->GetClass()->GetName()) } if (ShapeType == EGCS_CollisionShapeType::Box) { if (const auto BoxCollision = Cast(SourceComponent)) { HalfSize = BoxCollision->GetScaledBoxExtent(); return true; } GCS_OWNED_CLOG(SourceComponent->GetOwner(), Warning, "No compatible shape component was found! Requires BoxComponent, Got %s(%s)", *GetNameSafe(SourceComponent), *SourceComponent->GetClass()->GetName()) } if (ShapeType == EGCS_CollisionShapeType::Capsule) { if (const auto CapsuleCollision = Cast(SourceComponent)) { HalfHeight = CapsuleCollision->GetScaledCapsuleHalfHeight(); Radius = CapsuleCollision->GetScaledCapsuleRadius(); return true; } GCS_OWNED_CLOG(SourceComponent->GetOwner(), Warning, "No compatible shape component was found! Requires CapsuleComponent, Got %s(%s)", *GetNameSafe(SourceComponent), *SourceComponent->GetClass()->GetName()) } return false; } FTransform FGCS_CollisionShape_ShapeBased::GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const { const auto ComponentCurrentTransform = SourceComponent->GetComponentTransform(); return FTransform(Orientation, Offset) * ComponentCurrentTransform; } FCollisionShape FGCS_CollisionShape_ShapeBased::GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const { switch (ShapeType) { case EGCS_CollisionShapeType::Sphere: { return FCollisionShape::MakeSphere(Radius); } case EGCS_CollisionShapeType::Box: { return FCollisionShape::MakeBox(HalfSize); } case EGCS_CollisionShapeType::Capsule: { return FCollisionShape::MakeCapsule(Radius, HalfHeight); } default: { return FCollisionShape::MakeSphere(Radius); } } } bool FGCS_CollisionShape_Attached::InitializeShape(const UPrimitiveComponent* SourceComponent) { if (!IsValid(SourceComponent) || !SourceComponent->DoesSocketExist(SocketOrBoneName)) { GCS_OWNED_CLOG(SourceComponent->GetOwner(), Warning, "No SocketOrBone(%s) exists on mesh component! Got %s(%s)", *SocketOrBoneName.ToString(), *GetNameSafe(SourceComponent), *SourceComponent->GetClass()->GetName()) FDebug::DumpStackTraceToLog(ELogVerbosity::VeryVerbose); return false; } return true; } FTransform FGCS_CollisionShape_Attached::GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const { const auto BoneTransform = SourceComponent->GetSocketTransform(SocketOrBoneName); return FTransform(Orientation, Offset) * BoneTransform; } FTransform FGCS_CollisionShape_SocketBased::GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const { const auto ComponentCurrentTransform = SourceComponent->GetComponentTransform(); return FTransform(Orientation, Offset) * ComponentCurrentTransform; } bool FGCS_CollisionShape_SocketBased::InitializeShape(const UPrimitiveComponent* SourceComponent) { if (const UMeshComponent* MeshComponent = Cast(SourceComponent)) { const auto SocketStartTransform = MeshComponent->GetSocketTransform(MeshSocketStart, RTS_Component); const auto SocketStartLocation = SocketStartTransform.GetLocation(); const auto SocketEndTransform = MeshComponent->GetSocketTransform(MeshSocketEnd, RTS_Component); const auto SocketEndLocation = SocketEndTransform.GetLocation(); const FVector CenterLocation = (SocketStartLocation + SocketEndLocation) / 2.f; HalfHeight = FMath::Max((SocketStartLocation - SocketEndLocation).Length() / 2.f + MeshSocketLengthOffset, 1.f); Offset = CenterLocation; Orientation = FRotationMatrix::MakeFromZ(SocketStartLocation - SocketEndLocation).Rotator(); return true; } GCS_OWNED_CLOG(SourceComponent->GetOwner(), Warning, "No compatible mesh component was found! Got %s(%s)", *GetNameSafe(SourceComponent), *SourceComponent->GetClass()->GetName()) return false; } FCollisionShape FGCS_CollisionShape_SocketBased::GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const { return FCollisionShape::MakeCapsule(Radius, HalfHeight); } FGCS_TraceDefinition::FGCS_TraceDefinition() { CollisionShape.InitializeAs(FGCS_CollisionShape_Static::StaticStruct()); } bool FGCS_TraceDefinition::IsValidDefinition() const { // Base collision shape is not allowed! return TraceTag.IsValid() && CollisionShape.IsValid() && CollisionShape.GetScriptStruct() != FGCS_CollisionShape::StaticStruct(); } FString FGCS_TraceDefinition::ToString() const { return FString::Format(TEXT("{0} {1}"), {TraceTag.ToString(), GetNameSafe(CollisionShape.GetScriptStruct())}); } bool FGCS_TraceHandle::IsValidHandle() const { return TraceTag.IsValid() && Guid.IsValid() && SourceObject.IsValid(); } void FGCS_TraceState::ChangeExecutionState(const bool bNewTraceState, const bool bStopImmediate) { if (bNewTraceState) { this->ExecutionState = EGCS_TraceExecutionState::InProgress; this->TimeSinceLastTick = 0; this->TimeSinceActive = 0; this->TotalTickNumDuringExecution = 0; this->HitActors.Reset(); if (SourceComponent) { UpdatePreviousTransform(GetCurrentTransform()); } } else { if (this->ExecutionState == EGCS_TraceExecutionState::InProgress && !bStopImmediate) { this->ExecutionState = EGCS_TraceExecutionState::PendingStop; } else { this->ExecutionState = EGCS_TraceExecutionState::Stopped; } } } FTransform FGCS_TraceState::GetCurrentTransform() const { check(Shape.IsValid()) return Shape.Get().GetTransform(SourceComponent.Get(), TimeSinceActive); } void FGCS_TraceState::UpdatePreviousTransform(const FTransform& Transform) { if (TransformsOverTime.Num() == 0) { TransformsOverTime.Add(Transform); } else { TransformsOverTime[0] = Transform; } }