I’m trying to set up so that when some ability get activate it should add a new Mapping Context. But it seems like here it only do for the Host/Server and Clients can’t add these mapping in. If Host/Server add a mapping in that mapping will also change for clients somehow. Is there any other way to solve this problem.
Here is the code.
void UDS_GameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
if (WaitTargetDataActor && ActorInfo->IsLocallyControlled())
{
// Get the local player enhanced input subsystem
UEnhancedInputLocalPlayerSubsystem* EnhancedInputLocalPlayerSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(ActorInfo->PlayerController->GetLocalPlayer());
if (ActorInfo->PlayerController.IsValid())
{
ADS_PlayerController* DS_PS = CastChecked<ADS_PlayerController>(ActorInfo->PlayerController.Get());
EnhancedInputLocalPlayerSubsystem->AddMappingContext(DS_PS->WaitTargetDataMapping, 1);
}
}
}
I found the problem after some hours of debugging. Player State didn’t get initialize or replicated or available at the time I try to bind the input action because of late join and haven’t received a valid player state
if (PlayerState* M_PlayerState = Cast<S_PlayerState>(PlayerState))
{
EnhancedInputComponent->BindAction(InputTargetActorConfirm, ETriggerEvent::Triggered, S_PlayerState->GetAbilitySystemComponent(), &UAbilitySystemComponent::InputConfirm);
EnhancedInputComponent->BindAction(InputTargetActorCancel, ETriggerEvent::Triggered, S_PlayerState->GetAbilitySystemComponent(), &UAbilitySystemComponent::InputCancel);
}
So I just remove the If check and bind them to these function instead
EnhancedInputComponent->BindAction(InputTargetActorConfirm, ETriggerEvent::Triggered, this, &S_PlayerController::TryConfirmAbility);
EnhancedInputComponent->BindAction(InputTargetActorCancel, ETriggerEvent::Triggered, this, &S_PlayerController::TryCancelAbility);
And these function do
void S_PlayerController::TryConfirmAbility()
{
if (S_PlayerState* M_PlayerState = Cast<S_PlayerState>(PlayerState))
{
M_PlayerState->ConfirmInput();
}
}
void S_PlayerController::TryCancelAbility()
{
if (S_PlayerState* M_PlayerState = Cast<S_PlayerState>(PlayerState))
{
M_PlayerState->CancelInput();
}
}