Add CVar debug system: ps.ai.Behavior.Debug controls all diagnostic logs
- New CVar ps.ai.Behavior.Debug: -1=use bDebug property, 0=force off, 1=force on - IsDebugEnabled() static helper checks CVar then PersonalityComponent.bDebug - All diagnostic logs gated by IsDebugEnabled (no spam when debug off) - Logs use Log level (visible) when enabled, silent when disabled - Applied to: UpdateThreat, FindAndFollowSpline, FindCover, PerceptionComponent, PersonalityComponent EvaluateReaction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b473fcda22
commit
661e8c66ac
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -40,19 +40,22 @@ void UPS_AI_Behavior_BTService_UpdateThreat::TickNode(
|
||||
// Debug: check what perception sees
|
||||
TArray<AActor*> PerceivedActors;
|
||||
Perception->GetCurrentlyPerceivedActors(nullptr, PerceivedActors);
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] UpdateThreat: Perceived %d actors"),
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] UpdateThreat: Perceived %d actors"),
|
||||
*AIC->GetName(), PerceivedActors.Num());
|
||||
for (AActor* A : PerceivedActors)
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT(" - %s"), *A->GetName());
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT(" - %s"), *A->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
// Also check known actors (perceived in the past but maybe lost sight)
|
||||
TArray<AActor*> KnownActors;
|
||||
Perception->GetKnownPerceivedActors(nullptr, KnownActors);
|
||||
if (KnownActors.Num() != PerceivedActors.Num())
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()) && KnownActors.Num() != PerceivedActors.Num())
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] UpdateThreat: Known (past) %d actors"),
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] UpdateThreat: Known (past) %d actors"),
|
||||
*AIC->GetName(), KnownActors.Num());
|
||||
}
|
||||
|
||||
@ -74,8 +77,11 @@ void UPS_AI_Behavior_BTService_UpdateThreat::TickNode(
|
||||
|
||||
BB->SetValueAsFloat(PS_AI_Behavior_BB::ThreatLevel, FinalThreat);
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] UpdateThreat: raw=%.2f, stored=%.2f, final=%.2f"),
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] UpdateThreat: raw=%.2f, stored=%.2f, final=%.2f"),
|
||||
*AIC->GetName(), RawThreat, StoredThreat, FinalThreat);
|
||||
}
|
||||
|
||||
// ─── Update threat actor and location with LOS tracking ─────────
|
||||
FUpdateThreatMemory* Memory = reinterpret_cast<FUpdateThreatMemory*>(NodeMemory);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "PS_AI_Behavior_SplineNetwork.h"
|
||||
#include "PS_AI_Behavior_SplinePath.h"
|
||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||
#include "PS_AI_Behavior_Statics.h"
|
||||
#include "PS_AI_Behavior_Definitions.h"
|
||||
#include "Navigation/PathFollowingComponent.h"
|
||||
|
||||
@ -32,10 +33,13 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
||||
}
|
||||
|
||||
// Debug: log state on entry
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] FindAndFollowSpline: bIsFollowing=%d CurrentSpline=%s"),
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindAndFollowSpline: bIsFollowing=%d CurrentSpline=%s"),
|
||||
*AIC->GetName(),
|
||||
(int32)Follower->bIsFollowing,
|
||||
Follower->CurrentSpline ? *Follower->CurrentSpline->GetName() : TEXT("null"));
|
||||
}
|
||||
|
||||
// If already following a spline, don't re-search — just succeed immediately
|
||||
// The Follow Spline task will continue the movement
|
||||
@ -59,10 +63,13 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
||||
const FVector SplineDir = Follower->CurrentSpline->GetWorldDirectionAtDistance(ClosestDist);
|
||||
const bool bForward = FVector::DotProduct(PawnFwd, SplineDir) >= 0.0f;
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] FindAndFollowSpline: resuming spline '%s' at closest point (gap=%.0fcm, dist=%.0f, bWalkToSpline=%d, AcceptanceRadius=%.0f)"),
|
||||
*AIC->GetName(), *Follower->CurrentSpline->GetName(), GapToSpline, ClosestDist,
|
||||
(int32)bWalkToSpline, AcceptanceRadius);
|
||||
}
|
||||
|
||||
if (bWalkToSpline && GapToSpline > AcceptanceRadius)
|
||||
{
|
||||
@ -73,9 +80,12 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
||||
/*bUsePathfinding=*/true, /*bProjectDestinationToNavigation=*/true,
|
||||
/*bCanStrafe=*/false);
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] FindAndFollowSpline: MoveToLocation result=%d (0=Failed, 1=AlreadyAtGoal, 2=RequestSuccessful)"),
|
||||
*AIC->GetName(), (int32)Result);
|
||||
}
|
||||
|
||||
if (Result == EPathFollowingRequestResult::AlreadyAtGoal)
|
||||
{
|
||||
@ -98,9 +108,12 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
||||
{
|
||||
// Close enough — clear any residual movement request and start following
|
||||
AIC->StopMovement();
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] FindAndFollowSpline: close enough, StartFollowingAtDistance(dist=%.0f, fwd=%d)"),
|
||||
*AIC->GetName(), ClosestDist, (int32)bForward);
|
||||
}
|
||||
Follower->StartFollowingAtDistance(Follower->CurrentSpline, ClosestDist, bForward);
|
||||
return EBTNodeResult::Succeeded;
|
||||
}
|
||||
@ -131,9 +144,12 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
||||
AIC->GetPawn()->GetActorLocation(), NPCType, MaxSearchDistance,
|
||||
ClosestSpline, DistAlongSpline))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] FindAndFollowSpline: no accessible spline within %.0fcm."),
|
||||
*AIC->GetName(), MaxSearchDistance);
|
||||
}
|
||||
return EBTNodeResult::Failed;
|
||||
}
|
||||
|
||||
@ -141,10 +157,13 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
||||
const FVector SplinePoint = ClosestSpline->GetWorldLocationAtDistance(DistAlongSpline);
|
||||
const float GapToSpline = FVector::Dist(AIC->GetPawn()->GetActorLocation(), SplinePoint);
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] FindAndFollowSpline: found spline '%s' at dist=%.0f/%.0f, gap=%.0fcm"),
|
||||
*AIC->GetName(), *ClosestSpline->GetName(), DistAlongSpline,
|
||||
ClosestSpline->GetSplineLength(), GapToSpline);
|
||||
}
|
||||
|
||||
if (bWalkToSpline && GapToSpline > AcceptanceRadius)
|
||||
{
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "PS_AI_Behavior_Interface.h"
|
||||
#include "PS_AI_Behavior_CoverPoint.h"
|
||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||
#include "PS_AI_Behavior_Statics.h"
|
||||
#include "PS_AI_Behavior_Definitions.h"
|
||||
#include "BehaviorTree/BlackboardComponent.h"
|
||||
#include "NavigationSystem.h"
|
||||
@ -122,7 +123,10 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindCover::ExecuteTask(
|
||||
|
||||
if (BestScore < 0.1f)
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] FindCover: no suitable cover found."), *AIC->GetName());
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindCover: no suitable cover found."), *AIC->GetName());
|
||||
}
|
||||
return EBTNodeResult::Failed;
|
||||
}
|
||||
|
||||
@ -132,18 +136,24 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindCover::ExecuteTask(
|
||||
ChosenPoint->Claim(AIC->GetPawn());
|
||||
BB->SetValueAsObject(PS_AI_Behavior_BB::CoverPoint, ChosenPoint);
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] FindCover: using manual %s '%s' (score %.2f)"),
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindCover: using manual %s '%s' (score %.2f)"),
|
||||
*AIC->GetName(),
|
||||
ChosenPoint->PointType == EPS_AI_Behavior_CoverPointType::Cover ? TEXT("Cover") : TEXT("HidingSpot"),
|
||||
*ChosenPoint->GetName(), BestScore);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BB->ClearValue(PS_AI_Behavior_BB::CoverPoint);
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] FindCover: using procedural cover (score %.2f)"),
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindCover: using procedural cover (score %.2f)"),
|
||||
*AIC->GetName(), BestScore);
|
||||
}
|
||||
}
|
||||
|
||||
BB->SetValueAsVector(PS_AI_Behavior_BB::CoverLocation, BestCoverPos);
|
||||
|
||||
@ -215,10 +225,13 @@ void UPS_AI_Behavior_BTTask_FindCover::TickTask(
|
||||
const FVector CoverLoc = BB->GetValueAsVector(PS_AI_Behavior_BB::CoverLocation);
|
||||
const float DistToCover = FVector::Dist2D(Pawn->GetActorLocation(), CoverLoc);
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] FindCover: MoveStatus=Idle, dist2D=%.0fcm, acceptance=%.0fcm, coverLoc=%s, pawnLoc=%s"),
|
||||
*AIC->GetName(), DistToCover, AcceptanceRadius,
|
||||
*CoverLoc.ToString(), *Pawn->GetActorLocation().ToString());
|
||||
}
|
||||
|
||||
if (DistToCover > AcceptanceRadius * 2.0f)
|
||||
{
|
||||
@ -445,9 +458,12 @@ void UPS_AI_Behavior_BTTask_FindCover::RunRefinementQuery(
|
||||
&UPS_AI_Behavior_BTTask_FindCover::OnRefinementQueryFinished,
|
||||
&OwnerComp, NodeMemory, CoverCenter));
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] FindCover: EQS refinement query launched around %s"),
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(Pawn))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindCover: EQS refinement query launched around %s"),
|
||||
*Pawn->GetName(), *CoverCenter.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void UPS_AI_Behavior_BTTask_FindCover::OnRefinementQueryFinished(
|
||||
TSharedPtr<FEnvQueryResult> Result,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||
#include "PS_AI_Behavior_PersonalityProfile.h"
|
||||
#include "PS_AI_Behavior_TeamComponent.h"
|
||||
#include "PS_AI_Behavior_Statics.h"
|
||||
#include "PS_AI_Behavior_Settings.h"
|
||||
#include "Perception/AISenseConfig_Sight.h"
|
||||
#include "Perception/AISenseConfig_Hearing.h"
|
||||
@ -286,6 +287,11 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
||||
TArray<AActor*> PerceivedActors;
|
||||
GetCurrentlyPerceivedActors(nullptr, PerceivedActors); // All senses at once
|
||||
|
||||
// Resolve debug flag once for all logs in this function
|
||||
const AAIController* DebugAIC = Cast<AAIController>(GetOwner());
|
||||
const APawn* DebugPawn = DebugAIC ? DebugAIC->GetPawn() : nullptr;
|
||||
const bool bDebugLog = UPS_AI_Behavior_Statics::IsDebugEnabled(DebugPawn);
|
||||
|
||||
// ─── Omniscient awareness for high-priority target types ────────
|
||||
// Protectors (police, player) are always known if within sight radius,
|
||||
// even outside the perception cone. This ensures enemies prioritize
|
||||
@ -325,7 +331,9 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
||||
if (MappedType == TopPriority)
|
||||
{
|
||||
PerceivedActors.Add(CandidatePawn);
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
||||
if (bDebugLog)
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] Omniscient awareness: added '%s' (type=%d, dist=%.0f) — top priority target"),
|
||||
*OwnerPawn->GetName(), *CandidatePawn->GetName(),
|
||||
static_cast<int32>(CandidateType), Dist);
|
||||
@ -333,6 +341,7 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PerceivedActors.Num() == 0)
|
||||
{
|
||||
@ -407,8 +416,11 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
||||
// Allied teams (Civilian ↔ Protector) → allow gunfire through
|
||||
if (AIC->GetGenericTeamId().GetId() == GetActorTeamId(OwningPawn))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] Target '%s': SKIPPED (same team 0x%02X)"),
|
||||
if (bDebugLog)
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Target '%s': SKIPPED (same team 0x%02X)"),
|
||||
*Owner->GetName(), *OwningPawn->GetName(), GetActorTeamId(OwningPawn));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -430,9 +442,12 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
||||
|
||||
if (!bActorHasGunshot)
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] Target '%s': SKIPPED (attitude=%d, not hostile, no gunshot, theirTeam=0x%02X, myTeam=0x%02X)"),
|
||||
if (bDebugLog)
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Target '%s': SKIPPED (attitude=%d, not hostile, no gunshot, theirTeam=0x%02X, myTeam=0x%02X)"),
|
||||
*Owner->GetName(), *OwningPawn->GetName(), static_cast<int32>(Attitude),
|
||||
GetActorTeamId(OwningPawn), AIC->GetGenericTeamId().GetId());
|
||||
}
|
||||
continue; // Not hostile, no gunshot — skip
|
||||
}
|
||||
}
|
||||
@ -522,9 +537,12 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
||||
{
|
||||
const FActorScore& Entry = Pair.Value;
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] Target '%s' (pawn='%s'): type=%d, hostile=%d, score=%.0f"),
|
||||
if (bDebugLog)
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Target '%s' (pawn='%s'): type=%d, hostile=%d, score=%.0f"),
|
||||
*Owner->GetName(), *Entry.Actor->GetName(), *Pair.Key->GetName(),
|
||||
static_cast<int32>(Entry.ActorType), Entry.bIsHostile ? 1 : 0, Entry.Score);
|
||||
}
|
||||
|
||||
if (Entry.Score > BestScore)
|
||||
{
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||
#include "PS_AI_Behavior_Interface.h"
|
||||
#include "PS_AI_Behavior_PersonalityProfile.h"
|
||||
#include "PS_AI_Behavior_Statics.h"
|
||||
#include "PS_AI_Behavior_AIController.h"
|
||||
#include "PS_AI_Behavior_SplineFollowerComponent.h"
|
||||
#include "PS_AI_Behavior_SplinePath.h"
|
||||
@ -87,11 +88,14 @@ EPS_AI_Behavior_State UPS_AI_Behavior_PersonalityComponent::EvaluateReaction() c
|
||||
const float EffectiveFleeThresh = FleeThresh * (0.5f + Courage * 0.5f) * (1.5f - Caution * 0.5f);
|
||||
const float EffectiveAttackThresh = AttackThresh * (1.5f - Aggressivity * 0.5f);
|
||||
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(Cast<APawn>(GetOwner())))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log,
|
||||
TEXT("[%s] EvaluateReaction: threat=%.2f, aggr=%.2f, courage=%.2f, caution=%.2f | attackThresh=%.2f, fleeThresh=%.2f, alertThresh=%.2f"),
|
||||
GetOwner() ? *GetOwner()->GetName() : TEXT("?"),
|
||||
PerceivedThreatLevel, Aggressivity, Courage, Caution,
|
||||
EffectiveAttackThresh, EffectiveFleeThresh, AlertThresh);
|
||||
}
|
||||
|
||||
// Decision cascade — with hysteresis to prevent state flickering.
|
||||
// Once in a state, require a larger threshold drop to leave it.
|
||||
@ -231,11 +235,14 @@ EPS_AI_Behavior_State UPS_AI_Behavior_PersonalityComponent::ApplyReaction()
|
||||
const EPS_AI_Behavior_State OldState = CurrentState;
|
||||
CurrentState = NewState; // Replicated → OnRep fires on clients
|
||||
|
||||
UE_LOG(LogPS_AI_Behavior, Verbose, TEXT("[%s] State: %s -> %s (Threat: %.2f)"),
|
||||
if (UPS_AI_Behavior_Statics::IsDebugEnabled(Cast<APawn>(GetOwner())))
|
||||
{
|
||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] State: %s -> %s (Threat: %.2f)"),
|
||||
*GetOwner()->GetName(),
|
||||
*UEnum::GetValueAsString(OldState),
|
||||
*UEnum::GetValueAsString(NewState),
|
||||
PerceivedThreatLevel);
|
||||
}
|
||||
|
||||
HandleStateChanged(OldState, NewState);
|
||||
}
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
// Copyright Asterion. All Rights Reserved.
|
||||
|
||||
#include "PS_AI_Behavior_Statics.h"
|
||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||
#include "Perception/AISense_Hearing.h"
|
||||
#include "CollisionQueryParams.h"
|
||||
#include "Engine/World.h"
|
||||
|
||||
static TAutoConsoleVariable<int32> CVarBehaviorDebug(
|
||||
TEXT("ps.ai.Behavior.Debug"),
|
||||
-1,
|
||||
TEXT("Global debug override for PS_AI_Behavior. -1=use per-NPC bDebug property, 0=force off, 1=force on."),
|
||||
ECVF_Default);
|
||||
|
||||
void UPS_AI_Behavior_Statics::ReportGunfire(UObject* WorldContext, FVector Location,
|
||||
AActor* Shooter, bool bIsEnemyFire, float Loudness, float MaxRange)
|
||||
{
|
||||
@ -58,3 +65,16 @@ bool UPS_AI_Behavior_Statics::HasLineOfSight(const UWorld* World, const AActor*
|
||||
|
||||
return !World->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECC_Visibility, Params);
|
||||
}
|
||||
|
||||
bool UPS_AI_Behavior_Statics::IsDebugEnabled(const APawn* Pawn)
|
||||
{
|
||||
// CVar override: 0=off, 1=on, -1=use property
|
||||
const int32 CVar = CVarBehaviorDebug.GetValueOnGameThread();
|
||||
if (CVar == 0) return false;
|
||||
if (CVar == 1) return true;
|
||||
|
||||
// Fall through to per-NPC property
|
||||
if (!Pawn) return false;
|
||||
const auto* Personality = Pawn->FindComponentByClass<UPS_AI_Behavior_PersonalityComponent>();
|
||||
return Personality && Personality->bDebug;
|
||||
}
|
||||
|
||||
@ -53,4 +53,7 @@ public:
|
||||
*/
|
||||
static bool HasLineOfSight(const UWorld* World, const AActor* Source, const AActor* Target,
|
||||
float EyeHeightOffset = 150.0f);
|
||||
|
||||
/** Check if debug is enabled for a given Pawn (checks CVar override first, then PersonalityComponent.bDebug). */
|
||||
static bool IsDebugEnabled(const APawn* Pawn);
|
||||
};
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user