Compare commits
3 Commits
c32aba9902
...
a31ac1d782
| Author | SHA1 | Date | |
|---|---|---|---|
| a31ac1d782 | |||
| 661e8c66ac | |||
| b473fcda22 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
|
// Debug: check what perception sees
|
||||||
TArray<AActor*> PerceivedActors;
|
TArray<AActor*> PerceivedActors;
|
||||||
Perception->GetCurrentlyPerceivedActors(nullptr, 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()))
|
||||||
*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] UpdateThreat: Perceived %d actors"),
|
||||||
|
*AIC->GetName(), PerceivedActors.Num());
|
||||||
|
for (AActor* A : PerceivedActors)
|
||||||
|
{
|
||||||
|
UE_LOG(LogPS_AI_Behavior, Log, TEXT(" - %s"), *A->GetName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check known actors (perceived in the past but maybe lost sight)
|
// Also check known actors (perceived in the past but maybe lost sight)
|
||||||
TArray<AActor*> KnownActors;
|
TArray<AActor*> KnownActors;
|
||||||
Perception->GetKnownPerceivedActors(nullptr, 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());
|
*AIC->GetName(), KnownActors.Num());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +77,11 @@ void UPS_AI_Behavior_BTService_UpdateThreat::TickNode(
|
|||||||
|
|
||||||
BB->SetValueAsFloat(PS_AI_Behavior_BB::ThreatLevel, FinalThreat);
|
BB->SetValueAsFloat(PS_AI_Behavior_BB::ThreatLevel, FinalThreat);
|
||||||
|
|
||||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] UpdateThreat: raw=%.2f, stored=%.2f, final=%.2f"),
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
*AIC->GetName(), RawThreat, StoredThreat, FinalThreat);
|
{
|
||||||
|
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 ─────────
|
// ─── Update threat actor and location with LOS tracking ─────────
|
||||||
FUpdateThreatMemory* Memory = reinterpret_cast<FUpdateThreatMemory*>(NodeMemory);
|
FUpdateThreatMemory* Memory = reinterpret_cast<FUpdateThreatMemory*>(NodeMemory);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "PS_AI_Behavior_SplineNetwork.h"
|
#include "PS_AI_Behavior_SplineNetwork.h"
|
||||||
#include "PS_AI_Behavior_SplinePath.h"
|
#include "PS_AI_Behavior_SplinePath.h"
|
||||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||||
|
#include "PS_AI_Behavior_Statics.h"
|
||||||
#include "PS_AI_Behavior_Definitions.h"
|
#include "PS_AI_Behavior_Definitions.h"
|
||||||
#include "Navigation/PathFollowingComponent.h"
|
#include "Navigation/PathFollowingComponent.h"
|
||||||
|
|
||||||
@ -32,10 +33,13 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Debug: log state on entry
|
// Debug: log state on entry
|
||||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindAndFollowSpline: bIsFollowing=%d CurrentSpline=%s"),
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
*AIC->GetName(),
|
{
|
||||||
(int32)Follower->bIsFollowing,
|
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindAndFollowSpline: bIsFollowing=%d CurrentSpline=%s"),
|
||||||
Follower->CurrentSpline ? *Follower->CurrentSpline->GetName() : TEXT("null"));
|
*AIC->GetName(),
|
||||||
|
(int32)Follower->bIsFollowing,
|
||||||
|
Follower->CurrentSpline ? *Follower->CurrentSpline->GetName() : TEXT("null"));
|
||||||
|
}
|
||||||
|
|
||||||
// If already following a spline, don't re-search — just succeed immediately
|
// If already following a spline, don't re-search — just succeed immediately
|
||||||
// The Follow Spline task will continue the movement
|
// 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 FVector SplineDir = Follower->CurrentSpline->GetWorldDirectionAtDistance(ClosestDist);
|
||||||
const bool bForward = FVector::DotProduct(PawnFwd, SplineDir) >= 0.0f;
|
const bool bForward = FVector::DotProduct(PawnFwd, SplineDir) >= 0.0f;
|
||||||
|
|
||||||
UE_LOG(LogPS_AI_Behavior, Log,
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
TEXT("[%s] FindAndFollowSpline: resuming spline '%s' at closest point (gap=%.0fcm, dist=%.0f, bWalkToSpline=%d, AcceptanceRadius=%.0f)"),
|
{
|
||||||
*AIC->GetName(), *Follower->CurrentSpline->GetName(), GapToSpline, ClosestDist,
|
UE_LOG(LogPS_AI_Behavior, Log,
|
||||||
(int32)bWalkToSpline, AcceptanceRadius);
|
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)
|
if (bWalkToSpline && GapToSpline > AcceptanceRadius)
|
||||||
{
|
{
|
||||||
@ -73,9 +80,12 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
|||||||
/*bUsePathfinding=*/true, /*bProjectDestinationToNavigation=*/true,
|
/*bUsePathfinding=*/true, /*bProjectDestinationToNavigation=*/true,
|
||||||
/*bCanStrafe=*/false);
|
/*bCanStrafe=*/false);
|
||||||
|
|
||||||
UE_LOG(LogPS_AI_Behavior, Log,
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
TEXT("[%s] FindAndFollowSpline: MoveToLocation result=%d (0=Failed, 1=AlreadyAtGoal, 2=RequestSuccessful)"),
|
{
|
||||||
*AIC->GetName(), (int32)Result);
|
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)
|
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
|
// Close enough — clear any residual movement request and start following
|
||||||
AIC->StopMovement();
|
AIC->StopMovement();
|
||||||
UE_LOG(LogPS_AI_Behavior, Log,
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
TEXT("[%s] FindAndFollowSpline: close enough, StartFollowingAtDistance(dist=%.0f, fwd=%d)"),
|
{
|
||||||
*AIC->GetName(), ClosestDist, (int32)bForward);
|
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);
|
Follower->StartFollowingAtDistance(Follower->CurrentSpline, ClosestDist, bForward);
|
||||||
return EBTNodeResult::Succeeded;
|
return EBTNodeResult::Succeeded;
|
||||||
}
|
}
|
||||||
@ -131,9 +144,12 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
|||||||
AIC->GetPawn()->GetActorLocation(), NPCType, MaxSearchDistance,
|
AIC->GetPawn()->GetActorLocation(), NPCType, MaxSearchDistance,
|
||||||
ClosestSpline, DistAlongSpline))
|
ClosestSpline, DistAlongSpline))
|
||||||
{
|
{
|
||||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
TEXT("[%s] FindAndFollowSpline: no accessible spline within %.0fcm."),
|
{
|
||||||
*AIC->GetName(), MaxSearchDistance);
|
UE_LOG(LogPS_AI_Behavior, Log,
|
||||||
|
TEXT("[%s] FindAndFollowSpline: no accessible spline within %.0fcm."),
|
||||||
|
*AIC->GetName(), MaxSearchDistance);
|
||||||
|
}
|
||||||
return EBTNodeResult::Failed;
|
return EBTNodeResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,10 +157,13 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindAndFollowSpline::ExecuteTask(
|
|||||||
const FVector SplinePoint = ClosestSpline->GetWorldLocationAtDistance(DistAlongSpline);
|
const FVector SplinePoint = ClosestSpline->GetWorldLocationAtDistance(DistAlongSpline);
|
||||||
const float GapToSpline = FVector::Dist(AIC->GetPawn()->GetActorLocation(), SplinePoint);
|
const float GapToSpline = FVector::Dist(AIC->GetPawn()->GetActorLocation(), SplinePoint);
|
||||||
|
|
||||||
UE_LOG(LogPS_AI_Behavior, Verbose,
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
TEXT("[%s] FindAndFollowSpline: found spline '%s' at dist=%.0f/%.0f, gap=%.0fcm"),
|
{
|
||||||
*AIC->GetName(), *ClosestSpline->GetName(), DistAlongSpline,
|
UE_LOG(LogPS_AI_Behavior, Log,
|
||||||
ClosestSpline->GetSplineLength(), GapToSpline);
|
TEXT("[%s] FindAndFollowSpline: found spline '%s' at dist=%.0f/%.0f, gap=%.0fcm"),
|
||||||
|
*AIC->GetName(), *ClosestSpline->GetName(), DistAlongSpline,
|
||||||
|
ClosestSpline->GetSplineLength(), GapToSpline);
|
||||||
|
}
|
||||||
|
|
||||||
if (bWalkToSpline && GapToSpline > AcceptanceRadius)
|
if (bWalkToSpline && GapToSpline > AcceptanceRadius)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "PS_AI_Behavior_Interface.h"
|
#include "PS_AI_Behavior_Interface.h"
|
||||||
#include "PS_AI_Behavior_CoverPoint.h"
|
#include "PS_AI_Behavior_CoverPoint.h"
|
||||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||||
|
#include "PS_AI_Behavior_Statics.h"
|
||||||
#include "PS_AI_Behavior_Definitions.h"
|
#include "PS_AI_Behavior_Definitions.h"
|
||||||
#include "BehaviorTree/BlackboardComponent.h"
|
#include "BehaviorTree/BlackboardComponent.h"
|
||||||
#include "NavigationSystem.h"
|
#include "NavigationSystem.h"
|
||||||
@ -122,7 +123,10 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindCover::ExecuteTask(
|
|||||||
|
|
||||||
if (BestScore < 0.1f)
|
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;
|
return EBTNodeResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,17 +136,23 @@ EBTNodeResult::Type UPS_AI_Behavior_BTTask_FindCover::ExecuteTask(
|
|||||||
ChosenPoint->Claim(AIC->GetPawn());
|
ChosenPoint->Claim(AIC->GetPawn());
|
||||||
BB->SetValueAsObject(PS_AI_Behavior_BB::CoverPoint, ChosenPoint);
|
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()))
|
||||||
*AIC->GetName(),
|
{
|
||||||
ChosenPoint->PointType == EPS_AI_Behavior_CoverPointType::Cover ? TEXT("Cover") : TEXT("HidingSpot"),
|
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] FindCover: using manual %s '%s' (score %.2f)"),
|
||||||
*ChosenPoint->GetName(), BestScore);
|
*AIC->GetName(),
|
||||||
|
ChosenPoint->PointType == EPS_AI_Behavior_CoverPointType::Cover ? TEXT("Cover") : TEXT("HidingSpot"),
|
||||||
|
*ChosenPoint->GetName(), BestScore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BB->ClearValue(PS_AI_Behavior_BB::CoverPoint);
|
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()))
|
||||||
*AIC->GetName(), BestScore);
|
{
|
||||||
|
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);
|
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 FVector CoverLoc = BB->GetValueAsVector(PS_AI_Behavior_BB::CoverLocation);
|
||||||
const float DistToCover = FVector::Dist2D(Pawn->GetActorLocation(), CoverLoc);
|
const float DistToCover = FVector::Dist2D(Pawn->GetActorLocation(), CoverLoc);
|
||||||
|
|
||||||
UE_LOG(LogPS_AI_Behavior, Log,
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(AIC->GetPawn()))
|
||||||
TEXT("[%s] FindCover: MoveStatus=Idle, dist2D=%.0fcm, acceptance=%.0fcm, coverLoc=%s, pawnLoc=%s"),
|
{
|
||||||
*AIC->GetName(), DistToCover, AcceptanceRadius,
|
UE_LOG(LogPS_AI_Behavior, Log,
|
||||||
*CoverLoc.ToString(), *Pawn->GetActorLocation().ToString());
|
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)
|
if (DistToCover > AcceptanceRadius * 2.0f)
|
||||||
{
|
{
|
||||||
@ -445,8 +458,11 @@ void UPS_AI_Behavior_BTTask_FindCover::RunRefinementQuery(
|
|||||||
&UPS_AI_Behavior_BTTask_FindCover::OnRefinementQueryFinished,
|
&UPS_AI_Behavior_BTTask_FindCover::OnRefinementQueryFinished,
|
||||||
&OwnerComp, NodeMemory, CoverCenter));
|
&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))
|
||||||
*Pawn->GetName(), *CoverCenter.ToString());
|
{
|
||||||
|
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(
|
void UPS_AI_Behavior_BTTask_FindCover::OnRefinementQueryFinished(
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||||
#include "PS_AI_Behavior_PersonalityProfile.h"
|
#include "PS_AI_Behavior_PersonalityProfile.h"
|
||||||
#include "PS_AI_Behavior_TeamComponent.h"
|
#include "PS_AI_Behavior_TeamComponent.h"
|
||||||
|
#include "PS_AI_Behavior_Statics.h"
|
||||||
#include "PS_AI_Behavior_Settings.h"
|
#include "PS_AI_Behavior_Settings.h"
|
||||||
#include "Perception/AISenseConfig_Sight.h"
|
#include "Perception/AISenseConfig_Sight.h"
|
||||||
#include "Perception/AISenseConfig_Hearing.h"
|
#include "Perception/AISenseConfig_Hearing.h"
|
||||||
@ -286,6 +287,11 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
|||||||
TArray<AActor*> PerceivedActors;
|
TArray<AActor*> PerceivedActors;
|
||||||
GetCurrentlyPerceivedActors(nullptr, PerceivedActors); // All senses at once
|
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 ────────
|
// ─── Omniscient awareness for high-priority target types ────────
|
||||||
// Protectors (police, player) are always known if within sight radius,
|
// Protectors (police, player) are always known if within sight radius,
|
||||||
// even outside the perception cone. This ensures enemies prioritize
|
// even outside the perception cone. This ensures enemies prioritize
|
||||||
@ -325,10 +331,13 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
|||||||
if (MappedType == TopPriority)
|
if (MappedType == TopPriority)
|
||||||
{
|
{
|
||||||
PerceivedActors.Add(CandidatePawn);
|
PerceivedActors.Add(CandidatePawn);
|
||||||
UE_LOG(LogPS_AI_Behavior, Log,
|
if (bDebugLog)
|
||||||
TEXT("[%s] Omniscient awareness: added '%s' (type=%d, dist=%.0f) — top priority target"),
|
{
|
||||||
*OwnerPawn->GetName(), *CandidatePawn->GetName(),
|
UE_LOG(LogPS_AI_Behavior, Log,
|
||||||
static_cast<int32>(CandidateType), Dist);
|
TEXT("[%s] Omniscient awareness: added '%s' (type=%d, dist=%.0f) — top priority target"),
|
||||||
|
*OwnerPawn->GetName(), *CandidatePawn->GetName(),
|
||||||
|
static_cast<int32>(CandidateType), Dist);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,8 +416,11 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
|||||||
// Allied teams (Civilian ↔ Protector) → allow gunfire through
|
// Allied teams (Civilian ↔ Protector) → allow gunfire through
|
||||||
if (AIC->GetGenericTeamId().GetId() == GetActorTeamId(OwningPawn))
|
if (AIC->GetGenericTeamId().GetId() == GetActorTeamId(OwningPawn))
|
||||||
{
|
{
|
||||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Target '%s': SKIPPED (same team 0x%02X)"),
|
if (bDebugLog)
|
||||||
*Owner->GetName(), *OwningPawn->GetName(), GetActorTeamId(OwningPawn));
|
{
|
||||||
|
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Target '%s': SKIPPED (same team 0x%02X)"),
|
||||||
|
*Owner->GetName(), *OwningPawn->GetName(), GetActorTeamId(OwningPawn));
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,9 +442,12 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
|||||||
|
|
||||||
if (!bActorHasGunshot)
|
if (!bActorHasGunshot)
|
||||||
{
|
{
|
||||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Target '%s': SKIPPED (attitude=%d, not hostile, no gunshot, theirTeam=0x%02X, myTeam=0x%02X)"),
|
if (bDebugLog)
|
||||||
*Owner->GetName(), *OwningPawn->GetName(), static_cast<int32>(Attitude),
|
{
|
||||||
GetActorTeamId(OwningPawn), AIC->GetGenericTeamId().GetId());
|
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
|
continue; // Not hostile, no gunshot — skip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,9 +537,12 @@ AActor* UPS_AI_Behavior_PerceptionComponent::GetHighestThreatActor(
|
|||||||
{
|
{
|
||||||
const FActorScore& Entry = Pair.Value;
|
const FActorScore& Entry = Pair.Value;
|
||||||
|
|
||||||
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Target '%s' (pawn='%s'): type=%d, hostile=%d, score=%.0f"),
|
if (bDebugLog)
|
||||||
*Owner->GetName(), *Entry.Actor->GetName(), *Pair.Key->GetName(),
|
{
|
||||||
static_cast<int32>(Entry.ActorType), Entry.bIsHostile ? 1 : 0, Entry.Score);
|
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)
|
if (Entry.Score > BestScore)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "PS_AI_Behavior_PersonalityComponent.h"
|
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||||
#include "PS_AI_Behavior_Interface.h"
|
#include "PS_AI_Behavior_Interface.h"
|
||||||
#include "PS_AI_Behavior_PersonalityProfile.h"
|
#include "PS_AI_Behavior_PersonalityProfile.h"
|
||||||
|
#include "PS_AI_Behavior_Statics.h"
|
||||||
#include "PS_AI_Behavior_AIController.h"
|
#include "PS_AI_Behavior_AIController.h"
|
||||||
#include "PS_AI_Behavior_SplineFollowerComponent.h"
|
#include "PS_AI_Behavior_SplineFollowerComponent.h"
|
||||||
#include "PS_AI_Behavior_SplinePath.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 EffectiveFleeThresh = FleeThresh * (0.5f + Courage * 0.5f) * (1.5f - Caution * 0.5f);
|
||||||
const float EffectiveAttackThresh = AttackThresh * (1.5f - Aggressivity * 0.5f);
|
const float EffectiveAttackThresh = AttackThresh * (1.5f - Aggressivity * 0.5f);
|
||||||
|
|
||||||
UE_LOG(LogPS_AI_Behavior, Log,
|
if (UPS_AI_Behavior_Statics::IsDebugEnabled(Cast<APawn>(GetOwner())))
|
||||||
TEXT("[%s] EvaluateReaction: threat=%.2f, aggr=%.2f, courage=%.2f, caution=%.2f | attackThresh=%.2f, fleeThresh=%.2f, alertThresh=%.2f"),
|
{
|
||||||
GetOwner() ? *GetOwner()->GetName() : TEXT("?"),
|
UE_LOG(LogPS_AI_Behavior, Log,
|
||||||
PerceivedThreatLevel, Aggressivity, Courage, Caution,
|
TEXT("[%s] EvaluateReaction: threat=%.2f, aggr=%.2f, courage=%.2f, caution=%.2f | attackThresh=%.2f, fleeThresh=%.2f, alertThresh=%.2f"),
|
||||||
EffectiveAttackThresh, EffectiveFleeThresh, AlertThresh);
|
GetOwner() ? *GetOwner()->GetName() : TEXT("?"),
|
||||||
|
PerceivedThreatLevel, Aggressivity, Courage, Caution,
|
||||||
|
EffectiveAttackThresh, EffectiveFleeThresh, AlertThresh);
|
||||||
|
}
|
||||||
|
|
||||||
// Decision cascade — with hysteresis to prevent state flickering.
|
// Decision cascade — with hysteresis to prevent state flickering.
|
||||||
// Once in a state, require a larger threshold drop to leave it.
|
// 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;
|
const EPS_AI_Behavior_State OldState = CurrentState;
|
||||||
CurrentState = NewState; // Replicated → OnRep fires on clients
|
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())))
|
||||||
*GetOwner()->GetName(),
|
{
|
||||||
*UEnum::GetValueAsString(OldState),
|
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] State: %s -> %s (Threat: %.2f)"),
|
||||||
*UEnum::GetValueAsString(NewState),
|
*GetOwner()->GetName(),
|
||||||
PerceivedThreatLevel);
|
*UEnum::GetValueAsString(OldState),
|
||||||
|
*UEnum::GetValueAsString(NewState),
|
||||||
|
PerceivedThreatLevel);
|
||||||
|
}
|
||||||
|
|
||||||
HandleStateChanged(OldState, NewState);
|
HandleStateChanged(OldState, NewState);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,17 @@
|
|||||||
// Copyright Asterion. All Rights Reserved.
|
// Copyright Asterion. All Rights Reserved.
|
||||||
|
|
||||||
#include "PS_AI_Behavior_Statics.h"
|
#include "PS_AI_Behavior_Statics.h"
|
||||||
|
#include "PS_AI_Behavior_PersonalityComponent.h"
|
||||||
#include "Perception/AISense_Hearing.h"
|
#include "Perception/AISense_Hearing.h"
|
||||||
#include "CollisionQueryParams.h"
|
#include "CollisionQueryParams.h"
|
||||||
#include "Engine/World.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,
|
void UPS_AI_Behavior_Statics::ReportGunfire(UObject* WorldContext, FVector Location,
|
||||||
AActor* Shooter, bool bIsEnemyFire, float Loudness, float MaxRange)
|
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);
|
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,
|
static bool HasLineOfSight(const UWorld* World, const AActor* Source, const AActor* Target,
|
||||||
float EyeHeightOffset = 150.0f);
|
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.
Binary file not shown.
@ -232,18 +232,17 @@ void UPS_AI_ConvAgent_BodyExpressionComponent::PickAndSwitchAnim()
|
|||||||
void UPS_AI_ConvAgent_BodyExpressionComponent::OnConversationConnected(
|
void UPS_AI_ConvAgent_BodyExpressionComponent::OnConversationConnected(
|
||||||
const FPS_AI_ConvAgent_ConversationInfo_ElevenLabs& Info)
|
const FPS_AI_ConvAgent_ConversationInfo_ElevenLabs& Info)
|
||||||
{
|
{
|
||||||
bActive = true;
|
// Don't activate yet — wait for the agent to actually speak (OnSpeakingStarted).
|
||||||
|
// This prevents body expressions from playing while the NPC is still walking
|
||||||
|
// and the user hasn't said anything yet.
|
||||||
bIsSpeaking = false;
|
bIsSpeaking = false;
|
||||||
LastEventName = TEXT("Connected");
|
LastEventName = TEXT("Connected");
|
||||||
LastEventWorldTime = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0f;
|
LastEventWorldTime = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0f;
|
||||||
|
|
||||||
// Start with an idle anim
|
|
||||||
PickAndSwitchAnim();
|
|
||||||
|
|
||||||
if (bDebug)
|
if (bDebug)
|
||||||
{
|
{
|
||||||
UE_LOG(LogPS_AI_ConvAgent_BodyExpr, Log,
|
UE_LOG(LogPS_AI_ConvAgent_BodyExpr, Log,
|
||||||
TEXT("Conversation connected — body expression activating (idle)."));
|
TEXT("Conversation connected — waiting for agent speech to activate body expressions."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +267,12 @@ void UPS_AI_ConvAgent_BodyExpressionComponent::OnConversationDisconnected(
|
|||||||
|
|
||||||
void UPS_AI_ConvAgent_BodyExpressionComponent::OnSpeakingStarted()
|
void UPS_AI_ConvAgent_BodyExpressionComponent::OnSpeakingStarted()
|
||||||
{
|
{
|
||||||
|
// Activate on first speech if not already active (deferred from OnConversationConnected)
|
||||||
|
if (!bActive)
|
||||||
|
{
|
||||||
|
bActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
bIsSpeaking = true;
|
bIsSpeaking = true;
|
||||||
LastEventName = TEXT("SpeakStart");
|
LastEventName = TEXT("SpeakStart");
|
||||||
LastEventWorldTime = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0f;
|
LastEventWorldTime = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0f;
|
||||||
@ -278,7 +283,7 @@ void UPS_AI_ConvAgent_BodyExpressionComponent::OnSpeakingStarted()
|
|||||||
if (bDebug)
|
if (bDebug)
|
||||||
{
|
{
|
||||||
UE_LOG(LogPS_AI_ConvAgent_BodyExpr, Log,
|
UE_LOG(LogPS_AI_ConvAgent_BodyExpr, Log,
|
||||||
TEXT("Agent started speaking — switching to speaking body anim."));
|
TEXT("Agent started speaking — body expression activating + speaking anim."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user