You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Moved all State Tree things into StateTree folder - Added StateTree conditions that check Smart Object slot tags and state - Added StateTree task to modify SmartObject slot tags - Added StateTree task to monitor SmartObject slot tags - Added StateTree task to listen SmartObject events - Added StateTree task to sync execution based on SmartObject slot tags #rb Maxime.Mercier Luciano.Ferraro #preflight 636124a8ef6d25c67458635c [CL 22888785 by mikko mononen in ue5-main branch]
248 lines
8.4 KiB
C++
248 lines
8.4 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
#include "GameplayInteractionContext.h"
|
|
#include "GameplayInteractionSmartObjectBehaviorDefinition.h"
|
|
#include "GameplayInteractionsTypes.h"
|
|
#include "GameFramework/Actor.h"
|
|
#include "Engine/World.h"
|
|
#include "Subsystems/WorldSubsystem.h"
|
|
#include "StateTreeReference.h"
|
|
#include "VisualLogger/VisualLogger.h"
|
|
#include "GameplayInteractionStateTreeSchema.h"
|
|
#include "SmartObjectSubsystem.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(GameplayInteractionContext)
|
|
|
|
bool FGameplayInteractionContext::Activate(const UGameplayInteractionSmartObjectBehaviorDefinition& InDefinition)
|
|
{
|
|
Definition = &InDefinition;
|
|
check(Definition);
|
|
|
|
const FStateTreeReference& StateTreeReference = Definition->StateTreeReference;
|
|
const UStateTree* StateTree = StateTreeReference.GetStateTree();
|
|
|
|
if (!IsValid())
|
|
{
|
|
UE_LOG(LogGameplayInteractions, Error, TEXT("Failed to activate interaction. Context is not properly setup."));
|
|
return false;
|
|
}
|
|
|
|
if (StateTree == nullptr)
|
|
{
|
|
UE_VLOG_UELOG(ContextActor, LogGameplayInteractions, Error,
|
|
TEXT("Failed to activate interaction for %s. Definition %s doesn't point to a valid StateTree asset."),
|
|
*GetNameSafe(ContextActor),
|
|
*Definition.GetFullName());
|
|
return false;
|
|
}
|
|
|
|
FStateTreeExecutionContext StateTreeContext(*ContextActor, *StateTree, StateTreeInstanceData);
|
|
|
|
if (!StateTreeContext.IsValid())
|
|
{
|
|
UE_VLOG_UELOG(ContextActor, LogGameplayInteractions, Error,
|
|
TEXT("Failed to activate interaction for %s. Unable to initialize StateTree execution context for StateTree asset: %s."),
|
|
*GetNameSafe(ContextActor),
|
|
*StateTree->GetFullName());
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateSchema(StateTreeContext))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!SetContextRequirements(StateTreeContext))
|
|
{
|
|
UE_VLOG_UELOG(ContextActor, LogGameplayInteractions, Error,
|
|
TEXT("Failed to activate interaction for %s. Unable to provide all external data views for StateTree asset: %s."),
|
|
*GetNameSafe(ContextActor),
|
|
*StateTree->GetFullName());
|
|
return false;
|
|
}
|
|
|
|
// Set slot user actor
|
|
USmartObjectSubsystem* SmartObjectSubsystem = USmartObjectSubsystem::GetCurrent(ContextActor->GetWorld());
|
|
check(SmartObjectSubsystem);
|
|
FSmartObjectSlotView SlotView = SmartObjectSubsystem->GetSlotView(ClaimedHandle.SlotHandle);
|
|
if (SlotView.IsValid())
|
|
{
|
|
if (FGameplayInteractionSlotUserData* UserData = SlotView.GetStateDataPtr<FGameplayInteractionSlotUserData>())
|
|
{
|
|
UserData->UserActor = ContextActor;
|
|
}
|
|
else
|
|
{
|
|
SmartObjectSubsystem->AddSlotDataDeferred(ClaimedHandle, FConstStructView::Make(FGameplayInteractionSlotUserData(ContextActor)));
|
|
}
|
|
}
|
|
|
|
// Start State Tree
|
|
StateTreeContext.Start();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FGameplayInteractionContext::Tick(const float DeltaTime)
|
|
{
|
|
if (Definition == nullptr || !IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const FStateTreeReference& StateTreeReference = Definition->StateTreeReference;
|
|
const UStateTree* StateTree = StateTreeReference.GetStateTree();
|
|
FStateTreeExecutionContext StateTreeContext(*ContextActor, *StateTree, StateTreeInstanceData);
|
|
|
|
EStateTreeRunStatus RunStatus = EStateTreeRunStatus::Unset;
|
|
if (SetContextRequirements(StateTreeContext))
|
|
{
|
|
RunStatus = StateTreeContext.Tick(DeltaTime);
|
|
}
|
|
|
|
return RunStatus == EStateTreeRunStatus::Running;
|
|
}
|
|
|
|
void FGameplayInteractionContext::Deactivate()
|
|
{
|
|
if (Definition == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FStateTreeReference& StateTreeReference = Definition->StateTreeReference;
|
|
const UStateTree* StateTree = StateTreeReference.GetStateTree();
|
|
FStateTreeExecutionContext StateTreeContext(*ContextActor, *StateTree, StateTreeInstanceData);
|
|
|
|
if (SetContextRequirements(StateTreeContext))
|
|
{
|
|
StateTreeContext.Stop();
|
|
}
|
|
|
|
// Remove user
|
|
USmartObjectSubsystem* SmartObjectSubsystem = USmartObjectSubsystem::GetCurrent(ContextActor->GetWorld());
|
|
check(SmartObjectSubsystem);
|
|
FSmartObjectSlotView SlotView = SmartObjectSubsystem->GetSlotView(ClaimedHandle.SlotHandle);
|
|
if (SlotView.IsValid())
|
|
{
|
|
if (FGameplayInteractionSlotUserData* UserData = SlotView.GetStateDataPtr<FGameplayInteractionSlotUserData>())
|
|
{
|
|
UserData->UserActor = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FGameplayInteractionContext::SendEvent(const FStateTreeEvent& Event)
|
|
{
|
|
SendEvent(Event.Tag, Event.Payload, Event.Origin);
|
|
}
|
|
|
|
void FGameplayInteractionContext::SendEvent(const FGameplayTag Tag, const FConstStructView Payload, const FName Origin)
|
|
{
|
|
if (Definition == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FStateTreeReference& StateTreeReference = Definition->StateTreeReference;
|
|
const UStateTree* StateTree = StateTreeReference.GetStateTree();
|
|
const FStateTreeExecutionContext StateTreeContext(*ContextActor, *StateTree, StateTreeInstanceData);
|
|
StateTreeContext.SendEvent(Tag, Payload, Origin);
|
|
}
|
|
|
|
bool FGameplayInteractionContext::ValidateSchema(const FStateTreeExecutionContext& StateTreeContext) const
|
|
{
|
|
// Ensure that the actor and smart object match the schema.
|
|
const UGameplayInteractionStateTreeSchema* Schema = Cast<UGameplayInteractionStateTreeSchema>(StateTreeContext.GetStateTree()->GetSchema());
|
|
if (Schema == nullptr)
|
|
{
|
|
UE_VLOG_UELOG(ContextActor, LogGameplayInteractions, Error,
|
|
TEXT("Failed to activate interaction for %s. Expecting %s schema for StateTree asset: %s."),
|
|
*GetNameSafe(ContextActor),
|
|
*GetNameSafe(UGameplayInteractionStateTreeSchema::StaticClass()),
|
|
*GetFullNameSafe(StateTreeContext.GetStateTree()));
|
|
|
|
return false;
|
|
}
|
|
if (!ContextActor || !ContextActor->IsA(Schema->GetContextActorClass()))
|
|
{
|
|
UE_VLOG_UELOG(ContextActor, LogGameplayInteractions, Error,
|
|
TEXT("Failed to activate interaction for %s. Expecting Actor to be of type %s (found %s) for StateTree asset: %s."),
|
|
*GetNameSafe(ContextActor),
|
|
*GetNameSafe(Schema->GetContextActorClass()),
|
|
*GetNameSafe(ContextActor ? ContextActor->GetClass() : nullptr),
|
|
*GetFullNameSafe(StateTreeContext.GetStateTree()));
|
|
|
|
return false;
|
|
}
|
|
if (!SmartObjectActor || !SmartObjectActor->IsA(Schema->GetSmartObjectActorClass()))
|
|
{
|
|
UE_VLOG_UELOG(ContextActor, LogGameplayInteractions, Error,
|
|
TEXT("Failed to activate interaction for %s. SmartObject Actor to be of type %s (found %s) for StateTree asset: %s."),
|
|
*GetNameSafe(ContextActor),
|
|
*GetNameSafe(Schema->GetSmartObjectActorClass()),
|
|
*GetNameSafe(SmartObjectActor ? SmartObjectActor->GetClass() : nullptr),
|
|
*GetFullNameSafe(StateTreeContext.GetStateTree()));
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FGameplayInteractionContext::SetContextRequirements(FStateTreeExecutionContext& StateTreeContext) const
|
|
{
|
|
if (!StateTreeContext.IsValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!::IsValid(Definition))
|
|
{
|
|
return false;
|
|
}
|
|
const FStateTreeReference& StateTreeReference = Definition->StateTreeReference;
|
|
StateTreeContext.SetParameters(StateTreeReference.GetParameters());
|
|
|
|
for (const FStateTreeExternalDataDesc& ItemDesc : StateTreeContext.GetContextDataDescs())
|
|
{
|
|
if (ItemDesc.Name == UE::GameplayInteraction::Names::ContextActor)
|
|
{
|
|
StateTreeContext.SetExternalData(ItemDesc.Handle, FStateTreeDataView(ContextActor));
|
|
}
|
|
else if (ItemDesc.Name == UE::GameplayInteraction::Names::SmartObjectActor)
|
|
{
|
|
StateTreeContext.SetExternalData(ItemDesc.Handle, FStateTreeDataView(SmartObjectActor));
|
|
}
|
|
else if (ItemDesc.Name == UE::GameplayInteraction::Names::SmartObjectClaimedHandle)
|
|
{
|
|
StateTreeContext.SetExternalData(ItemDesc.Handle, FStateTreeDataView(FSmartObjectClaimHandle::StaticStruct(), (uint8*)&ClaimedHandle));
|
|
}
|
|
else if (ItemDesc.Name == UE::GameplayInteraction::Names::AbortContext)
|
|
{
|
|
StateTreeContext.SetExternalData(ItemDesc.Handle, FStateTreeDataView(FGameplayInteractionAbortContext::StaticStruct(), (uint8*)&AbortContext));
|
|
}
|
|
}
|
|
|
|
checkf(ContextActor != nullptr, TEXT("Should never reach this point with an invalid InteractorActor since it is required to get a valid StateTreeContext."));
|
|
const UWorld* World = ContextActor->GetWorld();
|
|
for (const FStateTreeExternalDataDesc& ItemDesc : StateTreeContext.GetExternalDataDescs())
|
|
{
|
|
if (ItemDesc.Struct != nullptr)
|
|
{
|
|
if (World != nullptr && ItemDesc.Struct->IsChildOf(UWorldSubsystem::StaticClass()))
|
|
{
|
|
UWorldSubsystem* Subsystem = World->GetSubsystemBase(Cast<UClass>(const_cast<UStruct*>(ToRawPtr(ItemDesc.Struct))));
|
|
StateTreeContext.SetExternalData(ItemDesc.Handle, FStateTreeDataView(Subsystem));
|
|
}
|
|
else if (ItemDesc.Struct->IsChildOf(AActor::StaticClass()))
|
|
{
|
|
StateTreeContext.SetExternalData(ItemDesc.Handle, FStateTreeDataView(ContextActor));
|
|
}
|
|
}
|
|
}
|
|
|
|
return StateTreeContext.AreExternalDataViewsValid();
|
|
}
|