2021-09-28 13:33:17 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "SmartObjectRuntime.h"
2023-01-18 10:52:51 -05:00
# include "SmartObjectComponent.h"
2022-01-19 14:16:16 -05:00
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(SmartObjectRuntime)
2021-09-28 13:33:17 -04:00
const FSmartObjectClaimHandle FSmartObjectClaimHandle : : InvalidHandle = { } ;
2023-11-29 11:23:11 -05:00
namespace UE : : SmartObject
{
TArray < FGameplayTag > GEnabledReasonTags ;
uint16 GetMaskForEnabledReasonTag ( const FGameplayTag Tag )
{
int32 Index = GEnabledReasonTags . IndexOfByKey ( Tag ) ;
if ( Index = = INDEX_NONE )
{
checkf ( GEnabledReasonTags . Num ( ) < = FSmartObjectRuntime : : MaxNumDisableFlags ,
TEXT ( " Too many different Tags were used to control smart object enabled state. You need to limit to %d or change to a larger type for DisableFlags in FSmartObjectRuntime. " ) ,
FSmartObjectRuntime : : MaxNumDisableFlags ) ;
Index = GEnabledReasonTags . Add ( Tag ) ;
}
return ( uint16 ) 1 < < Index ;
}
}
2021-09-28 13:33:17 -04:00
//----------------------------------------------------------------------//
// FSmartObjectRuntime
//----------------------------------------------------------------------//
2021-11-26 09:52:13 -05:00
FSmartObjectRuntime : : FSmartObjectRuntime ( const USmartObjectDefinition & InDefinition )
: Definition ( & InDefinition )
2021-09-28 13:33:17 -04:00
{
}
2023-11-29 11:23:11 -05:00
bool FSmartObjectRuntime : : IsEnabledForReason ( const FGameplayTag ReasonTag ) const
{
if ( ensureMsgf ( ReasonTag . IsValid ( ) , TEXT ( " %hs expects a valid tag. If the intent is to test the enabled state regardless of the reason use IsEnabled() instead. " ) , __FUNCTION__ ) )
{
const uint16 TagMask = UE : : SmartObject : : GetMaskForEnabledReasonTag ( ReasonTag ) ;
return ( DisableFlags & TagMask ) = = 0 ;
}
return DisableFlags = = 0 ;
}
void FSmartObjectRuntime : : SetEnabled ( const bool bEnabled , const uint16 ReasonMask )
{
if ( bEnabled )
{
// Enabling so removing the flag
DisableFlags & = ~ ReasonMask ;
}
else
{
// Disabling so adding the flag
DisableFlags | = ReasonMask ;
}
}
void FSmartObjectRuntime : : SetEnabled ( const FGameplayTag ReasonTag , const bool bEnabled )
{
if ( ensureMsgf ( ReasonTag . IsValid ( ) , TEXT ( " %hs expects a valid tag. " ) , __FUNCTION__ ) )
{
const uint16 ReasonMask = UE : : SmartObject : : GetMaskForEnabledReasonTag ( ReasonTag ) ;
SetEnabled ( bEnabled , ReasonMask ) ;
}
}
2024-02-08 13:21:26 -05:00
bool FSmartObjectRuntime : : ResolveOwnerActor ( ) const
2023-01-18 10:52:51 -05:00
{
2024-02-08 13:21:26 -05:00
if ( OwnerComponent . IsExplicitlyNull ( ) )
{
if ( const FSmartObjectActorOwnerData * ActorOwnerData = OwnerData . GetPtr < const FSmartObjectActorOwnerData > ( ) )
{
// Fetching the actor from the handle will either return the cached actor if already available
// or will try to create one synchronously.
// This actor is then expected to own a SmartObjectComponent that will register itself to the subsystem.
// On successful registration the subsystem will update the OwnerComponent of the current runtime object.
if ( ActorOwnerData - > Handle . FetchActor ( ) ! = nullptr )
{
ensureMsgf ( ! OwnerComponent . IsExplicitlyNull ( ) , TEXT ( " Successfully resolved actor is expected to register its smartobject component for '%s'. " ) , * LexToString ( GetRegisteredHandle ( ) ) ) ;
return true ;
}
}
// Unable to find owner data or to fetch actor from the Actor instance handle
return false ;
}
// Success since it was already resolved
return true ;
}
AActor * FSmartObjectRuntime : : GetOwnerActor ( const ETrySpawnActorIfDehydrated TrySpawnActorIfDehydrated ) const
{
const USmartObjectComponent * Component = GetOwnerComponent ( TrySpawnActorIfDehydrated ) ;
2023-01-18 10:52:51 -05:00
return Component ! = nullptr ? Component - > GetOwner ( ) : nullptr ;
}
2024-02-08 13:21:26 -05:00
USmartObjectComponent * FSmartObjectRuntime : : GetOwnerComponent ( const ETrySpawnActorIfDehydrated TrySpawnActorIfDehydrated ) const
2024-01-30 10:11:23 -05:00
{
2024-02-08 13:21:26 -05:00
if ( TrySpawnActorIfDehydrated = = ETrySpawnActorIfDehydrated : : Yes )
{
ResolveOwnerActor ( ) ;
}
2024-01-30 10:11:23 -05:00
return OwnerComponent . Get ( ) ;
}
2023-11-29 11:23:11 -05:00
# if WITH_SMARTOBJECT_DEBUG
FString FSmartObjectRuntime : : DebugGetDisableFlagsString ( ) const
{
FStringBuilderBase DisableFlagsStringBuilder ;
for ( int TagIndex = 0 ; TagIndex < MaxNumDisableFlags ; + + TagIndex )
{
const uint16 TagMask = ( uint16 ) 1 < < TagIndex ;
if ( ! ! ( DisableFlags & TagMask ) )
{
check ( UE : : SmartObject : : GEnabledReasonTags . IsValidIndex ( TagIndex ) ) ;
DisableFlagsStringBuilder + = DisableFlagsStringBuilder . Len ( ) ? TEXT ( " , " ) : TEXT ( " Disabled by: " ) ;
DisableFlagsStringBuilder + = UE : : SmartObject : : GEnabledReasonTags [ TagIndex ] . ToString ( ) ;
}
}
return DisableFlagsStringBuilder . ToString ( ) ;
}
# endif // WITH_SMARTOBJECT_DEBUG
2023-01-18 10:52:51 -05:00
2021-09-28 13:33:17 -04:00
//----------------------------------------------------------------------//
2022-11-01 15:11:25 -04:00
// FSmartObjectRuntimeSlot
2021-09-28 13:33:17 -04:00
//----------------------------------------------------------------------//
2023-11-30 02:26:33 -05:00
bool FSmartObjectRuntimeSlot : : Claim ( const FSmartObjectUserHandle & InUser , ESmartObjectClaimPriority ClaimPriority )
2021-09-28 13:33:17 -04:00
{
2023-11-30 02:26:33 -05:00
if ( CanBeClaimed ( ClaimPriority ) )
2021-09-28 13:33:17 -04:00
{
State = ESmartObjectSlotState : : Claimed ;
User = InUser ;
2023-11-30 02:26:33 -05:00
ClaimedPriority = ClaimPriority ;
2021-09-28 13:33:17 -04:00
return true ;
}
return false ;
}
2022-01-19 14:16:16 -05:00
2022-11-01 15:11:25 -04:00
bool FSmartObjectRuntimeSlot : : Release ( const FSmartObjectClaimHandle & ClaimHandle , const bool bAborted )
2022-01-19 14:16:16 -05:00
{
if ( ! ensureMsgf ( ClaimHandle . IsValid ( ) , TEXT ( " Attempting to release a slot using an invalid handle: %s " ) , * LexToString ( ClaimHandle ) ) )
{
return false ;
}
bool bReleased = false ;
if ( State ! = ESmartObjectSlotState : : Claimed & & State ! = ESmartObjectSlotState : : Occupied )
{
UE_LOG ( LogSmartObject , Error , TEXT ( " Expected slot state is 'Claimed' or 'Occupied' but current state is '%s'. Slot will not be released " ) ,
* UEnum : : GetValueAsString ( State ) ) ;
}
else if ( ClaimHandle . UserHandle ! = User )
{
UE_LOG ( LogSmartObject , Error , TEXT ( " User '%s' is trying to release slot claimed or used by other user '%s'. Slot will not be released " ) ,
* LexToString ( ClaimHandle . UserHandle ) , * LexToString ( User ) ) ;
}
else
{
if ( bAborted )
{
const bool bFunctionWasExecuted = OnSlotInvalidatedDelegate . ExecuteIfBound ( ClaimHandle , State ) ;
UE_LOG ( LogSmartObject , Verbose , TEXT ( " Slot invalidated callback was%scalled for %s " ) , bFunctionWasExecuted ? TEXT ( " " ) : TEXT ( " not " ) , * LexToString ( ClaimHandle ) ) ;
}
2022-11-01 15:11:25 -04:00
State = ESmartObjectSlotState : : Free ;
2022-03-18 12:31:49 -04:00
User . Invalidate ( ) ;
2023-02-02 18:43:13 -05:00
UserData . Reset ( ) ;
2023-11-30 02:26:33 -05:00
ClaimedPriority = ESmartObjectClaimPriority : : None ;
2022-01-19 14:16:16 -05:00
bReleased = true ;
}
return bReleased ;
}