第一次提交
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
|
||||
#include "Interaction/Tasks/GGS_AbilityTask_UseSmartObjectWithGameplayBehavior.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "GameplayBehavior.h"
|
||||
#include "GameplayBehaviorConfig.h"
|
||||
#include "GameplayBehaviorSmartObjectBehaviorDefinition.h"
|
||||
#include "GameplayBehaviorSubsystem.h"
|
||||
#include "GGS_LogChannels.h"
|
||||
#include "SmartObjectComponent.h"
|
||||
#include "SmartObjectSubsystem.h"
|
||||
|
||||
UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
|
||||
{
|
||||
bBehaviorFinished = false;
|
||||
}
|
||||
|
||||
UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior* UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::UseSmartObjectWithGameplayBehavior(UGameplayAbility* OwningAbility,
|
||||
FSmartObjectClaimHandle ClaimHandle, ESmartObjectClaimPriority ClaimPriority)
|
||||
{
|
||||
if (OwningAbility == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior* MyTask = NewAbilityTask<UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior>(OwningAbility);
|
||||
if (MyTask == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
MyTask->SetClaimHandle(ClaimHandle);
|
||||
return MyTask;
|
||||
}
|
||||
|
||||
void UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::Activate()
|
||||
{
|
||||
Super::Activate();
|
||||
bool bSuccess = false;
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
if (!bSuccess)
|
||||
{
|
||||
EndTask();
|
||||
}
|
||||
};
|
||||
|
||||
if (!ensureMsgf(ClaimedHandle.IsValid(), TEXT("SmartObject handle must be valid at this point.")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
APawn* Pawn = Cast<APawn>(GetAvatarActor());
|
||||
if (Pawn == nullptr)
|
||||
{
|
||||
GGS_CLOG(Error, "Pawn required to use GameplayBehavior with claim handle: %s.", *LexToString(ClaimedHandle));
|
||||
return;
|
||||
}
|
||||
USmartObjectSubsystem* SmartObjectSubsystem = USmartObjectSubsystem::GetCurrent(Pawn->GetWorld());
|
||||
if (!ensureMsgf(SmartObjectSubsystem != nullptr, TEXT("SmartObjectSubsystem must be accessible at this point.")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// A valid claimed handle can point to an object that is no longer part of the simulation
|
||||
if (!SmartObjectSubsystem->IsClaimedSmartObjectValid(ClaimedHandle))
|
||||
{
|
||||
GGS_CLOG(Log, "Claim handle: %s refers to an object that is no longer available.", *LexToString(ClaimedHandle));
|
||||
return;
|
||||
}
|
||||
|
||||
// Register a callback to be notified if the claimed slot became unavailable
|
||||
SmartObjectSubsystem->RegisterSlotInvalidationCallback(ClaimedHandle, FOnSlotInvalidated::CreateUObject(this, &UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::OnSlotInvalidated));
|
||||
|
||||
bSuccess = StartInteraction();
|
||||
}
|
||||
|
||||
bool UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::StartInteraction()
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
USmartObjectSubsystem* SmartObjectSubsystem = USmartObjectSubsystem::GetCurrent(World);
|
||||
if (!ensure(SmartObjectSubsystem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const UGameplayBehaviorSmartObjectBehaviorDefinition* SmartObjectGameplayBehaviorDefinition = SmartObjectSubsystem->MarkSlotAsOccupied<
|
||||
UGameplayBehaviorSmartObjectBehaviorDefinition>(ClaimedHandle);
|
||||
const UGameplayBehaviorConfig* GameplayBehaviorConfig = SmartObjectGameplayBehaviorDefinition != nullptr ? SmartObjectGameplayBehaviorDefinition->GameplayBehaviorConfig : nullptr;
|
||||
GameplayBehavior = GameplayBehaviorConfig != nullptr ? GameplayBehaviorConfig->GetBehavior(*World) : nullptr;
|
||||
if (GameplayBehavior == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const USmartObjectComponent* SmartObjectComponent = SmartObjectSubsystem->GetSmartObjectComponent(ClaimedHandle);
|
||||
AActor& InteractorActor = *GetAvatarActor();
|
||||
AActor* InteracteeActor = SmartObjectComponent ? SmartObjectComponent->GetOwner() : nullptr;
|
||||
const bool bBehaviorActive = UGameplayBehaviorSubsystem::TriggerBehavior(*GameplayBehavior, InteractorActor, GameplayBehaviorConfig, InteracteeActor);
|
||||
// Behavior can be successfully triggered AND ended synchronously. We are only interested to register callback when still running
|
||||
if (bBehaviorActive)
|
||||
{
|
||||
OnBehaviorFinishedNotifyHandle = GameplayBehavior->GetOnBehaviorFinishedDelegate().AddUObject(this, &UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::OnSmartObjectBehaviorFinished);
|
||||
}
|
||||
|
||||
return bBehaviorActive;
|
||||
}
|
||||
|
||||
void UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::OnSmartObjectBehaviorFinished(UGameplayBehavior& Behavior, AActor& Avatar, const bool bInterrupted)
|
||||
{
|
||||
// Adding an ensure in case the assumptions change in the future.
|
||||
ensure(GetAvatarActor() != nullptr);
|
||||
|
||||
// make sure we handle the right pawn - we can get this notify for a different
|
||||
// Avatar if the behavior sending it out is not instanced (CDO is being used to perform actions)
|
||||
if (GetAvatarActor() == &Avatar)
|
||||
{
|
||||
Behavior.GetOnBehaviorFinishedDelegate().Remove(OnBehaviorFinishedNotifyHandle);
|
||||
bBehaviorFinished = true;
|
||||
EndTask();
|
||||
}
|
||||
}
|
||||
|
||||
void UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::OnDestroy(bool bInOwnerFinished)
|
||||
{
|
||||
if (ClaimedHandle.IsValid())
|
||||
{
|
||||
USmartObjectSubsystem* SmartObjectSubsystem = USmartObjectSubsystem::GetCurrent(GetWorld());
|
||||
check(SmartObjectSubsystem);
|
||||
SmartObjectSubsystem->MarkSlotAsFree(ClaimedHandle);
|
||||
SmartObjectSubsystem->UnregisterSlotInvalidationCallback(ClaimedHandle);
|
||||
ClaimedHandle.Invalidate();
|
||||
}
|
||||
|
||||
if (TaskState != EGameplayTaskState::Finished)
|
||||
{
|
||||
if (GameplayBehavior != nullptr && bBehaviorFinished)
|
||||
{
|
||||
OnSucceeded.Broadcast();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnFailed.Broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
Super::OnDestroy(bInOwnerFinished);
|
||||
}
|
||||
|
||||
void UGGS_AbilityTask_UseSmartObjectWithGameplayBehavior::OnSlotInvalidated(const FSmartObjectClaimHandle& ClaimHandle, const ESmartObjectSlotState State)
|
||||
{
|
||||
if (!bBehaviorFinished && GameplayBehavior != nullptr)
|
||||
{
|
||||
check(GetAvatarActor());
|
||||
GameplayBehavior->GetOnBehaviorFinishedDelegate().Remove(OnBehaviorFinishedNotifyHandle);
|
||||
GameplayBehavior->AbortBehavior(*GetAvatarActor());
|
||||
}
|
||||
EndTask();
|
||||
}
|
||||
Reference in New Issue
Block a user