2021-09-28 13:33:00 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# pragma once
2022-01-19 14:16:16 -05:00
# include "MassEntityTypes.h"
# include "MassEntityView.h"
2021-09-28 13:33:00 -04:00
# include "Delegates/DelegateCombinations.h"
# include "SmartObjectTypes.h"
2021-11-26 15:48:13 -05:00
# include "SmartObjectDefinition.h"
2021-09-28 13:33:00 -04:00
# include "SmartObjectRuntime.generated.h"
2022-03-16 03:47:02 -04:00
/** Delegate fired when a given tag is added or removed. Tags on smart object are not using reference counting so count will be 0 or 1 */
DECLARE_DELEGATE_TwoParams ( FOnSmartObjectTagChanged , const FGameplayTag , int32 ) ;
2021-09-28 13:33:00 -04:00
/**
* Enumeration to represent the runtime state of a slot
*/
UENUM ( )
enum class ESmartObjectSlotState : uint8
{
2022-01-19 14:16:16 -05:00
Invalid ,
2022-03-16 03:47:02 -04:00
/** Slot is available */
2021-09-28 13:33:00 -04:00
Free ,
2022-03-16 03:47:02 -04:00
/** Slot is claimed but interaction is not active yet */
2021-09-28 13:33:00 -04:00
Claimed ,
2022-03-16 03:47:02 -04:00
/** Slot is claimed and interaction is active */
Occupied ,
/** Slot can no longer be claimed or used since the parent object and its slot are disabled (e.g. instance tags) */
Disabled
2021-09-28 13:33:00 -04:00
} ;
/**
* Struct describing a reservation between a user and a smart object slot .
*/
2021-11-26 15:48:13 -05:00
USTRUCT ( BlueprintType )
2021-09-28 13:33:00 -04:00
struct SMARTOBJECTSMODULE_API FSmartObjectClaimHandle
{
GENERATED_BODY ( )
2022-01-19 14:16:16 -05:00
FSmartObjectClaimHandle ( const FSmartObjectHandle InSmartObjectHandle , const FSmartObjectSlotHandle InSlotHandle , const FSmartObjectUserHandle & InUser )
: SmartObjectHandle ( InSmartObjectHandle ) , SlotHandle ( InSlotHandle ) , UserHandle ( InUser )
2021-09-28 13:33:00 -04:00
{ }
FSmartObjectClaimHandle ( )
{ }
bool operator = = ( const FSmartObjectClaimHandle & Other ) const
{
2022-03-18 12:31:49 -04:00
return SmartObjectHandle = = Other . SmartObjectHandle
2022-01-19 14:16:16 -05:00
& & SlotHandle = = Other . SlotHandle
& & UserHandle = = Other . UserHandle ;
2021-09-28 13:33:00 -04:00
}
2021-11-26 15:48:13 -05:00
bool operator ! = ( const FSmartObjectClaimHandle & Other ) const
{
return ! ( * this = = Other ) ;
}
2022-01-19 14:16:16 -05:00
friend FString LexToString ( const FSmartObjectClaimHandle & Handle )
2021-09-28 13:33:00 -04:00
{
2022-01-19 14:16:16 -05:00
return FString : : Printf ( TEXT ( " Object:%s Slot:%s User:%s " ) , * LexToString ( Handle . SmartObjectHandle ) , * LexToString ( Handle . SlotHandle ) , * LexToString ( Handle . UserHandle ) ) ;
2021-09-28 13:33:00 -04:00
}
void Invalidate ( ) { * this = InvalidHandle ; }
2022-03-16 03:47:02 -04:00
/**
2022-03-18 12:31:49 -04:00
* Indicates that the handle was properly assigned by a call to ' Claim ' but doesn ' t guarantee that the associated
* object and slot are still registered in the simulation .
* This information requires a call to ` USmartObjectSubsystem : : IsClaimedObjectValid ` using the handle .
2022-03-16 03:47:02 -04:00
*/
2021-09-28 13:33:00 -04:00
bool IsValid ( ) const
{
2022-01-19 14:16:16 -05:00
return SmartObjectHandle . IsValid ( )
& & SlotHandle . IsValid ( )
& & UserHandle . IsValid ( ) ;
2021-09-28 13:33:00 -04:00
}
static const FSmartObjectClaimHandle InvalidHandle ;
UPROPERTY ( Transient )
2022-01-19 14:16:16 -05:00
FSmartObjectHandle SmartObjectHandle ;
2021-09-28 13:33:00 -04:00
UPROPERTY ( Transient )
2022-01-19 14:16:16 -05:00
FSmartObjectSlotHandle SlotHandle ;
2021-09-28 13:33:00 -04:00
2022-01-19 14:16:16 -05:00
UPROPERTY ( Transient )
FSmartObjectUserHandle UserHandle ;
} ;
/**
* Runtime data holding the final slot transform ( i . e . parent transform applied on slot local offset and rotation )
*/
USTRUCT ( )
struct SMARTOBJECTSMODULE_API FSmartObjectSlotTransform : public FSmartObjectSlotStateData
{
GENERATED_BODY ( )
const FTransform & GetTransform ( ) const { return Transform ; }
FTransform & GetMutableTransform ( ) { return Transform ; }
void SetTransform ( const FTransform & InTransform ) { Transform = InTransform ; }
protected :
UPROPERTY ( Transient )
FTransform Transform ;
2021-09-28 13:33:00 -04:00
} ;
/** Delegate to notify when a given slot gets invalidated and the interaction must be aborted */
DECLARE_DELEGATE_TwoParams ( FOnSlotInvalidated , const FSmartObjectClaimHandle & , ESmartObjectSlotState /* Current State */ ) ;
/**
2021-11-26 15:48:13 -05:00
* Struct to store and manage state of a runtime instance associated to a given slot definition
2021-09-28 13:33:00 -04:00
*/
USTRUCT ( )
2022-01-19 14:16:16 -05:00
struct FSmartObjectSlotClaimState
2021-09-28 13:33:00 -04:00
{
GENERATED_BODY ( )
public :
2022-01-19 14:16:16 -05:00
/* Provide default constructor to be able to compile template instantiation 'UScriptStruct::TCppStructOps<FSmartObjectSlotState>' */
/* Also public to pass void 'UScriptStruct::TCppStructOps<FSmartObjectSlotState>::ConstructForTests(void *)' */
FSmartObjectSlotClaimState ( ) { }
2021-09-28 13:33:00 -04:00
2021-11-29 11:34:31 -05:00
ESmartObjectSlotState GetState ( ) const { return State ; }
2021-09-28 13:33:00 -04:00
protected :
/** Struct could have been nested inside the subsystem but not possible with USTRUCT */
friend class USmartObjectSubsystem ;
friend struct FSmartObjectRuntime ;
2022-01-19 14:16:16 -05:00
bool Claim ( const FSmartObjectUserHandle & InUser ) ;
2022-03-16 03:47:02 -04:00
bool Release ( const FSmartObjectClaimHandle & ClaimHandle , const ESmartObjectSlotState NewState , const bool bAborted ) ;
2021-09-28 13:33:00 -04:00
2022-01-19 14:16:16 -05:00
friend FString LexToString ( const FSmartObjectSlotClaimState & ClaimState )
{
return FString : : Printf ( TEXT ( " User:%s State:%s " ) , * LexToString ( ClaimState . User ) , * UEnum : : GetValueAsString ( ClaimState . State ) ) ;
}
2021-09-28 13:33:00 -04:00
2022-01-19 14:16:16 -05:00
/** Handle to the user that reserves or uses the slot */
FSmartObjectUserHandle User ;
2021-09-28 13:33:00 -04:00
/** Delegate used to notify when a slot gets invalidated. See RegisterSlotInvalidationCallback */
FOnSlotInvalidated OnSlotInvalidatedDelegate ;
2022-01-19 14:16:16 -05:00
/** Current availability state of the slot */
ESmartObjectSlotState State = ESmartObjectSlotState : : Free ;
2021-09-28 13:33:00 -04:00
} ;
/**
2021-11-26 15:48:13 -05:00
* Struct to store and manage state of a runtime instance associated to a given smart object definition
2021-09-28 13:33:00 -04:00
*/
USTRUCT ( )
struct FSmartObjectRuntime
{
GENERATED_BODY ( )
public :
2022-03-17 19:07:54 -04:00
FSmartObjectHandle GetRegisteredHandle ( ) const { return RegisteredHandle ; }
2021-09-28 13:33:00 -04:00
const FTransform & GetTransform ( ) const { return Transform ; }
2021-11-26 15:48:13 -05:00
const USmartObjectDefinition & GetDefinition ( ) const { checkf ( Definition ! = nullptr , TEXT ( " Initialized from a valid reference from the constructor " ) ) ; return * Definition ; }
2022-03-16 03:47:02 -04:00
/** Returns all tags assigned to the smart object instance */
2022-03-02 13:25:37 -05:00
const FGameplayTagContainer & GetTags ( ) const { return Tags ; }
2021-09-28 13:33:00 -04:00
2022-03-16 03:47:02 -04:00
/** Returns delegate that is invoked whenever a tag is added or removed */
FOnSmartObjectTagChanged & GetTagChangedDelegate ( ) { return OnTagChangedDelegate ; }
/** Indicates that this instance is still part of the simulation (space partition) but should not be considered valid by queries */
uint32 IsDisabled ( ) const { return bDisabledByTags ; }
2021-09-28 13:33:00 -04:00
/* Provide default constructor to be able to compile template instantiation 'UScriptStruct::TCppStructOps<FSmartObjectRuntime>' */
/* Also public to pass void 'UScriptStruct::TCppStructOps<FSmartObjectRuntime>::ConstructForTests(void *)' */
2022-02-21 01:10:34 -05:00
FSmartObjectRuntime ( ) { }
2021-09-28 13:33:00 -04:00
private :
/** Struct could have been nested inside the subsystem but not possible with USTRUCT */
friend class USmartObjectSubsystem ;
2021-11-26 15:48:13 -05:00
explicit FSmartObjectRuntime ( const USmartObjectDefinition & Definition ) ;
2021-09-28 13:33:00 -04:00
void SetTransform ( const FTransform & Value ) { Transform = Value ; }
2022-03-02 13:25:37 -05:00
void SetRegisteredHandle ( const FSmartObjectHandle Value ) { RegisteredHandle = Value ; }
2021-09-28 13:33:00 -04:00
2022-01-19 14:16:16 -05:00
/** Runtime SlotHandles associated to each defined slot */
TArray < FSmartObjectSlotHandle > SlotHandles ;
2021-09-28 13:33:00 -04:00
2021-11-26 15:48:13 -05:00
/** Associated smart object definition */
UPROPERTY ( )
const USmartObjectDefinition * Definition = nullptr ;
2021-09-28 13:33:00 -04:00
/** Instance specific transform */
FTransform Transform ;
/** Tags applied to the current instance */
FGameplayTagContainer Tags ;
2022-03-16 03:47:02 -04:00
/** Delegate fired whenever a new tag is added or an existing one gets removed */
FOnSmartObjectTagChanged OnTagChangedDelegate ;
2022-01-19 14:16:16 -05:00
/** RegisteredHandle != FSmartObjectHandle::Invalid when registered with SmartObjectSubsystem */
FSmartObjectHandle RegisteredHandle ;
2021-09-28 13:33:00 -04:00
2022-02-21 01:10:34 -05:00
/** Spatial representation data associated to the current instance */
2022-05-22 10:30:02 -04:00
UPROPERTY ( EditDefaultsOnly , Category = " SmartObject " , meta = ( BaseStruct = " /Script/SmartObjectsModule.SmartObjectSpatialEntryData " , ExcludeBaseStruct ) )
2022-02-21 01:10:34 -05:00
FInstancedStruct SpatialEntryData ;
# if UE_ENABLE_DEBUG_DRAWING
FBox Bounds = FBox ( EForceInit : : ForceInit ) ;
# endif
2022-03-16 03:47:02 -04:00
/** Each slot has its own disable state but keeping it also in the parent instance allow faster validation in some cases. */
bool bDisabledByTags = false ;
2021-09-28 13:33:00 -04:00
} ;
2022-01-19 14:16:16 -05:00
USTRUCT ( )
struct SMARTOBJECTSMODULE_API FSmartObjectSlotView
{
GENERATED_BODY ( )
public :
FSmartObjectSlotView ( ) = default ;
2022-03-16 03:47:02 -04:00
bool IsValid ( ) const { return EntityView . IsSet ( ) ; }
2022-01-19 14:16:16 -05:00
FSmartObjectSlotHandle GetSlotHandle ( ) const { return EntityView . GetEntity ( ) ; }
/**
* Returns a reference to the slot state data of the specified type .
* Method will fail a check if the slot doesn ' t have the given type .
*/
template < typename T >
T & GetStateData ( ) const
{
static_assert ( TIsDerivedFrom < T , FSmartObjectSlotStateData > : : IsDerived ,
" Given struct doesn't represent a valid runtime data type. Make sure to inherit from FSmartObjectSlotStateData or one of its child-types. " ) ;
return EntityView . GetFragmentData < T > ( ) ;
}
/**
* Returns a pointer to the slot state data of the specified type .
* Method will return null if the slot doesn ' t have the given type .
*/
template < typename T >
T * GetStateDataPtr ( ) const
{
static_assert ( TIsDerivedFrom < T , FSmartObjectSlotStateData > : : IsDerived ,
" Given struct doesn't represent a valid runtime data type. Make sure to inherit from FSmartObjectSlotStateData or one of its child-types. " ) ;
return EntityView . GetFragmentDataPtr < T > ( ) ;
}
2022-02-17 03:40:43 -05:00
/**
* Returns a reference to the definition of the slot ' s parent object .
* Method will fail a check if called on an invalid SlotView .
* @ note The definition fragment is always created and assigned when creating an entity associated to a slot
* so a valid SlotView is guaranteed to be able to provide it .
*/
const USmartObjectDefinition & GetSmartObjectDefinition ( ) const
{
checkf ( EntityView . IsSet ( ) , TEXT ( " Definition can only be accessed through a valid SlotView " ) ) ;
return * ( EntityView . GetConstSharedFragmentData < FSmartObjectSlotDefinitionFragment > ( ) . SmartObjectDefinition ) ;
}
2022-01-19 14:16:16 -05:00
/**
* Returns a reference to the main definition of the slot .
* Method will fail a check if called on an invalid SlotView .
*/
const FSmartObjectSlotDefinition & GetDefinition ( ) const
{
checkf ( EntityView . IsSet ( ) , TEXT ( " Definition can only be accessed through a valid SlotView " ) ) ;
return * ( EntityView . GetConstSharedFragmentData < FSmartObjectSlotDefinitionFragment > ( ) . SlotDefinition ) ;
}
2022-03-02 22:33:53 -05:00
/**
* Fills the provided GameplayTagContainer with the activity tags associated to the slot according to the tag filtering policy .
* Method will fail a check if called on an invalid SlotView .
*/
void GetActivityTags ( FGameplayTagContainer & OutActivityTags ) const
{
checkf ( EntityView . IsSet ( ) , TEXT ( " Definition can only be accessed through a valid SlotView " ) ) ;
const FSmartObjectSlotDefinitionFragment & DefinitionFragment = EntityView . GetConstSharedFragmentData < FSmartObjectSlotDefinitionFragment > ( ) ;
checkf ( DefinitionFragment . SmartObjectDefinition ! = nullptr , TEXT ( " SmartObjectDefinition should always be valid in a valid SlotView " ) ) ;
checkf ( DefinitionFragment . SlotDefinition ! = nullptr , TEXT ( " SlotDefinition should always be valid in a valid SlotView " ) ) ;
DefinitionFragment . SmartObjectDefinition - > GetSlotActivityTags ( * DefinitionFragment . SlotDefinition , OutActivityTags ) ;
}
2022-01-19 14:16:16 -05:00
/**
* Returns a reference to the definition data of the specified type from the main slot definition .
* Method will fail a check if the slot definition doesn ' t contain the given type .
*/
template < typename T >
const T & GetDefinitionData ( ) const
{
static_assert ( TIsDerivedFrom < T , FSmartObjectSlotDefinitionData > : : IsDerived ,
" Given struct doesn't represent a valid definition data type. Make sure to inherit from FSmartObjectSlotDefinitionData or one of its child-types. " ) ;
const FSmartObjectSlotDefinition & SlotDefinition = GetDefinition ( ) ;
for ( const FInstancedStruct & Data : SlotDefinition . Data )
{
if ( Data . GetScriptStruct ( ) - > IsChildOf ( T : : StaticStruct ( ) ) )
{
return Data . Get < T > ( ) ;
}
}
return nullptr ;
}
/**
* Returns a pointer to the definition data of the specified type from the main slot definition .
* Method will return null if the slot doesn ' t contain the given type .
*/
template < typename T >
const T * GetDefinitionDataPtr ( ) const
{
static_assert ( TIsDerivedFrom < T , FSmartObjectSlotDefinitionData > : : IsDerived ,
" Given struct doesn't represent a valid definition data type. Make sure to inherit from FSmartObjectSlotDefinitionData or one of its child-types. " ) ;
const FSmartObjectSlotDefinition & SlotDefinition = GetDefinition ( ) ;
for ( const FInstancedStruct & Data : SlotDefinition . Data )
{
if ( Data . GetScriptStruct ( ) - > IsChildOf ( T : : StaticStruct ( ) ) )
{
return Data . GetPtr < T > ( ) ;
}
}
return nullptr ;
}
private :
friend class USmartObjectSubsystem ;
FSmartObjectSlotView ( const UMassEntitySubsystem & EntitySubsystem , const FSmartObjectSlotHandle SlotHandle ) : EntityView ( EntitySubsystem , SlotHandle . EntityHandle )
{
}
FMassEntityView EntityView ;
} ;