/** The TargetActor we spawned locally has called back with valid target data */ void UAbilityTask_WaitTargetData::OnTargetDataReadyCallback(FGameplayAbilityTargetDataHandle Data) { check(AbilitySystemComponent); if (!Ability) { return; } FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent, ShouldReplicateDataToServer()); const FGameplayAbilityActorInfo* Info = Ability->GetCurrentActorInfo(); if (IsPredictingClient()) { if (!TargetActor->ShouldProduceTargetDataOnServer) { FGameplayTag ApplicationTag; // Fixme: where would this be useful? AbilitySystemComponent->ServerSetReplicatedTargetData(GetAbilitySpecHandle(), GetActivationPredictionKey(), Data, ApplicationTag, AbilitySystemComponent->ScopedPredictionKey); } else if (ConfirmationType == EGameplayTargetingConfirmation::UserConfirmed) { // We aren't going to send the target data, but we will send a generic confirmed message. AbilitySystemComponent->ServerSetReplicatedEvent(EAbilityGenericReplicatedEvent::GenericConfirm, GetAbilitySpecHandle(), GetActivationPredictionKey(), AbilitySystemComponent->ScopedPredictionKey); } } ValidData.Broadcast(Data); if (ConfirmationType != EGameplayTargetingConfirmation::CustomMulti) { EndTask(); } }
/** Valid TargetData was replicated to use (we are server, was sent from client) */ void UAbilityTask_WaitTargetData::OnTargetDataReplicatedCallback(FGameplayAbilityTargetDataHandle Data, FGameplayTag ActivationTag) { check(AbilitySystemComponent); AbilitySystemComponent->ConsumeClientReplicatedTargetData(GetAbilitySpecHandle(), GetActivationPredictionKey()); /** * Call into the TargetActor to sanitize/verify the data. If this returns false, we are rejecting * the replicated target data and will treat this as a cancel. * * This can also be used for bandwidth optimizations. OnReplicatedTargetDataReceived could do an actual * trace/check/whatever server side and use that data. So rather than having the client send that data * explicitly, the client is basically just sending a 'confirm' and the server is now going to do the work * in OnReplicatedTargetDataReceived. */ if (TargetActor && !TargetActor->OnReplicatedTargetDataReceived(Data)) { Cancelled.Broadcast(Data); } else { ValidData.Broadcast(Data); } if (ConfirmationType != EGameplayTargetingConfirmation::CustomMulti) { EndTask(); } }
void UAbilityTask_WaitTargetData::RegisterTargetDataCallbacks() { if (!ensure(IsPendingKill() == false)) { return; } check(TargetClass); check(Ability); const AGameplayAbilityTargetActor* CDO = CastChecked<AGameplayAbilityTargetActor>(TargetClass->GetDefaultObject()); const bool bIsLocallyControlled = Ability->GetCurrentActorInfo()->IsLocallyControlled(); const bool bShouldProduceTargetDataOnServer = CDO->ShouldProduceTargetDataOnServer; // If not locally controlled (server for remote client), see if TargetData was already sent // else register callback for when it does get here. if (!bIsLocallyControlled) { // Register with the TargetData callbacks if we are expecting client to send them if (!bShouldProduceTargetDataOnServer) { FGameplayAbilitySpecHandle SpecHandle = GetAbilitySpecHandle(); FPredictionKey ActivationPredictionKey = GetActivationPredictionKey(); //Since multifire is supported, we still need to hook up the callbacks AbilitySystemComponent->AbilityTargetDataSetDelegate(SpecHandle, ActivationPredictionKey ).AddUObject(this, &UAbilityTask_WaitTargetData::OnTargetDataReplicatedCallback); AbilitySystemComponent->AbilityTargetDataCancelledDelegate(SpecHandle, ActivationPredictionKey ).AddUObject(this, &UAbilityTask_WaitTargetData::OnTargetDataReplicatedCancelledCallback); AbilitySystemComponent->CallReplicatedTargetDataDelegatesIfSet(SpecHandle, ActivationPredictionKey ); SetWaitingOnRemotePlayerData(); } } }
void UAbilityTask_WaitConfirmCancel::OnLocalCancelCallback() { if (AbilitySystemComponent && IsPredictingClient()) { AbilitySystemComponent->ServerSetReplicatedEvent(EAbilityGenericReplicatedEvent::GenericCancel, GetAbilitySpecHandle(), GetActivationPredictionKey() ,AbilitySystemComponent->ScopedPredictionKey); } OnCancelCallback(); }
void UAbilityTask_WaitConfirmCancel::OnCancelCallback() { if (AbilitySystemComponent) { AbilitySystemComponent->ConsumeGenericReplicatedEvent(EAbilityGenericReplicatedEvent::GenericCancel, GetAbilitySpecHandle(), GetActivationPredictionKey()); OnCancel.Broadcast(); EndTask(); } }
/** The TargetActor we spawned locally has called back with a cancel event (they still include the 'last/best' targetdata but the consumer of this may want to discard it) */ void UAbilityTask_WaitTargetData::OnTargetDataCancelledCallback(FGameplayAbilityTargetDataHandle Data) { check(AbilitySystemComponent); if (IsPredictingClient()) { if (!TargetActor->ShouldProduceTargetDataOnServer) { AbilitySystemComponent->ServerSetReplicatedTargetDataCancelled(GetAbilitySpecHandle(), GetActivationPredictionKey(), AbilitySystemComponent->ScopedPredictionKey ); } else { // We aren't going to send the target data, but we will send a generic confirmed message. AbilitySystemComponent->ServerSetReplicatedEvent(EAbilityGenericReplicatedEvent::GenericCancel, GetAbilitySpecHandle(), GetActivationPredictionKey(), AbilitySystemComponent->ScopedPredictionKey); } } Cancelled.Broadcast(Data); EndTask(); }
bool UAbilityTask::CallOrAddReplicatedDelegate(EAbilityGenericReplicatedEvent::Type Event, FSimpleMulticastDelegate::FDelegate Delegate) { return AbilitySystemComponent->CallOrAddReplicatedDelegate(Event, GetAbilitySpecHandle(), GetActivationPredictionKey(), Delegate); }