// Copyright Epic Games, Inc. All Rights Reserved. #include "Perception/AISense.h" #include "Perception/AIPerceptionSystem.h" #include "Perception/AISenseConfig.h" #include "VisualLogger/VisualLogger.h" #include "Perception/AISenseConfig_Blueprint.h" #include "Perception/AISenseConfig_Hearing.h" #include "Perception/AISenseConfig_Prediction.h" #include "Perception/AISenseConfig_Sight.h" #include "Perception/AISenseConfig_Team.h" #include "Perception/AISenseConfig_Touch.h" #include "Perception/AIPerceptionComponent.h" #include "Perception/AISense_Blueprint.h" #include "Perception/AISense_Prediction.h" #include "Perception/AISense_Touch.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(AISense) #if WITH_GAMEPLAY_DEBUGGER_MENU #include "GameplayDebuggerTypes.h" #include "GameplayDebuggerCategory.h" #endif // WITH_GAMEPLAY_DEBUGGER_MENU const float UAISense::SuspendNextUpdate = FLT_MAX; UAISense::UAISense(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , TimeUntilNextUpdate(SuspendNextUpdate) , SenseID(FAISenseID::InvalidID()) { bNeedsForgettingNotification = false; if (HasAnyFlags(RF_ClassDefaultObject) == false) { SenseID = ((const UAISense*)GetClass()->GetDefaultObject())->GetSenseID(); } } UWorld* UAISense::GetWorld() const { return PerceptionSystemInstance ? PerceptionSystemInstance->GetWorld() : nullptr; } void UAISense::HardcodeSenseID(TSubclassOf SenseClass, FAISenseID HardcodedID) { UAISense* MutableCDO = GetMutableDefault(SenseClass); check(MutableCDO); MutableCDO->SenseID = HardcodedID; } void UAISense::PostInitProperties() { Super::PostInitProperties(); if (HasAnyFlags(RF_ClassDefaultObject) == false) { PerceptionSystemInstance = Cast(GetOuter()); } } AIPerception::FListenerMap* UAISense::GetListeners() { check(PerceptionSystemInstance); return &(PerceptionSystemInstance->GetListenersMap()); } void UAISense::OnNewPawn(APawn& NewPawn) { if (WantsNewPawnNotification()) { UE_VLOG(GetPerceptionSystem(), LogAIPerception, Warning , TEXT("%s declars it needs New Pawn notification but does not override OnNewPawn"), *GetName()); } } void UAISense::SetSenseID(FAISenseID Index) { check(Index != FAISenseID::InvalidID()); SenseID = Index; } void UAISense::ForceSenseID(FAISenseID InSenseID) { check(GetClass()->HasAnyClassFlags(CLASS_CompiledFromBlueprint) == true); ensure(GetClass()->HasAnyClassFlags(CLASS_Abstract) == false); SenseID = InSenseID; } FAISenseID UAISense::UpdateSenseID() { check(HasAnyFlags(RF_ClassDefaultObject) == true && GetClass()->HasAnyClassFlags(CLASS_Abstract | CLASS_CompiledFromBlueprint) == false); if (SenseID.IsValid() == false) { SenseID = FAISenseID(GetFName()); } return SenseID; } void UAISense::RegisterWrappedEvent(UAISenseEvent& PerceptionEvent) { UE_VLOG(GetPerceptionSystem(), LogAIPerception, Error, TEXT("%s did not override UAISense::RegisterWrappedEvent!"), *GetName()); } #if WITH_GAMEPLAY_DEBUGGER_MENU void UAISense::DescribeSelfToGameplayDebugger(const UAIPerceptionSystem& PerceptionSystem, FGameplayDebuggerCategory& DebuggerCategory) const { DebuggerCategory.AddTextLine(FString::Printf(TEXT("%s"), *SenseID.Name.ToString())); } #endif // WITH_GAMEPLAY_DEBUGGER_MENU //----------------------------------------------------------------------// // //----------------------------------------------------------------------// UAISenseConfig::UAISenseConfig(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer), DebugColor(FColor::White), bStartsEnabled(true) { } TSubclassOf UAISenseConfig::GetSenseImplementation() const { return UAISense::StaticClass(); } FString UAISenseConfig::GetSenseName() const { if (CachedSenseName.Len() == 0) { CachedSenseName = GetSenseImplementation()->GetName(); CachedSenseName.RemoveFromEnd(TEXT("_C")); int32 SeparatorIdx = INDEX_NONE; const bool bHasSeparator = CachedSenseName.FindLastChar(TEXT('_'), SeparatorIdx); if (bHasSeparator) { CachedSenseName.MidInline(SeparatorIdx + 1, MAX_int32, EAllowShrinking::No); } } return CachedSenseName; } #if WITH_GAMEPLAY_DEBUGGER_MENU static FString DescribeColorHelper(const FColor& Color) { const int32 MaxColors = GColorList.GetColorsNum(); for (int32 Idx = 0; Idx < MaxColors; Idx++) { if (Color == GColorList.GetFColorByIndex(Idx)) { return GColorList.GetColorNameByIndex(Idx); } } return FString(TEXT("color")); } void UAISenseConfig::DescribeSelfToGameplayDebugger(const UAIPerceptionComponent* PerceptionComponent, FGameplayDebuggerCategory* DebuggerCategory) const { if (DebuggerCategory) { DebuggerCategory->AddTextLine( FString::Printf(TEXT("%s: {%s}%s"), *GetSenseName(), *GetDebugColor().ToString(), *DescribeColorHelper(GetDebugColor())) ); } } #endif // WITH_GAMEPLAY_DEBUGGER_MENU //----------------------------------------------------------------------// // //----------------------------------------------------------------------// UAISenseConfig_Sight::UAISenseConfig_Sight(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { DebugColor = FColor::Green; } TSubclassOf UAISenseConfig_Sight::GetSenseImplementation() const { return *Implementation; } #if WITH_EDITOR void UAISenseConfig_Sight::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) { static const FName NAME_AutoSuccessRangeFromLastSeenLocation = GET_MEMBER_NAME_CHECKED(UAISenseConfig_Sight, AutoSuccessRangeFromLastSeenLocation); Super::PostEditChangeProperty(PropertyChangedEvent); if (PropertyChangedEvent.Property) { const FName PropName = PropertyChangedEvent.Property->GetFName(); if (PropName == NAME_AutoSuccessRangeFromLastSeenLocation) { if (AutoSuccessRangeFromLastSeenLocation < 0) { AutoSuccessRangeFromLastSeenLocation = FAISystem::InvalidRange; } } } } #endif // WITH_EDITOR #if WITH_GAMEPLAY_DEBUGGER_MENU void UAISenseConfig_Sight::DescribeSelfToGameplayDebugger(const UAIPerceptionComponent* PerceptionComponent, FGameplayDebuggerCategory* DebuggerCategory) const { if (PerceptionComponent == nullptr || DebuggerCategory == nullptr) { return; } FColor SightRangeColor = FColor::Green; FColor LoseSightRangeColor = FColorList::NeonPink; // don't call Super implementation on purpose, replace color description line DebuggerCategory->AddTextLine( FString::Printf(TEXT("%s: {%s}%s {white}rangeIN:{%s} %.2f (%s) {white} rangeOUT:{%s} %.2f (%s)"), *GetSenseName(), *GetDebugColor().ToString(), *DescribeColorHelper(GetDebugColor()), *SightRangeColor.ToString(), SightRadius, *DescribeColorHelper(SightRangeColor), *LoseSightRangeColor.ToString(), LoseSightRadius, *DescribeColorHelper(LoseSightRangeColor)) ); const AActor* BodyActor = PerceptionComponent->GetBodyActor(); if (BodyActor != nullptr) { FVector BodyLocation, BodyFacing; PerceptionComponent->GetLocationAndDirection(BodyLocation, BodyFacing); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeCylinder(BodyLocation, LoseSightRadius, 25.0f, LoseSightRangeColor)); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeCylinder(BodyLocation, SightRadius, 25.0f, SightRangeColor)); const float SightPieLength = FMath::Max(LoseSightRadius, SightRadius) + PointOfViewBackwardOffset; const FVector RootLocation = BodyLocation - (BodyFacing * PointOfViewBackwardOffset); const FVector LeftDirection = BodyFacing.RotateAngleAxis(PeripheralVisionAngleDegrees, FVector::UpVector); const FVector RightDirection = BodyFacing.RotateAngleAxis(-PeripheralVisionAngleDegrees, FVector::UpVector); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeSegment(RootLocation + (BodyFacing * NearClippingRadius), RootLocation + (BodyFacing * SightPieLength), SightRangeColor)); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeSegment(RootLocation + (LeftDirection * NearClippingRadius), RootLocation + (LeftDirection * SightPieLength), SightRangeColor)); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeSegment(RootLocation + (RightDirection * NearClippingRadius), RootLocation + (RightDirection * SightPieLength), SightRangeColor)); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeSegment(RootLocation + (LeftDirection * NearClippingRadius), RootLocation + (BodyFacing * NearClippingRadius), SightRangeColor)); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeSegment(RootLocation + (BodyFacing * NearClippingRadius), RootLocation + (RightDirection * NearClippingRadius), SightRangeColor)); } } #endif // WITH_GAMEPLAY_DEBUGGER_MENU //----------------------------------------------------------------------// // UAISenseConfig_Hearing //----------------------------------------------------------------------// UAISenseConfig_Hearing::UAISenseConfig_Hearing(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer), HearingRange(3000.f) { DebugColor = FColor::Yellow; } TSubclassOf UAISenseConfig_Hearing::GetSenseImplementation() const { return *Implementation; } #if WITH_GAMEPLAY_DEBUGGER_MENU void UAISenseConfig_Hearing::DescribeSelfToGameplayDebugger(const UAIPerceptionComponent* PerceptionComponent, FGameplayDebuggerCategory* DebuggerCategory) const { if (PerceptionComponent == nullptr || DebuggerCategory == nullptr) { return; } FColor HearingRangeColor = FColor::Yellow; FColor LoSHearingRangeColor = FColorList::Cyan; // don't call Super implementation on purpose, replace color description line DebuggerCategory->AddTextLine( FString::Printf(TEXT("%s: {%s}%s {white}range:{%s}%s {white} rangeLoS:{%s}%s"), *GetSenseName(), *GetDebugColor().ToString(), *DescribeColorHelper(GetDebugColor()), *HearingRangeColor.ToString(), *DescribeColorHelper(HearingRangeColor), *LoSHearingRangeColor.ToString(), *DescribeColorHelper(LoSHearingRangeColor)) ); const AActor* BodyActor = PerceptionComponent->GetBodyActor(); if (BodyActor != nullptr) { FVector OwnerLocation = BodyActor->GetActorLocation(); DebuggerCategory->AddShape(FGameplayDebuggerShape::MakeCylinder(OwnerLocation, HearingRange, 25.0f, HearingRangeColor)); } } #endif // WITH_GAMEPLAY_DEBUGGER_MENU //----------------------------------------------------------------------// // UAISenseConfig_Prediction //----------------------------------------------------------------------// UAISenseConfig_Prediction::UAISenseConfig_Prediction(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { DebugColor = FColorList::Grey; } TSubclassOf UAISenseConfig_Prediction::GetSenseImplementation() const { return UAISense_Prediction::StaticClass(); } UAISenseConfig_Blueprint::UAISenseConfig_Blueprint(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { DebugColor = FColorList::Grey; } TSubclassOf UAISenseConfig_Blueprint::GetSenseImplementation() const { return *Implementation; } UAISenseConfig_Team::UAISenseConfig_Team(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { DebugColor = FColor::Blue; } UAISenseConfig_Touch::UAISenseConfig_Touch(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { DebugColor = FColor::Cyan; } TSubclassOf UAISenseConfig_Touch::GetSenseImplementation() const { return UAISense_Touch::StaticClass(); }