Files
UnrealEngineUWP/Engine/Source/Editor/SubobjectDataInterface/Public/SubobjectData.h
ben hoffman 1eb5090127 Do not allow copying or duplicating subobjects with the name of "DefaultSceneRoot". This will prevent confusing renaming situations where the DefaultSceneRoot could be deleted, but still be preventing other subobjects from being named that
#jira UE-119104
#rb todo
#rnx
#preflight 60ff101a47c93a00010d9d2e

#ROBOMERGE-SOURCE: CL 16961027 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)

[CL 16961064 by ben hoffman in ue5-release-engine-test branch]
2021-07-26 16:58:12 -04:00

311 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Templates/SharedPointer.h"
#include "SubobjectDataHandle.h"
#include "Components/ActorComponent.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Engine/SCS_Node.h" // #TODO_BH We need to remove this when the actual subobject refactor happens
#include "SubobjectData.generated.h"
class UBlueprint;
/**
* A struct that represents a single subobject. This can be anything, but are
* most commonly components attached to an actor instance or blueprint. Keeps track
* of the handles to its parent object and any child that it has.
*
* If you wish to modify a subobject, use the SubobjectDataSubsystem.
*/
USTRUCT(BlueprintType)
struct SUBOBJECTDATAINTERFACE_API FSubobjectData
{
friend class USubobjectDataSubsystem;
public:
GENERATED_BODY()
FSubobjectData();
FSubobjectData(UObject* ContextObject, const FSubobjectDataHandle& ParentHandle);
virtual ~FSubobjectData();
/** True if this subobject's handle is valid */
bool IsValid() const { return Handle.IsValid(); }
/**
* @return Whether or not we can edit properties for this subobject
*/
virtual bool CanEdit() const;
/**
* @return Whether or not this object represents a subobject that can be deleted
*/
virtual bool CanDelete() const;
/**
* @return Whether or not this object represents a subobject that can be duplicated
*/
virtual bool CanDuplicate() const;
/**
* @return Whether or not this object represents a subobject that can be copied
*/
virtual bool CanCopy() const;
/**
* @return Whether or not this object represents a subobject that can
* be reparented to other subobjects based on its context.
*/
virtual bool CanReparent() const;
/**
* @return Whether or not this object represents a subobject that can
* be renamed.
*/
virtual bool CanRename() const;
/**
* @return A read-only reference to the object represented by this node.
*/
inline const UObject* GetObject(bool bEvenIfPendingKill = false) const { return WeakObjectPtr.Get(bEvenIfPendingKill); }
/**
* @param InBlueprint The Blueprint in which the object will be edited.
*
* @note May not be the same as the value returned by GetObject().
* @return A reference to the object represented by this node that can be modified within the given Blueprint.
*/
const UObject* GetObjectForBlueprint(UBlueprint* Blueprint) const;
template<class T>
inline const T* GetObjectForBlueprint(UBlueprint* Blueprint) const
{
return Cast<T>(GetObjectForBlueprint(Blueprint));
}
/**
* @param bEvenIfPendingKill If false, nullptr will be returned if the cached object instance is pending kill.
* If true, it will be returned regardless (this is used for recaching the object if the objects
* have been reinstanced following construction script execution).
*
* @note Deliberately non-virtual, for performance reasons.
* @return A read-only reference to the object represented by this node.
*/
template<class T>
inline const T* GetObject(bool bEvenIfPendingKill = false) const
{
return Cast<T>(WeakObjectPtr.Get(bEvenIfPendingKill));
}
/**
* @param bEvenIfPendingKill If false, nullptr will be returned if the cached component template is pending kill.
* If true, it will be returned regardless (this is used for recaching the component template if the objects
* have been reinstanced following construction script execution).
*
* @note Deliberately non-virtual, for performance reasons.
* @warning This will not return the right component for components overridden by the inherited component handler, you need to call GetOrCreateEditableComponentTemplate instead
* @return The component template or instance represented by this node, if it's a component node.
*/
inline const UActorComponent* GetComponentTemplate(bool bEvenIfPendingKill = false) const
{
return Cast<UActorComponent>(WeakObjectPtr.Get(bEvenIfPendingKill));
}
inline const UActorComponent* FindComponentInstanceInActor(const AActor* InActor) const { return FindMutableComponentInstanceInActor(InActor); }
UBlueprint* GetBlueprint() const;
virtual bool IsInstancedComponent() const;
virtual bool IsInstancedActor() const;
virtual bool IsNativeComponent() const;
virtual bool IsInheritedComponent() const;
virtual bool IsSceneComponent() const;
virtual bool IsRootComponent() const;
virtual bool IsDefaultSceneRoot() const;
/** Returns true if the component template's FName starts with USceneComponent::GetDefaultSceneRootVariableName */
bool SceneRootHasDefaultName() const;
/* Returns true if this subobject is a component. */
virtual bool IsComponent() const;
virtual bool IsChildActor() const;
/** Returns true if this subobject is a part of a child actor's hierarchy and not the root actor. */
virtual bool IsChildActorSubtreeObject() const;
virtual bool IsRootActor() const;
virtual bool IsActor() const;
/** True if this subobject is an instance of an inherited component (its owner is an instanced actor) */
virtual bool IsInstancedInheritedComponent() const;
bool IsAttachedTo(const FSubobjectDataHandle& InHandle) const;
virtual FString GetDisplayString(bool bShowNativeComponentNames = true) const;
/** Get the display name of this subobject that should be used during drag/drop operations */
FText GetDragDropDisplayText() const;
/**
* Returns a string that gives details about this subobject. For Inherited
* components it will return "(Inherited)". For native components
* this function will return "(NativeComponentName) (Inherited)"
*/
virtual FText GetDisplayNameContextModifiers(bool bShowNativeComponentNames = true) const;
virtual FText GetDisplayName() const;
virtual FName GetVariableName() const;
// Sockets for attaching in the viewport
FText GetSocketName() const;
FName GetSocketFName() const;
bool HasValidSocket() const;
void SetSocketName(FName InNewName);
void SetupAttachment(FName SocketName, const FSubobjectDataHandle& AttachParentHandle = FSubobjectDataHandle::InvalidHandle);
FSubobjectDataHandle GetHandle() const { return Handle; }
FSubobjectDataHandle GetParentHandle() const { return ParentObjectHandle; }
FSubobjectData* GetParentData() const { return ParentObjectHandle.GetData(); }
bool HasParent() const { return ParentObjectHandle.IsValid(); }
const TArray<FSubobjectDataHandle>& GetChildrenHandles() const { return ChildrenHandles; }
/** Walks the parent heirarchy and returns the root subobject in this case */
FSubobjectDataHandle GetRootSubobject() const;
// Return true if the given handle is a child of this subobject
bool HasChild(const FSubobjectDataHandle& ChildHandle) const;
// Attempt to find the given handle in out child array and return a pointer to it
FSubobjectDataHandle FindChild(const FSubobjectDataHandle& ChildHandle) const;
FSubobjectDataHandle FindChildByObject(UObject* ContextObject) const;
/** Get the asset name of this subobject from the asset brokerage */
FText GetAssetName() const;
/** Get the asset path of this subobject from the asset brokerage */
FText GetAssetPath() const;
/** Returns true if the asset this object represents is visible */
bool IsAssetVisible() const;
/**
* Retrieves tooltip text describing the specified component's mobility.
*
* @returns An FText object containing a description of the component's mobility
*/
FText GetMobilityToolTipText() const;
/**
* Retrieves a tooltip text describing if the component is marked Editor only or not
*
* @returns An FText object containing a description of if the component is marked Editor only or not
*/
FText GetComponentEditorOnlyTooltipText() const;
/**
* Retrieves tooltip text describing where the component was first introduced (for inherited components).
*
* @returns An FText object containing a description of when the component was first introduced
*/
FText GetIntroducedInToolTipText() const;
virtual FText GetActorDisplayText() const;
FLinearColor GetColorTintForIcon() const;
protected:
/**
* Add the given subobject handle as a child of this.
* NOTE: This does NOT do any actual manipulation of the subobject structure.
* This only updates this subobject to have the correct handles in it's child structure.
* Actual manipulation of subobjects should be done via the SubobjectSubsystem.
*/
bool AddChildHandleOnly(const FSubobjectDataHandle& InHandle);
/**
* Add the given subobject handle as a child of this.
* * NOTE: This does NOT do any actual manipulation of the subobject structure.
* This only updates this subobject to have the correct handles in it's child structure.
* Actual manipulation of subobjects should be done via the SubobjectSubsystem.
*/
bool RemoveChildHandleOnly(const FSubobjectDataHandle& InHandle);
void SetParentHandle(const FSubobjectDataHandle& NewParentHandle) { ParentObjectHandle = NewParentHandle; }
void ClearParentHandle() { ParentObjectHandle = FSubobjectDataHandle::InvalidHandle; }
// Weak ptr to the object instance represented by this node (e.g. component template)
UPROPERTY()
TWeakObjectPtr<UObject> WeakObjectPtr;
// Handle that will have a globally unique ID when it is constructed (i.e. when this is constructed)
UPROPERTY()
FSubobjectDataHandle Handle;
// Handle to this object's parent. If this is invalid, then it is the root subobject.
UPROPERTY()
FSubobjectDataHandle ParentObjectHandle;
// Set of child subobjects that use this subobject as a parent
UPROPERTY()
TArray<FSubobjectDataHandle> ChildrenHandles;
////////////////////////////////////////////
// Muteable accessors for this subobject to be used by the subsystem
inline UObject* GetMutableObject(bool bEvenIfPendingKill = false) const { return WeakObjectPtr.Get(bEvenIfPendingKill); }
// If this subobject is an actor, then return a pointer to that. Otherwise, search for
// the owning actor on this component and return it.
AActor* GetMutableActorContext();
template<class T>
inline T* GetMutableObject(bool bEvenIfPendingKill = false) const
{
return Cast<T>(WeakObjectPtr.Get(bEvenIfPendingKill));
}
template<class T>
inline T* GetMutableObjectForBlueprint(UBlueprint* Blueprint) const
{
return const_cast<T*>(GetObjectForBlueprint<T>(Blueprint));
}
inline UActorComponent* GetMutableComponentTemplate(bool bEvenIfPendingKill = false) const
{
return Cast<UActorComponent>(WeakObjectPtr.Get(bEvenIfPendingKill));
}
UActorComponent* FindMutableComponentInstanceInActor(const AActor* InActor) const;
////////////////////////////////////////////////////
// Anything related to an SCS node will be changed with an upcoming refactor and should remain private
protected:
// Tries to find a SCS node that was likely responsible for creating the specified instance component. Note: This is not always possible to do!
static USCS_Node* FindSCSNodeForInstance(const UActorComponent* InstanceComponent, UClass* ClassToSearch);
virtual USCS_Node* GetSCSNode(bool bEvenIfPendingKill = false) const;
/**
* Attempts to set the SCS node member variable based on the WeakObjectPtr.
* If the weak obj ptr _is_ an USCS_Node type, then we have to change the component
* template.
*
* If this is an instanced component, then we can find the scs node via FindSCSNodeForInstance.
*
* @return True if an SCS node has been set
*/
bool AttemptToSetSCSNode();
// For now, we need a pointer to the SCS node in order to have the correct component template
// and to be able to get the UBlueprint* from components. This will only be set upon construction
// if the given Object Context is an USCS_Node. The context object will be set to its template.
TWeakObjectPtr<USCS_Node> SCSNodePtr;
/**
* True if this SCS node's blueprint is a child of another Blueprint-generated class,
* which means that we must use the InheritableComponentHandler
*/
virtual bool IsInheritedSCSNode() const;
};