You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Fixed hashing when adding shared fragment for smart object slot definition - Added per slot Runtime Tags - Added common event handling for Smart Object and Slot changes and events - Added annotations, which are slot definition data that has visualization - Added linked slot annotation which allows behavior reuse on slots - Added editor only ID for each slot so that they can be identified during edits - Added SmartObject slot reference type that can be used to reference other slots in the Smart Object - Changed Smart Object bDisable to bEnabled - Added separate enabled state for slots - Changed Smart Object disable to send an event, not forcefully unclaim - Added more visualization support for Smart Object editor (canvas, visualize annotations) - Changed Smart Object editor to use the commonly transform for slots - Remove Smart Object Component instance from the asset editor as it was not needed #rb Stephen.Holmes #preflight 6360f0cf63608aee36e01ba5 [CL 22888712 by mikko mononen in ue5-main branch]
245 lines
7.3 KiB
C++
245 lines
7.3 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SmartObjectDefinition.h"
|
|
#include "SmartObjectSettings.h"
|
|
#include "SmartObjectTypes.h"
|
|
#if WITH_EDITOR
|
|
#include "UObject/ObjectSaveContext.h"
|
|
#endif
|
|
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(SmartObjectDefinition)
|
|
|
|
namespace UE::SmartObject
|
|
{
|
|
const FVector DefaultSlotSize(40, 40, 90);
|
|
}
|
|
|
|
USmartObjectDefinition::USmartObjectDefinition(const FObjectInitializer& ObjectInitializer): UDataAsset(ObjectInitializer)
|
|
{
|
|
UserTagsFilteringPolicy = GetDefault<USmartObjectSettings>()->DefaultUserTagsFilteringPolicy;
|
|
ActivityTagsMergingPolicy = GetDefault<USmartObjectSettings>()->DefaultActivityTagsMergingPolicy;
|
|
}
|
|
|
|
bool USmartObjectDefinition::Validate() const
|
|
{
|
|
bValid = false;
|
|
if (Slots.Num() == 0)
|
|
{
|
|
UE_LOG(LogSmartObject, Error, TEXT("Need to provide at least one slot definition"));
|
|
return false;
|
|
}
|
|
|
|
// Detect null entries in default definitions
|
|
int32 NullEntryIndex;
|
|
if (DefaultBehaviorDefinitions.Find(nullptr, NullEntryIndex))
|
|
{
|
|
UE_LOG(LogSmartObject, Error, TEXT("Null entry found at index %d in default behavior definition list"), NullEntryIndex);
|
|
return false;
|
|
}
|
|
|
|
// Detect null entries in slot definitions
|
|
for (int i = 0; i < Slots.Num(); ++i)
|
|
{
|
|
const FSmartObjectSlotDefinition& Slot = Slots[i];
|
|
if (Slot.BehaviorDefinitions.Find(nullptr, NullEntryIndex))
|
|
{
|
|
UE_LOG(LogSmartObject, Error, TEXT("Null definition entry found at index %d in behavior list of slot %d"), i, NullEntryIndex);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Detect missing definitions in slots if no default one are provided
|
|
if (DefaultBehaviorDefinitions.Num() == 0)
|
|
{
|
|
for (int i = 0; i < Slots.Num(); ++i)
|
|
{
|
|
const FSmartObjectSlotDefinition& Slot = Slots[i];
|
|
if (Slot.BehaviorDefinitions.Num() == 0)
|
|
{
|
|
UE_LOG(LogSmartObject, Error, TEXT("Slot at index %d needs to provide a behavior definition since there is no default one in the SmartObject definition"), i);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bValid = true;
|
|
return true;
|
|
}
|
|
|
|
FBox USmartObjectDefinition::GetBounds() const
|
|
{
|
|
FBox BoundingBox(ForceInitToZero);
|
|
for (const FSmartObjectSlotDefinition& Slot : GetSlots())
|
|
{
|
|
BoundingBox += Slot.Offset + UE::SmartObject::DefaultSlotSize;
|
|
BoundingBox += Slot.Offset - UE::SmartObject::DefaultSlotSize;
|
|
}
|
|
return BoundingBox;
|
|
}
|
|
|
|
void USmartObjectDefinition::GetSlotActivityTags(const FSmartObjectSlotIndex& SlotIndex, FGameplayTagContainer& OutActivityTags) const
|
|
{
|
|
if (ensureMsgf(Slots.IsValidIndex(SlotIndex), TEXT("Requesting activity tags for an out of range slot index: %s"), *LexToString(SlotIndex)))
|
|
{
|
|
GetSlotActivityTags(Slots[SlotIndex], OutActivityTags);
|
|
}
|
|
}
|
|
|
|
void USmartObjectDefinition::GetSlotActivityTags(const FSmartObjectSlotDefinition& SlotDefinition, FGameplayTagContainer& OutActivityTags) const
|
|
{
|
|
OutActivityTags = ActivityTags;
|
|
|
|
if (ActivityTagsMergingPolicy == ESmartObjectTagMergingPolicy::Combine)
|
|
{
|
|
OutActivityTags.AppendTags(SlotDefinition.ActivityTags);
|
|
}
|
|
else if (ActivityTagsMergingPolicy == ESmartObjectTagMergingPolicy::Override && !SlotDefinition.ActivityTags.IsEmpty())
|
|
{
|
|
OutActivityTags = SlotDefinition.ActivityTags;
|
|
}
|
|
}
|
|
|
|
TOptional<FTransform> USmartObjectDefinition::GetSlotTransform(const FTransform& OwnerTransform, const FSmartObjectSlotIndex SlotIndex) const
|
|
{
|
|
TOptional<FTransform> Transform;
|
|
|
|
if (ensureMsgf(Slots.IsValidIndex(SlotIndex), TEXT("Requesting slot transform for an out of range index: %s"), *LexToString(SlotIndex)))
|
|
{
|
|
const FSmartObjectSlotDefinition& Slot = Slots[SlotIndex];
|
|
Transform = FTransform(Slot.Rotation, Slot.Offset) * OwnerTransform;
|
|
}
|
|
|
|
return Transform;
|
|
}
|
|
|
|
|
|
const USmartObjectBehaviorDefinition* USmartObjectDefinition::GetBehaviorDefinition(const FSmartObjectSlotIndex& SlotIndex,
|
|
const TSubclassOf<USmartObjectBehaviorDefinition>& DefinitionClass) const
|
|
{
|
|
const USmartObjectBehaviorDefinition* Definition = nullptr;
|
|
if (Slots.IsValidIndex(SlotIndex))
|
|
{
|
|
Definition = GetBehaviorDefinitionByType(Slots[SlotIndex].BehaviorDefinitions, DefinitionClass);
|
|
}
|
|
|
|
if (Definition == nullptr)
|
|
{
|
|
Definition = GetBehaviorDefinitionByType(DefaultBehaviorDefinitions, DefinitionClass);
|
|
}
|
|
|
|
return Definition;
|
|
}
|
|
|
|
|
|
const USmartObjectBehaviorDefinition* USmartObjectDefinition::GetBehaviorDefinitionByType(const TArray<USmartObjectBehaviorDefinition*>& BehaviorDefinitions,
|
|
const TSubclassOf<USmartObjectBehaviorDefinition>& DefinitionClass)
|
|
{
|
|
USmartObjectBehaviorDefinition* const* BehaviorDefinition = BehaviorDefinitions.FindByPredicate([&DefinitionClass](USmartObjectBehaviorDefinition* SlotBehaviorDefinition)
|
|
{
|
|
return SlotBehaviorDefinition != nullptr && SlotBehaviorDefinition->GetClass()->IsChildOf(*DefinitionClass);
|
|
});
|
|
|
|
return BehaviorDefinition != nullptr ? *BehaviorDefinition : nullptr;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
int32 USmartObjectDefinition::FindSlotByID(const FGuid ID) const
|
|
{
|
|
const int32 Slot = Slots.IndexOfByPredicate([&ID](const FSmartObjectSlotDefinition& Slot) { return Slot.ID == ID; });
|
|
return Slot;
|
|
}
|
|
|
|
void USmartObjectDefinition::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
|
|
{
|
|
Super::PostEditChangeChainProperty(PropertyChangedEvent);
|
|
|
|
const FProperty* Property = PropertyChangedEvent.Property;
|
|
if (Property == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
const FProperty* MemberProperty = nullptr;
|
|
if (PropertyChangedEvent.PropertyChain.GetActiveMemberNode())
|
|
{
|
|
MemberProperty = PropertyChangedEvent.PropertyChain.GetActiveMemberNode()->GetValue();
|
|
}
|
|
if (MemberProperty == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Ensure unique Slot ID on added or duplicated items.
|
|
if (PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayAdd
|
|
|| PropertyChangedEvent.ChangeType == EPropertyChangeType::Duplicate)
|
|
{
|
|
if (Property->GetFName() == GET_MEMBER_NAME_CHECKED(USmartObjectDefinition, Slots))
|
|
{
|
|
const int32 ArrayIndex = PropertyChangedEvent.GetArrayIndex(MemberProperty->GetFName().ToString());
|
|
if (Slots.IsValidIndex(ArrayIndex))
|
|
{
|
|
FSmartObjectSlotDefinition& Slot = Slots[ArrayIndex];
|
|
Slot.ID = FGuid::NewGuid();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Anything in the slots changed, update references.
|
|
if (MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(USmartObjectDefinition, Slots))
|
|
{
|
|
UpdateSlotReferences();
|
|
}
|
|
}
|
|
|
|
void USmartObjectDefinition::PostLoad()
|
|
{
|
|
Super::PostLoad();
|
|
|
|
// Fill in missing slot ID for old data.
|
|
for (FSmartObjectSlotDefinition& Slot : Slots)
|
|
{
|
|
if (!Slot.ID.IsValid())
|
|
{
|
|
Slot.ID = FGuid::NewGuid();
|
|
}
|
|
}
|
|
|
|
UpdateSlotReferences();
|
|
}
|
|
|
|
void USmartObjectDefinition::PreSave(FObjectPreSaveContext SaveContext)
|
|
{
|
|
UpdateSlotReferences();
|
|
Super::PreSave(SaveContext);
|
|
}
|
|
|
|
void USmartObjectDefinition::UpdateSlotReferences()
|
|
{
|
|
for (FSmartObjectSlotDefinition& Slot : Slots)
|
|
{
|
|
for (FInstancedStruct& Data : Slot.Data)
|
|
{
|
|
if (!Data.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
const UScriptStruct* ScriptStruct = Data.GetScriptStruct();
|
|
uint8* Memory = Data.GetMutableMemory();
|
|
|
|
for (TFieldIterator<FProperty> It(ScriptStruct); It; ++It)
|
|
{
|
|
if (FStructProperty* StructProp = CastField<FStructProperty>(*It))
|
|
{
|
|
if (StructProp->Struct == TBaseStructure<FSmartObjectSlotReference>::Get())
|
|
{
|
|
FSmartObjectSlotReference& Ref = *StructProp->ContainerPtrToValuePtr<FSmartObjectSlotReference>(Memory);
|
|
const int32 Index = FindSlotByID(Ref.GetSlotID());
|
|
Ref.SetIndex(Index);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // WITH_EDITOR
|