通过GetLifetimeReplicatedProps控制属性的复制顺序失效

我们项目使用派生自​UAbilitySystemComponent的子类UExtendAbilitySystemComponent。在子类中,有一个FastArray类型的需要复制的成员变量ExtendActivatableAbilities,我们希望它在​UAbilitySystemComponent::ActivatableAbilities之前被复制到客户端。为了达到这个目的,UExtendAbilitySystemComponent::GetLifetimeReplicatedProps被实现为:

​void UExtendAbilitySystemComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	FDoRepLifetimeParams SharedParams;
	SharedParams.bIsPushBased = true;
	SharedParams.Condition = COND_OwnerOnly;
	DOREPLIFETIME_WITH_PARAMS_FAST(UExtendAbilitySystemComponent, ExtendActivatableAbilities, SharedParams);
	Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 放在最后
}​
​

如此一来,ExtendActivatableAbilities就会先于ActivatableAbilities到达客户端。​

根据控制台变量bReplicateCustomDeltaPropertiesInRepIndexOrder的描述,​这应该是引擎有意提供的机制。

在我们把引擎升级到5.6.1后,该机制失效了。

​查看源码得知,之前FRepLayout::InitFromClass函数会按照LifetimeProps的顺序构造LifetimeCustomPropertyState;而在新版本,改成了按照ClassReps的顺序进行构造。看上去,用户不能再通过填充LifetimeProps的顺序对复制顺序产生影响了。

那么,在5.6.1版本,用户应该如何控制属性的复制顺序呢 ?​

你好,你们是开启了iris出现这个问题还是没开启出现的?试下关闭这个设置看看还会出现吗?

Net.AutoRegisterReplicatedProperties=false

我们没有开启iris。

设置 Net.AutoRegisterReplicatedProperties=false 之后没有变化,属性依然是按照RepIndex的顺序复制到客户端。

所以你们项目net.ReplicateCustomDeltaPropertiesInRepIndexOrder设置的也是false对吧?

是的

你好,看起来CL37524353引入了这个问题,我创建了一个JiraUE-352529后面会记录一下,事实上虽然之前版本可能是某些情况会按顺序接收但是某些时候比如网络丢包等情况并不会保证顺序的先后,所以引擎不能保证顺序到达,用户可以通过在回调时置脏并在​PostNetReceive()中等所有属性都接收后在处理

好的。

我对你说的​“引擎不能保证顺序到达”有点疑惑。针对同一个UActorComponent对象里的两个USTRUCT类型的复制属性,DS在同一帧对二者进行了修改,客户端上更新这两个属性的顺序仍然是不保证的吗 ?

虽然一个对象里同一帧修改内部的两个复制属性,在实现细节上是按照顺序进行发送,而且这个问题还是会在后面版本中修复,因为这个cvar会让用户困惑,但在游戏逻辑上接收时不建议依赖更新顺序去做判断,因为接收时的回调不一定按顺序接受,而且可能切换到iris后还是会发生类似的问题。可以用一个结构体同时包含两个变量或者我上面提到的方式来规避。

好的。非常感谢。

不客气,有问题再交流~