// Copyright Epic Games, Inc. All Rights Reserved. #include "BehaviorTree/ValueOrBBKey.h" #include "BehaviorTree/BehaviorTree.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Bool.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Class.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Enum.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Float.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Int.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Name.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Object.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Rotator.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_String.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Struct.h" #include "BehaviorTree/Blackboard/BlackboardKeyType_Vector.h" #include "BehaviorTree/BlackboardData.h" #include "BehaviorTree/BTNode.h" // For LogBehaviorTree #include UE_INLINE_GENERATED_CPP_BY_NAME(ValueOrBBKey) namespace FBlackboard { FConstStructView TryGetBlackboardKeyStruct(const UBlackboardComponent& Blackboard, const FName& Name, FBlackboard::FKey& InOutCachedKey, const UScriptStruct* TargetStruct) { if (InOutCachedKey == FBlackboard::InvalidKey) { InOutCachedKey = Blackboard.GetKeyID(Name); } if (const UBlackboardData* BlackBoarData = Blackboard.GetBlackboardAsset()) { if (const FBlackboardEntry* BBEntry = BlackBoarData->GetKey(InOutCachedKey)) { if (UBlackboardKeyType_Struct* StructKeyType = Cast(BBEntry->KeyType)) { if (StructKeyType->DefaultValue.GetScriptStruct() == TargetStruct) { return Blackboard.GetValue(InOutCachedKey); } } } } return FConstStructView{}; } FConstStructView GetStructValue(const UBlackboardComponent& Blackboard, const FName& Name, FBlackboard::FKey& InOutCachedKey, const FConstStructView& DefaultValue) { if (!Name.IsNone()) { FConstStructView KeyValue = FBlackboard::TryGetBlackboardKeyStruct(Blackboard, Name, InOutCachedKey, DefaultValue.GetScriptStruct()); if (KeyValue.IsValid()) { return KeyValue; } } return DefaultValue; } FConstStructView GetStructValue(const UBehaviorTreeComponent& BehaviorComp, const FName& Name, FBlackboard::FKey& InOutCachedKey, const FConstStructView& DefaultValue) { if (const UBlackboardComponent* Blackboard = BehaviorComp.GetBlackboardComponent()) { return GetStructValue(*Blackboard, Name, InOutCachedKey, DefaultValue); } return DefaultValue; } } // namespace FBlackboard FBlackboard::FKey FValueOrBlackboardKeyBase::GetKeyId(const UBehaviorTreeComponent& OwnerComp) const { if (KeyId == FBlackboard::InvalidKey) { if (const UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent()) { KeyId = BlackboardComp->GetKeyID(Key); } } return KeyId; } FString FValueOrBlackboardKeyBase::ToStringKeyName() const { return FString::Format(TEXT("Key: {0}"), { *Key.ToString() }); } FString FValueOrBBKey_Class::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return GetNameSafe(DefaultValue); } } FString FValueOrBBKey_Enum::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return EnumType ? EnumType->GetNameStringByValue(DefaultValue) : TEXT("Invalid Enum"); } } FString FValueOrBBKey_Float::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return FString::Printf(TEXT("%.2f"), DefaultValue); } } bool FValueOrBBKey_Float::IsBoundOrNonZero() const { return !Key.IsNone() || !FMath::IsNearlyEqual(DefaultValue, 0.f); } FString FValueOrBBKey_Name::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return DefaultValue.ToString(); } } FString FValueOrBBKey_Object::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return GetNameSafe(DefaultValue); } } FString FValueOrBBKey_Rotator::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return DefaultValue.ToString(); } } FString FValueOrBBKey_Struct::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return GetNameSafe(DefaultValue.GetScriptStruct()); } } FString FValueOrBBKey_Vector::ToString() const { if (!Key.IsNone()) { return ToStringKeyName(); } else { return DefaultValue.ToString(); } } bool FValueOrBBKey_Bool::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } bool FValueOrBBKey_Bool::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } bool FValueOrBBKey_Bool::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } bool FValueOrBBKey_Bool::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } UClass* FValueOrBBKey_Class::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue.Get()); } UClass* FValueOrBBKey_Class::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue.Get(); } UClass* FValueOrBBKey_Class::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue.Get()); } UClass* FValueOrBBKey_Class::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue.Get(); } uint8 FValueOrBBKey_Enum::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } uint8 FValueOrBBKey_Enum::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } uint8 FValueOrBBKey_Enum::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } uint8 FValueOrBBKey_Enum::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } float FValueOrBBKey_Float::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } float FValueOrBBKey_Float::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } float FValueOrBBKey_Float::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } float FValueOrBBKey_Float::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } int32 FValueOrBBKey_Int32::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } int32 FValueOrBBKey_Int32::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } int32 FValueOrBBKey_Int32::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } int32 FValueOrBBKey_Int32::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } FName FValueOrBBKey_Name::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } FName FValueOrBBKey_Name::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } FName FValueOrBBKey_Name::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } FName FValueOrBBKey_Name::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } FString FValueOrBBKey_String::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } FString FValueOrBBKey_String::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } FString FValueOrBBKey_String::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } FString FValueOrBBKey_String::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } UObject* FValueOrBBKey_Object::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue.Get()); } UObject* FValueOrBBKey_Object::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue.Get(); } UObject* FValueOrBBKey_Object::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue.Get()); } UObject* FValueOrBBKey_Object::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue.Get(); } FRotator FValueOrBBKey_Rotator::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } FRotator FValueOrBBKey_Rotator::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } FRotator FValueOrBBKey_Rotator::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } FRotator FValueOrBBKey_Rotator::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } FConstStructView FValueOrBBKey_Struct::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetStructValue(Blackboard, Key, KeyId, FConstStructView(DefaultValue)); } FConstStructView FValueOrBBKey_Struct::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } FConstStructView FValueOrBBKey_Struct::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetStructValue(BehaviorComp, Key, KeyId, FConstStructView(DefaultValue)); } FConstStructView FValueOrBBKey_Struct::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } FVector FValueOrBBKey_Vector::GetValue(const UBlackboardComponent& Blackboard) const { return FBlackboard::GetValue(Blackboard, Key, KeyId, DefaultValue); } FVector FValueOrBBKey_Vector::GetValue(const UBlackboardComponent* Blackboard) const { return Blackboard ? GetValue(*Blackboard) : DefaultValue; } FVector FValueOrBBKey_Vector::GetValue(const UBehaviorTreeComponent& BehaviorComp) const { return FBlackboard::GetValue(BehaviorComp, Key, KeyId, DefaultValue); } FVector FValueOrBBKey_Vector::GetValue(const UBehaviorTreeComponent* BehaviorComp) const { return BehaviorComp ? GetValue(*BehaviorComp) : DefaultValue; } bool FValueOrBBKey_Bool::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_BoolProperty) { DefaultValue = Tag.BoolVal != 0; return true; } return false; } bool FValueOrBBKey_Class::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_ObjectProperty) // Class and object share the same tag { Slot << DefaultValue; return true; } return false; } bool FValueOrBBKey_Enum::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if ((Tag.Type == NAME_EnumProperty || Tag.Type == NAME_ByteProperty) && Tag.GetType().GetParameterCount() > 0) { if (const UEnum* Enum = FindFirstObject(*Tag.GetType().GetParameterName(0).ToString(), EFindFirstObjectOptions::NativeFirst)) { FName EnumValue; Slot << EnumValue; DefaultValue = static_cast(Enum->GetValueByName(EnumValue)); return true; } } return false; } bool FValueOrBBKey_Float::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_FloatProperty) { Slot << DefaultValue; return true; } return false; } bool FValueOrBBKey_Int32::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_Int32Property || Tag.Type == NAME_IntProperty) { Slot << DefaultValue; return true; } return false; } bool FValueOrBBKey_Name::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_NameProperty) { Slot << DefaultValue; return true; } return false; } bool FValueOrBBKey_String::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_StrProperty) { Slot << DefaultValue; return true; } return false; } bool FValueOrBBKey_Object::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_ObjectProperty) { Slot << DefaultValue; return true; } return false; } bool FValueOrBBKey_Rotator::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_RotatorProperty) { Slot << DefaultValue; return true; } return false; } bool FValueOrBBKey_Struct::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_StructProperty && Tag.GetType().GetParameterCount() > 0) { if (UScriptStruct* Struct = FindFirstObject(*Tag.GetType().GetParameterName(0).ToString(), EFindFirstObjectOptions::NativeFirst)) { if (Struct == DefaultValue.GetScriptStruct() || DefaultValue.GetScriptStruct() == nullptr) { TUniquePtr SerializedStruct = MakeUnique(Struct->GetStructureSize()); Struct->InitializeStruct(SerializedStruct.Get()); Struct->SerializeItem(Slot, SerializedStruct.Get(), nullptr); DefaultValue.InitializeAs(Struct, SerializedStruct.Get()); return true; } } } return false; } bool FValueOrBBKey_Vector::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot) { if (Tag.Type == NAME_VectorProperty) { Slot << DefaultValue; return true; } return false; } void FValueOrBBKey_Class::SetBaseClass(UClass* NewBaseClass) { if (NewBaseClass != BaseClass) { if (!BaseClass || !BaseClass->IsChildOf(NewBaseClass)) { Key = NAME_None; DefaultValue = nullptr; } BaseClass = NewBaseClass; } } void FValueOrBBKey_Enum::SetEnumType(UEnum* NewEnumType) { if (EnumType != NewEnumType) { Key = NAME_None; EnumType = NewEnumType; if (EnumType) { DefaultValue = static_cast(EnumType->GetValueByIndex(0)); } } } void FValueOrBBKey_Object::SetBaseClass(UClass* NewBaseClass) { if (NewBaseClass != BaseClass) { if (!BaseClass || !BaseClass->IsChildOf(NewBaseClass)) { Key = NAME_None; DefaultValue = nullptr; } BaseClass = NewBaseClass; } } void FValueOrBBKey_Struct::SetStructType(UScriptStruct* NewStructType) { if (NewStructType != DefaultValue.GetScriptStruct()) { DefaultValue.InitializeAs(NewStructType, nullptr); Key = NAME_None; } } #if WITH_EDITOR void FValueOrBlackboardKeyBase::PreSave(const UObject* Outer, const UBlackboardData& Blackboard, FName PropertyName) { if (!Key.IsNone()) { const FBlackboard::FKey Id = Blackboard.GetKeyID(Key); if (Id != FBlackboard::InvalidKey) { if (const FBlackboardEntry* BlackboardEntry = Blackboard.GetKey(Id)) { if (IsCompatibleType(BlackboardEntry->KeyType)) { return; } else { UE_LOG(LogBehaviorTree, Warning, TEXT("%s in node %s in bt %s is bound to key %s but the type doesn't match in blackboard %s. Resetting the key to none."), *PropertyName.ToString(), *GetNameSafe(Outer), Outer ? *GetNameSafe(Outer->GetTypedOuter()) : TEXT("None"), *Key.ToString(), *Blackboard.GetFullName()); } } else { UE_LOG(LogBehaviorTree, Warning, TEXT("%s in node %s in bt %s is bound to key %s but the key doesn't exist in blackboard %s. Resetting the key to none."), *PropertyName.ToString(), *GetNameSafe(Outer), Outer ? *GetNameSafe(Outer->GetTypedOuter()) : TEXT("None"), *Key.ToString(), *Blackboard.GetFullName()); } } else { UE_LOG(LogBehaviorTree, Warning, TEXT("%s in node %s in bt %s is bound to key %s but the key doesn't exist in blackboard %s. Resetting the key to none."), *PropertyName.ToString(), *GetNameSafe(Outer), Outer ? *GetNameSafe(Outer->GetTypedOuter()) : TEXT("None"), *Key.ToString(), *Blackboard.GetFullName()); } Key = NAME_None; } } bool FValueOrBBKey_Bool::IsCompatibleType(const UBlackboardKeyType* KeyType) const { return KeyType && KeyType->GetClass() == UBlackboardKeyType_Bool::StaticClass(); } bool FValueOrBBKey_Class::IsCompatibleType(const UBlackboardKeyType* KeyType) const { if (const UBlackboardKeyType_Class* ClassKey = Cast(KeyType)) { if (BaseClass && ClassKey->BaseClass) { return ClassKey->BaseClass->IsChildOf(BaseClass); } } return false; } bool FValueOrBBKey_Enum::IsCompatibleType(const UBlackboardKeyType* KeyType) const { if (const UBlackboardKeyType_Enum* EnumKey = Cast(KeyType)) { if (EnumType && EnumKey->EnumType) { return EnumKey->EnumType == EnumType; } } return false; } bool FValueOrBBKey_Float::IsCompatibleType(const UBlackboardKeyType* KeyType) const { return KeyType && KeyType->GetClass() == UBlackboardKeyType_Float::StaticClass(); } bool FValueOrBBKey_Int32::IsCompatibleType(const UBlackboardKeyType* KeyType) const { return KeyType && KeyType->GetClass() == UBlackboardKeyType_Int::StaticClass(); } bool FValueOrBBKey_Name::IsCompatibleType(const UBlackboardKeyType* KeyType) const { return KeyType && KeyType->GetClass() == UBlackboardKeyType_Name::StaticClass(); } bool FValueOrBBKey_String::IsCompatibleType(const UBlackboardKeyType* KeyType) const { return KeyType && KeyType->GetClass() == UBlackboardKeyType_String::StaticClass(); } bool FValueOrBBKey_Object::IsCompatibleType(const UBlackboardKeyType* KeyType) const { if (const UBlackboardKeyType_Object* ObjectKey = Cast(KeyType)) { if (BaseClass && ObjectKey->BaseClass) { return ObjectKey->BaseClass->IsChildOf(BaseClass); } } return false; } bool FValueOrBBKey_Rotator::IsCompatibleType(const UBlackboardKeyType* KeyType) const { return KeyType && KeyType->GetClass() == UBlackboardKeyType_Rotator::StaticClass(); } bool FValueOrBBKey_Struct::IsCompatibleType(const UBlackboardKeyType* KeyType) const { if (const UBlackboardKeyType_Struct* StructKey = Cast(KeyType)) { return StructKey->DefaultValue.GetScriptStruct() == DefaultValue.GetScriptStruct(); } return false; } bool FValueOrBBKey_Vector::IsCompatibleType(const UBlackboardKeyType* KeyType) const { return KeyType && KeyType->GetClass() == UBlackboardKeyType_Vector::StaticClass(); } #endif // WITH_EDITOR