diff --git a/Source/GameBaseFramework/Private/Characters/GBFCharacter.cpp b/Source/GameBaseFramework/Private/Characters/GBFCharacter.cpp index 9adf02ea..d5cb6167 100644 --- a/Source/GameBaseFramework/Private/Characters/GBFCharacter.cpp +++ b/Source/GameBaseFramework/Private/Characters/GBFCharacter.cpp @@ -141,12 +141,13 @@ void AGBFCharacter::SetupPlayerInputComponent( UInputComponent * player_input_co void AGBFCharacter::OnMovementModeChanged( EMovementMode prev_movement_mode, uint8 previous_custom_mode ) { - Super::OnMovementModeChanged( prev_movement_mode, previous_custom_mode ); - + // Update the tags before calling Super, which calls a delegate, and some code bound to this delegate may require the tags to be up-to-date const auto * character_movement_component = GetCharacterMovement(); SetMovementModeTag( prev_movement_mode, previous_custom_mode, false ); SetMovementModeTag( character_movement_component->MovementMode, character_movement_component->CustomMovementMode, true ); + + Super::OnMovementModeChanged( prev_movement_mode, previous_custom_mode ); } void AGBFCharacter::OnAbilitySystemInitialized() diff --git a/Source/GameBaseFramework/Private/GAS/Tasks/GBFAT_WaitMovementModeChanged.cpp b/Source/GameBaseFramework/Private/GAS/Tasks/GBFAT_WaitMovementModeChanged.cpp new file mode 100644 index 00000000..f955d48e --- /dev/null +++ b/Source/GameBaseFramework/Private/GAS/Tasks/GBFAT_WaitMovementModeChanged.cpp @@ -0,0 +1,73 @@ +#include "GAS/Tasks/GBFAT_WaitMovementModeChanged.h" + +#include "GameFramework/CharacterMovementComponent.h" + +#include + +UGBFAT_WaitMovementModeChanged::UGBFAT_WaitMovementModeChanged() : + RequiredMode( MOVE_None ), + bTriggerInstantlyIfMovementModeChanges( true ) +{ +} + +UGBFAT_WaitMovementModeChanged * UGBFAT_WaitMovementModeChanged::WaitMovementModeChange( UGameplayAbility * owning_ability, ACharacter * character /*= nullptr */, bool trigger_instantly_if_movement_mode_matches /*= true*/, EMovementMode required_mode /*= MOVE_None*/ ) +{ + auto * task = NewAbilityTask< UGBFAT_WaitMovementModeChanged >( owning_ability ); + task->RequiredMode = required_mode; + task->Character = character; + task->bTriggerInstantlyIfMovementModeChanges = trigger_instantly_if_movement_mode_matches; + return task; +} + +void UGBFAT_WaitMovementModeChanged::Activate() +{ + Super::Activate(); + + if ( Character.IsValid() ) + { + if ( const auto * movement_component = Cast< UCharacterMovementComponent >( Character->GetMovementComponent() ) ) + { + if ( bTriggerInstantlyIfMovementModeChanges && ( RequiredMode == MOVE_None || movement_component->MovementMode == RequiredMode ) ) + { + BroadcastEvent( movement_component->MovementMode ); + return; + } + } + Character->MovementModeChangedDelegate.AddDynamic( this, &ThisClass::OnMovementModeChange ); + } + + SetWaitingOnAvatar(); +} + +void UGBFAT_WaitMovementModeChanged::OnDestroy( bool AbilityEnded ) +{ + Super::OnDestroy( AbilityEnded ); + + if ( Character.IsValid() ) + { + Character->MovementModeChangedDelegate.RemoveDynamic( this, &ThisClass::OnMovementModeChange ); + } +} + +void UGBFAT_WaitMovementModeChanged::OnMovementModeChange( ACharacter * character, EMovementMode prev_movement_mode, uint8 previous_custom_node ) +{ + if ( Character.IsValid() ) + { + if ( const auto * movement_component = Cast< UCharacterMovementComponent >( Character->GetMovementComponent() ) ) + { + if ( RequiredMode == MOVE_None || movement_component->MovementMode == RequiredMode ) + { + BroadcastEvent( movement_component->MovementMode ); + } + } + } +} + +void UGBFAT_WaitMovementModeChanged::BroadcastEvent( EMovementMode movement_mode ) +{ + if ( ShouldBroadcastAbilityTaskDelegates() ) + { + OnChange.Broadcast( movement_mode ); + } + EndTask(); +} \ No newline at end of file diff --git a/Source/GameBaseFramework/Public/GAS/Tasks/GBFAT_WaitMovementModeChanged.h b/Source/GameBaseFramework/Public/GAS/Tasks/GBFAT_WaitMovementModeChanged.h new file mode 100644 index 00000000..ee554ae6 --- /dev/null +++ b/Source/GameBaseFramework/Public/GAS/Tasks/GBFAT_WaitMovementModeChanged.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include "GBFAT_WaitMovementModeChanged.generated.h" + +class ACharacter; + +UCLASS() +class GAMEBASEFRAMEWORK_API UGBFAT_WaitMovementModeChanged final : public UAbilityTask +{ + GENERATED_BODY() + +public: + DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FGBFMovementModeChangedDelegate, EMovementMode, NewMovementMode ); + + UGBFAT_WaitMovementModeChanged(); + + /** Wait until movement mode changes (E.g., landing) */ + UFUNCTION( BlueprintCallable, Category = "Ability|Tasks", DisplayName = "Wait for character movement changed", meta = ( HidePin = "owning_ability", DefaultToSelf = "owning_ability", BlueprintInternalUseOnly = "true" ) ) + static UGBFAT_WaitMovementModeChanged * WaitMovementModeChange( UGameplayAbility * owning_ability, ACharacter * character = nullptr, bool trigger_instantly_if_movement_mode_matches = true, EMovementMode required_mode = MOVE_None ); + + void Activate() override; + +protected: + void OnDestroy( bool AbilityEnded ) override; + + UFUNCTION() + void OnMovementModeChange( ACharacter * character, EMovementMode prev_movement_mode, uint8 previous_custom_node ); + + void BroadcastEvent( EMovementMode movement_mode ); + + UPROPERTY( BlueprintAssignable ) + FGBFMovementModeChangedDelegate OnChange; + + EMovementMode RequiredMode; + TWeakObjectPtr< ACharacter > Character; + bool bTriggerInstantlyIfMovementModeChanges; +};