第一次提交
This commit is contained in:
@@ -0,0 +1,369 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
#include "Targeting/Selections/GCS_TargetingSelectionTask_LineTrace.h"
|
||||
|
||||
#include "CollisionQueryParams.h"
|
||||
#include "KismetTraceUtils.h"
|
||||
#include "Components/PrimitiveComponent.h"
|
||||
#include "Engine/EngineTypes.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
#include "TargetingSystem/TargetingSubsystem.h"
|
||||
|
||||
#if ENABLE_DRAW_DEBUG
|
||||
#include "Engine/Canvas.h"
|
||||
#endif // ENABLE_DRAW_DEBUG
|
||||
|
||||
|
||||
UGCS_TargetingSelectionTask_LineTrace::UGCS_TargetingSelectionTask_LineTrace(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
bComplexTrace = false;
|
||||
bIgnoreSourceActor = false;
|
||||
bIgnoreInstigatorActor = false;
|
||||
bGenerateDefaultHitResult = true;
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::Execute(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
Super::Execute(TargetingHandle);
|
||||
|
||||
SetTaskAsyncState(TargetingHandle, ETargetingTaskAsyncState::Executing);
|
||||
|
||||
if (IsAsyncTargetingRequest(TargetingHandle))
|
||||
{
|
||||
ExecuteAsyncTrace(TargetingHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteImmediateTrace(TargetingHandle);
|
||||
}
|
||||
}
|
||||
|
||||
FVector UGCS_TargetingSelectionTask_LineTrace::GetSourceLocation_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (SourceContext->SourceActor)
|
||||
{
|
||||
return SourceContext->SourceActor->GetActorLocation();
|
||||
}
|
||||
|
||||
return SourceContext->SourceLocation;
|
||||
}
|
||||
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
FVector UGCS_TargetingSelectionTask_LineTrace::GetSourceOffset_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
return DefaultSourceOffset;
|
||||
}
|
||||
|
||||
FVector UGCS_TargetingSelectionTask_LineTrace::GetTraceDirection_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (SourceContext->SourceActor)
|
||||
{
|
||||
if (APawn* Pawn = Cast<APawn>(SourceContext->SourceActor))
|
||||
{
|
||||
return Pawn->GetControlRotation().Vector();
|
||||
}
|
||||
else
|
||||
{
|
||||
return SourceContext->SourceActor->GetActorForwardVector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_LineTrace::GetTraceLength_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
return DefaultTraceLength.GetValueAtLevel(GetTraceLevel(TargetingHandle));
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::GetAdditionalActorsToIgnore_Implementation(const FTargetingRequestHandle& TargetingHandle, TArray<AActor*>& OutAdditionalActorsToIgnore) const
|
||||
{
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_LineTrace::GetTraceLevel_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::ExecuteImmediateTrace(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (UWorld* World = GetSourceContextWorld(TargetingHandle))
|
||||
{
|
||||
#if ENABLE_DRAW_DEBUG
|
||||
ResetTraceResultsDebugString(TargetingHandle);
|
||||
#endif // ENABLE_DRAW_DEBUG
|
||||
|
||||
const FVector Direction = GetTraceDirection(TargetingHandle).GetSafeNormal();
|
||||
const FVector Start = (GetSourceLocation(TargetingHandle) + GetSourceOffset(TargetingHandle));
|
||||
const FVector End = Start + (Direction * GetTraceLength(TargetingHandle));
|
||||
|
||||
FCollisionQueryParams Params(SCENE_QUERY_STAT(ExecuteImmediateTrace), bComplexTrace);
|
||||
InitCollisionParams(TargetingHandle, Params);
|
||||
|
||||
bool bHasBlockingHit = false;
|
||||
TArray<FHitResult> Hits;
|
||||
if (CollisionProfileName.Name != TEXT("NoCollision"))
|
||||
{
|
||||
bHasBlockingHit = World->LineTraceMultiByProfile(Hits, Start, End, CollisionProfileName.Name, Params);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ECollisionChannel CollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceChannel);
|
||||
bHasBlockingHit = World->LineTraceMultiByChannel(Hits, Start, End, CollisionChannel, Params);
|
||||
}
|
||||
|
||||
#if ENABLE_DRAW_DEBUG
|
||||
DrawDebugTrace(TargetingHandle, Start, End, bHasBlockingHit, Hits);
|
||||
#endif // ENABLE_DRAW_DEBUG
|
||||
|
||||
ProcessHitResults(TargetingHandle, Hits);
|
||||
}
|
||||
|
||||
SetTaskAsyncState(TargetingHandle, ETargetingTaskAsyncState::Completed);
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::ExecuteAsyncTrace(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (UWorld* World = GetSourceContextWorld(TargetingHandle))
|
||||
{
|
||||
AActor* SourceActor = nullptr;
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
SourceActor = SourceContext->SourceActor;
|
||||
}
|
||||
const FVector Direction = GetTraceDirection(TargetingHandle).GetSafeNormal();
|
||||
const FVector Start = (GetSourceLocation(TargetingHandle) + GetSourceOffset(TargetingHandle));
|
||||
const FVector End = Start + (Direction * GetTraceLength(TargetingHandle));
|
||||
|
||||
FCollisionQueryParams Params(SCENE_QUERY_STAT(ExecuteAsyncTrace), bComplexTrace);
|
||||
InitCollisionParams(TargetingHandle, Params);
|
||||
|
||||
FTraceDelegate Delegate = FTraceDelegate::CreateUObject(this, &UGCS_TargetingSelectionTask_LineTrace::HandleAsyncTraceComplete, TargetingHandle);
|
||||
if (CollisionProfileName.Name != TEXT("NoCollision"))
|
||||
{
|
||||
World->AsyncLineTraceByProfile(EAsyncTraceType::Multi, Start, End, CollisionProfileName.Name, Params, &Delegate);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ECollisionChannel CollisionChannel = UEngineTypes::ConvertToCollisionChannel(TraceChannel);
|
||||
World->AsyncLineTraceByChannel(EAsyncTraceType::Multi, Start, End, CollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, &Delegate);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTaskAsyncState(TargetingHandle, ETargetingTaskAsyncState::Completed);
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::HandleAsyncTraceComplete(const FTraceHandle& InTraceHandle, FTraceDatum& InTraceDatum, FTargetingRequestHandle TargetingHandle) const
|
||||
{
|
||||
if (TargetingHandle.IsValid())
|
||||
{
|
||||
#if ENABLE_DRAW_DEBUG
|
||||
ResetTraceResultsDebugString(TargetingHandle);
|
||||
|
||||
// We have to manually find if there is a blocking hit.
|
||||
bool bHasBlockingHit = false;
|
||||
for (const FHitResult& HitResult : InTraceDatum.OutHits)
|
||||
{
|
||||
if (HitResult.bBlockingHit)
|
||||
{
|
||||
bHasBlockingHit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DrawDebugTrace(TargetingHandle, InTraceDatum.Start, InTraceDatum.End, bHasBlockingHit, InTraceDatum.OutHits);
|
||||
|
||||
#endif // ENABLE_DRAW_DEBUG
|
||||
|
||||
ProcessHitResults(TargetingHandle, InTraceDatum.OutHits);
|
||||
}
|
||||
|
||||
SetTaskAsyncState(TargetingHandle, ETargetingTaskAsyncState::Completed);
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::ProcessHitResults(const FTargetingRequestHandle& TargetingHandle, const TArray<FHitResult>& Hits) const
|
||||
{
|
||||
if (!TargetingHandle.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
FTargetingDefaultResultsSet& TargetingResults = FTargetingDefaultResultsSet::FindOrAdd(TargetingHandle);
|
||||
|
||||
if (Hits.Num() > 0)
|
||||
{
|
||||
for (const FHitResult& HitResult : Hits)
|
||||
{
|
||||
if (!HitResult.GetActor())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool bAddResult = true;
|
||||
for (const FTargetingDefaultResultData& ResultData : TargetingResults.TargetResults)
|
||||
{
|
||||
if (ResultData.HitResult.GetActor() == HitResult.GetActor())
|
||||
{
|
||||
bAddResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bAddResult)
|
||||
{
|
||||
FTargetingDefaultResultData* ResultData = new(TargetingResults.TargetResults) FTargetingDefaultResultData();
|
||||
ResultData->HitResult = HitResult;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_DRAW_DEBUG
|
||||
BuildTraceResultsDebugString(TargetingHandle, TargetingResults.TargetResults);
|
||||
#endif // ENABLE_DRAW_DEBUG
|
||||
}
|
||||
else if (bGenerateDefaultHitResult)
|
||||
{
|
||||
// If there were no hits, add a default HitResult at the end of the trace
|
||||
FHitResult HitResult;
|
||||
const FVector Start = (GetSourceLocation(TargetingHandle) + GetSourceOffset(TargetingHandle));
|
||||
const FVector End = Start + (GetTraceDirection(TargetingHandle) * GetTraceLength(TargetingHandle));
|
||||
// Start param could be player ViewPoint. We want HitResult to always display the StartLocation.
|
||||
HitResult.TraceStart = Start;
|
||||
HitResult.TraceEnd = End;
|
||||
HitResult.Location = End;
|
||||
HitResult.ImpactPoint = End;
|
||||
FTargetingDefaultResultData* ResultData = new(TargetingResults.TargetResults) FTargetingDefaultResultData();
|
||||
ResultData->HitResult = HitResult;
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::InitCollisionParams(const FTargetingRequestHandle& TargetingHandle, FCollisionQueryParams& OutParams) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (bIgnoreSourceActor && SourceContext->SourceActor)
|
||||
{
|
||||
OutParams.AddIgnoredActor(SourceContext->SourceActor);
|
||||
}
|
||||
|
||||
if (bIgnoreInstigatorActor && SourceContext->InstigatorActor)
|
||||
{
|
||||
OutParams.AddIgnoredActor(SourceContext->InstigatorActor);
|
||||
}
|
||||
|
||||
TArray<AActor*> AdditionalActorsToIgnoreArray;
|
||||
GetAdditionalActorsToIgnore(TargetingHandle, AdditionalActorsToIgnoreArray);
|
||||
|
||||
if (AdditionalActorsToIgnoreArray.Num() > 0)
|
||||
{
|
||||
OutParams.AddIgnoredActors(AdditionalActorsToIgnoreArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
bool UGCS_TargetingSelectionTask_LineTrace::CanEditChange(const FProperty* InProperty) const
|
||||
{
|
||||
bool bCanEdit = Super::CanEditChange(InProperty);
|
||||
|
||||
if (bCanEdit && InProperty)
|
||||
{
|
||||
const FName PropertyName = InProperty->GetFName();
|
||||
|
||||
if (PropertyName == GET_MEMBER_NAME_CHECKED(UGCS_TargetingSelectionTask_LineTrace, TraceChannel))
|
||||
{
|
||||
return (CollisionProfileName.Name == TEXT("NoCollision"));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
|
||||
#if ENABLE_DRAW_DEBUG
|
||||
void UGCS_TargetingSelectionTask_LineTrace::DrawDebug(UTargetingSubsystem* TargetingSubsystem, FTargetingDebugInfo& Info, const FTargetingRequestHandle& TargetingHandle, float XOffset, float YOffset,
|
||||
int32 MinTextRowsToAdvance) const
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
if (UTargetingSubsystem::IsTargetingDebugEnabled())
|
||||
{
|
||||
FTargetingDebugData& DebugData = FTargetingDebugData::FindOrAdd(TargetingHandle);
|
||||
FString& ScratchPadString = DebugData.DebugScratchPadStrings.FindOrAdd(GetNameSafe(this));
|
||||
if (!ScratchPadString.IsEmpty())
|
||||
{
|
||||
if (Info.Canvas)
|
||||
{
|
||||
Info.Canvas->SetDrawColor(FColor::Yellow);
|
||||
}
|
||||
|
||||
FString TaskString = FString::Printf(TEXT("Results : %s"), *ScratchPadString);
|
||||
TargetingSubsystem->DebugLine(Info, TaskString, XOffset, YOffset, MinTextRowsToAdvance);
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::DrawDebugTrace(const FTargetingRequestHandle TargetingHandle, const FVector& StartLocation, const FVector& EndLocation, const bool bHit,
|
||||
const TArray<FHitResult>& Hits) const
|
||||
{
|
||||
if (UTargetingSubsystem::IsTargetingDebugEnabled())
|
||||
{
|
||||
if (UWorld* World = GetSourceContextWorld(TargetingHandle))
|
||||
{
|
||||
const float DrawTime = UTargetingSubsystem::GetOverrideTargetingLifeTime();
|
||||
const EDrawDebugTrace::Type DrawDebugType = DrawTime <= 0.0f ? EDrawDebugTrace::Type::ForOneFrame : EDrawDebugTrace::Type::ForDuration;
|
||||
const FLinearColor TraceColor = FLinearColor::Red;
|
||||
const FLinearColor TraceHitColor = FLinearColor::Green;
|
||||
DrawDebugLineTraceMulti(World, StartLocation, EndLocation, DrawDebugType, bHit, Hits, TraceColor, TraceHitColor, DrawTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::BuildTraceResultsDebugString(const FTargetingRequestHandle& TargetingHandle, const TArray<FTargetingDefaultResultData>& TargetResults) const
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
if (UTargetingSubsystem::IsTargetingDebugEnabled())
|
||||
{
|
||||
FTargetingDebugData& DebugData = FTargetingDebugData::FindOrAdd(TargetingHandle);
|
||||
FString& ScratchPadString = DebugData.DebugScratchPadStrings.FindOrAdd(GetNameSafe(this));
|
||||
|
||||
for (const FTargetingDefaultResultData& TargetData : TargetResults)
|
||||
{
|
||||
if (const AActor* Target = TargetData.HitResult.GetActor())
|
||||
{
|
||||
if (ScratchPadString.IsEmpty())
|
||||
{
|
||||
ScratchPadString = FString::Printf(TEXT("%s"), *GetNameSafe(Target));
|
||||
}
|
||||
else
|
||||
{
|
||||
ScratchPadString += FString::Printf(TEXT(", %s"), *GetNameSafe(Target));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_LineTrace::ResetTraceResultsDebugString(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
FTargetingDebugData& DebugData = FTargetingDebugData::FindOrAdd(TargetingHandle);
|
||||
FString& ScratchPadString = DebugData.DebugScratchPadStrings.FindOrAdd(GetNameSafe(this));
|
||||
ScratchPadString.Reset();
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
}
|
||||
|
||||
#endif // ENABLE_DRAW_DEBUG
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Targeting/Selections/GCS_TargetingSelectionTask_TraceExt.h"
|
||||
|
||||
#include "GCS_LogChannels.h"
|
||||
#include "Collision/DEPRECATED_GCS_CollisionTraceInstance.h"
|
||||
#include "Targeting/GCS_TargetingSourceInterface.h"
|
||||
|
||||
UDEPRECATED_GCS_CollisionTraceInstance* UGCS_TargetingSelectionTask_TraceExt::GetSourceTraceInstance_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (SourceContext->SourceObject)
|
||||
{
|
||||
return Cast<UDEPRECATED_GCS_CollisionTraceInstance>(SourceContext->SourceObject);
|
||||
}
|
||||
}
|
||||
UE_LOG(LogGCS, Error, TEXT("No valid CollisionTraceInstance passed in as SourceObject! TargetingPreset:%s"), *GetOuter()->GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_TraceExt::Execute(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
Super::Execute(TargetingHandle);
|
||||
}
|
||||
|
||||
FVector UGCS_TargetingSelectionTask_TraceExt::GetSourceLocation_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (bUseContextLocationAsSourceLocation)
|
||||
{
|
||||
return SourceContext->SourceLocation;
|
||||
}
|
||||
if (SourceContext->SourceActor)
|
||||
{
|
||||
return SourceContext->SourceActor->GetActorLocation();
|
||||
}
|
||||
|
||||
return SourceContext->SourceLocation;
|
||||
}
|
||||
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
FVector UGCS_TargetingSelectionTask_TraceExt::GetTraceDirection_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (SourceContext->SourceObject && SourceContext->SourceObject->GetClass()->ImplementsInterface(UGCS_TargetingSourceInterface::StaticClass()))
|
||||
{
|
||||
FVector TraceDirection;
|
||||
if (IGCS_TargetingSourceInterface::Execute_GetTraceDirection(SourceContext->SourceObject, TraceDirection))
|
||||
{
|
||||
return TraceDirection;
|
||||
}
|
||||
}
|
||||
|
||||
return SourceContext->SourceLocation;
|
||||
}
|
||||
|
||||
return Super::GetTraceDirection_Implementation(TargetingHandle);
|
||||
}
|
||||
|
||||
void UGCS_TargetingSelectionTask_TraceExt::GetAdditionalActorsToIgnore_Implementation(const FTargetingRequestHandle& TargetingHandle, TArray<AActor*>& OutAdditionalActorsToIgnore) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (SourceContext->SourceObject && SourceContext->SourceObject->GetClass()->ImplementsInterface(UGCS_TargetingSourceInterface::StaticClass()))
|
||||
{
|
||||
OutAdditionalActorsToIgnore.Append(IGCS_TargetingSourceInterface::Execute_GetAdditionalActorsToIgnore(SourceContext->SourceObject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_TraceExt::GetTraceLevel_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (!IsValid(SourceContext->SourceObject))
|
||||
{
|
||||
UE_LOG(LogGCS, Error, TEXT("No valid Context Source Object found! TargetingPreset:%s"), *GetOuter()->GetName());
|
||||
return 0;
|
||||
}
|
||||
if (!SourceContext->SourceObject->GetClass()->ImplementsInterface(UGCS_TargetingSourceInterface::StaticClass()))
|
||||
{
|
||||
UE_LOG(LogGCS, Error, TEXT("Source Object(%s) doesn't implements GCS_TargetingSourceInterface.! TargetingPreset:%s"),
|
||||
*SourceContext->SourceObject->GetName(), *GetOuter()->GetName());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_TraceExt::GetTraceLength_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
return bTraceLengthLevel ? DefaultTraceLength.GetValueAtLevel(GetTraceLevel(TargetingHandle)) : DefaultTraceLength.GetValue();
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_TraceExt::GetSweptTraceRadius_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
return bSweptTraceRadiusLevel ? DefaultSweptTraceRadius.GetValueAtLevel(GetTraceLevel(TargetingHandle)) : DefaultSweptTraceRadius.GetValue();
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_TraceExt::GetSweptTraceCapsuleHalfHeight_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
return bSweptTraceCapsuleHalfHeightLevel ? DefaultSweptTraceCapsuleHalfHeight.GetValueAtLevel(GetTraceLevel(TargetingHandle)) : DefaultSweptTraceCapsuleHalfHeight.GetValue();
|
||||
}
|
||||
|
||||
FVector UGCS_TargetingSelectionTask_TraceExt::GetSweptTraceBoxHalfExtents_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (bSweptTraceBoxHalfExtentLevel)
|
||||
{
|
||||
float Level = GetTraceLevel(TargetingHandle);
|
||||
return FVector(DefaultSweptTraceBoxHalfExtentX.GetValueAtLevel(Level), DefaultSweptTraceBoxHalfExtentY.GetValueAtLevel(Level), DefaultSweptTraceBoxHalfExtentZ.GetValueAtLevel(Level));
|
||||
}
|
||||
|
||||
return Super::GetSweptTraceBoxHalfExtents_Implementation(TargetingHandle);
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Targeting/Selections/GCS_TargetingSelectionTask_TraceExt_BindShape.h"
|
||||
|
||||
#include "GCS_LogChannels.h"
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "Components/SphereComponent.h"
|
||||
#include "Components/ShapeComponent.h"
|
||||
#include "Misc/DataValidation.h"
|
||||
#include "Targeting/GCS_TargetingFunctionLibrary.h"
|
||||
#include "Targeting/GCS_TargetingSourceInterface.h"
|
||||
|
||||
void UGCS_TargetingSelectionTask_TraceExt_BindShape::Execute(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
bool bMatchShapeType = true;
|
||||
UShapeComponent* Shape = GetTraceShape(TargetingHandle);
|
||||
|
||||
if (!IsValid(Shape))
|
||||
{
|
||||
GCS_LOG(Warning, "")
|
||||
bMatchShapeType = false;
|
||||
}
|
||||
if (TraceType == ETargetingTraceType::Box && !Shape->IsA<UBoxComponent>())
|
||||
{
|
||||
GCS_LOG(Warning, "%s: Trace type mismatched! want Box, got %s. %s",
|
||||
*GetNameSafe(GetOuter()),
|
||||
*GetNameSafe(Shape->GetClass()),
|
||||
*UGCS_TargetingFunctionLibrary::GetTargetingSourceContextDebugString(TargetingHandle)
|
||||
)
|
||||
bMatchShapeType = false;
|
||||
}
|
||||
if (TraceType == ETargetingTraceType::Capsule && !Shape->IsA<UCapsuleComponent>())
|
||||
{
|
||||
GCS_LOG(Warning, "%s: Trace type mismatched! want Capsule, got %s. %s",
|
||||
*GetNameSafe(GetOuter()),
|
||||
*GetNameSafe(Shape->GetClass()),
|
||||
*UGCS_TargetingFunctionLibrary::GetTargetingSourceContextDebugString(TargetingHandle)
|
||||
)
|
||||
bMatchShapeType = false;
|
||||
}
|
||||
if (TraceType == ETargetingTraceType::Sphere && !Shape->IsA<USphereComponent>())
|
||||
{
|
||||
GCS_LOG(Warning, "%s: Trace type mismatched! want Capsule, got %s. %s",
|
||||
*GetNameSafe(GetOuter()),
|
||||
*GetNameSafe(Shape->GetClass()),
|
||||
*UGCS_TargetingFunctionLibrary::GetTargetingSourceContextDebugString(TargetingHandle)
|
||||
)
|
||||
bMatchShapeType = false;
|
||||
}
|
||||
|
||||
if (bMatchShapeType)
|
||||
{
|
||||
Super::Execute(TargetingHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTaskAsyncState(TargetingHandle, ETargetingTaskAsyncState::Completed);
|
||||
}
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_TraceExt_BindShape::GetSweptTraceRadius_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
float BaseValue = -1;
|
||||
|
||||
if (USphereComponent* Shape = Cast<USphereComponent>(GetTraceShape(TargetingHandle)))
|
||||
{
|
||||
BaseValue = Shape->GetScaledSphereRadius();
|
||||
}
|
||||
if (const UCapsuleComponent* Shape = Cast<UCapsuleComponent>(GetTraceShape(TargetingHandle)))
|
||||
{
|
||||
BaseValue = Shape->GetScaledCapsuleRadius();
|
||||
}
|
||||
|
||||
float Value = Super::GetSweptTraceRadius_Implementation(TargetingHandle);
|
||||
|
||||
if (BaseValue < 0)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
if (SweptTraceRadiusModType == EGCS_TraceDataModifyType::Add)
|
||||
{
|
||||
return BaseValue + Value;
|
||||
}
|
||||
|
||||
if (SweptTraceRadiusModType == EGCS_TraceDataModifyType::Multiply)
|
||||
{
|
||||
return BaseValue * Value;
|
||||
}
|
||||
return BaseValue;
|
||||
}
|
||||
|
||||
float UGCS_TargetingSelectionTask_TraceExt_BindShape::GetSweptTraceCapsuleHalfHeight_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
float BaseValue = -1;
|
||||
|
||||
if (const UCapsuleComponent* Capsule = Cast<UCapsuleComponent>(GetTraceShape(TargetingHandle)))
|
||||
{
|
||||
BaseValue = Capsule->GetScaledCapsuleHalfHeight();
|
||||
}
|
||||
|
||||
float Value = Super::GetSweptTraceCapsuleHalfHeight_Implementation(TargetingHandle);
|
||||
|
||||
if (BaseValue < 0)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
if (SweptTraceCapsuleHalfHeightModType == EGCS_TraceDataModifyType::Add)
|
||||
{
|
||||
return BaseValue + Value;
|
||||
}
|
||||
|
||||
if (SweptTraceCapsuleHalfHeightModType == EGCS_TraceDataModifyType::Multiply)
|
||||
{
|
||||
return BaseValue * Value;
|
||||
}
|
||||
return BaseValue;
|
||||
}
|
||||
|
||||
FVector UGCS_TargetingSelectionTask_TraceExt_BindShape::GetSweptTraceBoxHalfExtents_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
FVector BaseValue = FVector::ZeroVector;
|
||||
|
||||
if (const UBoxComponent* Shape = Cast<UBoxComponent>(GetTraceShape(TargetingHandle)))
|
||||
{
|
||||
BaseValue = Shape->GetScaledBoxExtent();
|
||||
}
|
||||
|
||||
FVector Value = Super::GetSweptTraceBoxHalfExtents_Implementation(TargetingHandle);
|
||||
|
||||
if (BaseValue == FVector::ZeroVector)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
if (SweptTraceBoxHalfExtentModType == EGCS_TraceDataModifyType::Add)
|
||||
{
|
||||
return BaseValue + Value;
|
||||
}
|
||||
|
||||
if (SweptTraceBoxHalfExtentModType == EGCS_TraceDataModifyType::Multiply)
|
||||
{
|
||||
return BaseValue * Value;
|
||||
}
|
||||
return BaseValue;
|
||||
}
|
||||
|
||||
UShapeComponent* UGCS_TargetingSelectionTask_TraceExt_BindShape::GetTraceShape(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
UShapeComponent* ShapeComponent = nullptr;
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (SourceContext->SourceObject)
|
||||
{
|
||||
if (SourceContext->SourceObject->GetClass()->ImplementsInterface(UGCS_TargetingSourceInterface::StaticClass()))
|
||||
{
|
||||
if (IGCS_TargetingSourceInterface::Execute_GetTraceShape(SourceContext->SourceObject, ShapeComponent))
|
||||
{
|
||||
return ShapeComponent;
|
||||
}
|
||||
UE_LOG(LogGCS, VeryVerbose, TEXT("Source Object(%s) doesn't provide valid ShapeComponent! TargetingPreset:%s"),
|
||||
*SourceContext->SourceObject->GetName(), *GetOuter()->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogGCS, VeryVerbose, TEXT("Source Object(%s) doesn't implements GCS_TargetingSourceInterface.! TargetingPreset:%s"),
|
||||
*SourceContext->SourceObject->GetName(), *GetOuter()->GetName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogGCS, Error, TEXT("No valid Context Source Object found! TargetingPreset:%s"), *GetOuter()->GetName());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FRotator UGCS_TargetingSelectionTask_TraceExt_BindShape::GetSweptTraceRotation_Implementation(const FTargetingRequestHandle& TargetingHandle) const
|
||||
{
|
||||
if (const FTargetingSourceContext* SourceContext = FTargetingSourceContext::Find(TargetingHandle))
|
||||
{
|
||||
if (SourceContext->SourceObject && SourceContext->SourceObject->GetClass()->ImplementsInterface(UGCS_TargetingSourceInterface::StaticClass()))
|
||||
{
|
||||
FRotator TraceRotation;
|
||||
if (IGCS_TargetingSourceInterface::Execute_GetSweptTraceRotation(SourceContext->SourceObject, TraceRotation))
|
||||
{
|
||||
return TraceRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Super::GetSweptTraceRotation_Implementation(TargetingHandle);
|
||||
}
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
EDataValidationResult UGCS_TargetingSelectionTask_TraceExt_BindShape::IsDataValid(class FDataValidationContext& Context) const
|
||||
{
|
||||
if (TraceType == ETargetingTraceType::Line)
|
||||
{
|
||||
FString Txt = FString::Format(TEXT("TraceType == Line is not allowed in this type of task:{0} "), {GetClass()->GetName()});
|
||||
Context.AddError(FText::FromString(Txt));
|
||||
}
|
||||
if (bUseContextLocationAsSourceLocation)
|
||||
{
|
||||
FString Txt = FString::Format(TEXT("bUseContextLocationAsSourceLocation is not allowed in this type of task:{0} "), {GetClass()->GetName()});
|
||||
Context.AddError(FText::FromString(Txt));
|
||||
}
|
||||
return Super::IsDataValid(Context);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user