Context
The property 'DefaultStartingData' in AbilitySystemComponent can be configured from blueprint to spawn default attribute sets. This happens OnRegister. For runtime spawned actors like pawns, both the server and client will individually construct those attribute set objects and store them in SpawnedAttributes. Eventually, the client will forget its locally created one from SpawnedAttributes and retain the object replicated over from the server.
Problem
When GameplayEffects (GE) are applied on the server immediately on character spawn, the GE can replicated over to the client via ActiveGameplayEffects and
FActiveGameplayEffectsContainer::NetDeltaSerialize
This can happen while the client is still using its locally created attribute set. ActiveGameplayEffects then contains a state for those attributes.
Currently, OnRep_SpawnedAttributes detects removed attribute sets by object and clears the state for all contained attributes. It doesn't account for the situation where an attribute set is replicated down from the server and replaces an equivalent client-side one. OnRep_SpawnedAttributes then calls
ActiveGameplayEffects.CleanupAttributeAggregator(Attribute);
on attributes that are still in play.
Proposal
The call to CleanupAttributeAggregator(Attribute) should be skipped for attributes that are still in play. Any relevant state should be migrated from the temp client attribute set to the attribute set replicated over from the server.
Given a character blueprint with an AbilitySystemComponent (ASC) in Full replication mode:
void UMyAttributeSet::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) { const FString NetRoleName = GetOwningActor() ? GetOwningActor()->HasAuthority() ? TEXT("Server") : TEXT("Client") : TEXT("Unresolved"); UE_LOG(LogTemp, Warning, TEXT("[%s] Value of %s changed: %.2f -> %.2f"), *NetRoleName, *Attribute.AttributeName, OldValue, NewValue); }
Non-fatal, but this is where the client erronously clears an aggregator for an attribute set:
> UnrealEditor-GameplayAbilities.dll!UAbilitySystemComponent::OnRep_SpawnedAttributes(const TArray<UAttributeSet *,TSizedDefaultAllocator<32>> & PreviousSpawnedAttributes) Line 3115 C++ UnrealEditor-GameplayAbilities.dll!UAbilitySystemComponent::execOnRep_SpawnedAttributes(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 3135 C++ UnrealEditor-CoreUObject.dll!UFunction::Invoke(UObject * Obj, FFrame & Stack, void * const Z_Param__Result) Line 7238 C++ UnrealEditor-CoreUObject.dll!UObject::ProcessEvent(UFunction * Function, void * Parms) Line 2144 C++ [Inline Frame] UnrealEditor-Engine.dll!EnumHasAnyFlags(ERepParentFlags) Line 38 C++ UnrealEditor-Engine.dll!FRepLayout::CallRepNotifies(FReceivingRepState * RepState, UObject * Object) Line 4697 C++ UnrealEditor-Engine.dll!FObjectReplicator::CallRepNotifies(bool bSkipIfChannelHasQueuedBunches) Line 2329 C++ UnrealEditor-Engine.dll!UActorChannel::ProcessBunch(FInBunch & Bunch) Line 3339 C++ UnrealEditor-Engine.dll!UActorChannel::ReceivedBunch(FInBunch & Bunch) Line 3092 C++ UnrealEditor-Engine.dll!UChannel::ReceivedSequencedBunch(FInBunch & Bunch) Line 576 C++ UnrealEditor-Engine.dll!UChannel::ReceivedNextBunch(FInBunch & Bunch, bool & bOutSkipAck) Line 1039 C++ UnrealEditor-Engine.dll!UChannel::ReceivedRawBunch(FInBunch & Bunch, bool & bOutSkipAck) Line 687 C++ UnrealEditor-Engine.dll!UNetConnection::DispatchPacket(FBitReader & Reader, int PacketId, bool & bOutSkipAck, bool & bOutHasBunchErrors) Line 3841 C++ UnrealEditor-Engine.dll!UNetConnection::ReceivedPacket(FBitReader & Reader, bool bIsReinjectedPacket, bool bDispatchPacket) Line 3217 C++ UnrealEditor-Engine.dll!UNetConnection::ReceivedRawPacket(void * InData, int Count) Line 2067 C++ UnrealEditor-OnlineSubsystemUtils.dll!UIpNetDriver::TickDispatch(float DeltaTime) Line 1301 C++ UnrealEditor-Engine.dll!UNetDriver::InternalTickDispatch(float DeltaSeconds) Line 2059 C++ [Inline Frame] UnrealEditor-Engine.dll!Invoke(void(UNetDriver::*)(float)) Line 66 C++ [Inline Frame] UnrealEditor-Engine.dll!UE::Core::Private::Tuple::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(UNetDriver::*)(float) &) Line 317 C++ UnrealEditor-Engine.dll!TBaseUObjectMethodDelegateInstance<0,UNetDriver,void __cdecl(float),FDefaultDelegateUserPolicy>::ExecuteIfSafe(float <Params_0>) Line 667 C++ [Inline Frame] UnrealEditor-Engine.dll!TMulticastDelegateBase<FDefaultDelegateUserPolicy>::Broadcast(float) Line 257 C++ UnrealEditor-Engine.dll!TMulticastDelegate<void __cdecl(float),FDefaultDelegateUserPolicy>::Broadcast(float <Params_0>) Line 1079 C++ UnrealEditor-Engine.dll!UWorld::Tick(ELevelTick TickType, float DeltaSeconds) Line 1328 C++ UnrealEditor-UnrealEd.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 2138 C++ UnrealEditor-UnrealEd.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 550 C++ UnrealEditor.exe!FEngineLoop::Tick() Line 5849 C++
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-228596 in the post.
0 |
Component | UE - Gameplay - Gameplay Ability System |
---|---|
Target Fix | 5.6 |
Fix Commit | 37889013 |
---|
Created | Oct 23, 2024 |
---|---|
Resolved | Nov 7, 2024 |
Updated | Nov 8, 2024 |