UE4.25: 网络新功能:PushModel

UE4.25:网络新功能:PushModel

在ue的网络框架里。Server会对需要同步的Actor的属性做是否已更改的检查(即用当前值和上一次同步的值做比对),只有已经更改后的属性才会从Server同步到Client,在同步量还不是特别大的时候,没有什么性能问题,不过当游戏内需要同步的Actor以及Proerty数量过多时,这里的属性更改检查就会成为Server端的瓶颈,UE已经出了诸如NetUpdateFrequency,NetCullDistanceSquared,Replication Graph等功能,目的就是为了排除尽可能多的不是必须同步的Actor,在这些功能的优化下,Fortnite每局比赛中都有多达50000个同步的Actor;而这篇文章的主题PushModel也是为了解决这一瓶颈;
PushModel可以使开发者主动标记该属性是否已更改,提供了一系列宏来完成,如下

#define MARK_PROPERTY_DIRTY(Object, Property) 
#define MARK_PROPERTY_DIRTY_STATIC_ARRAY_INDEX(Object, RepIndex, ArrayIndex) 
#define MARK_PROPERTY_DIRTY_STATIC_ARRAY(Object, RepIndex, ArrayIndex) 

#define MARK_PROPERTY_DIRTY_FROM_NAME(ClassName, PropertyName, Object) 
#define MARK_PROPERTY_DIRTY_FROM_NAME_STATIC_ARRAY_INDEX(ClassName, PropertyName, ArrayIndex, Object) 
#define MARK_PROPERTY_DIRTY_FROM_NAME_STATIC_ARRAY(ClassName, PropertyName, ArrayIndex, Object) 

这些宏可以在开发者逻辑中的一些设置某个同步变量的时候,就写下对于的标记宏,Server则省去了属性对比的逻辑,只需要检查一些标记即可知道该属性需不需要同步,同时开发者也不必关心该属性是否是正在同步等边界条件,交给PushModel即可;
要使用PushModel,首先属性肯定是要同步的,则必须有同步标记:

UPROPERTY(Replicated)

其次,在GetLifetimeReplicatedProps函数中,需要使用DOREPLIFETIME_WITH_PARAMS_FAST或者DOREPLIFETIME_WITH_PARAMS来标记同步的Proerty;宏定义参考:

#define DOREPLIFETIME_WITH_PARAMS_FAST(c,v,params) \
{ \
	static const bool bIsValid_##c_##v = ValidateReplicatedClassInheritance(StaticClass(), c::StaticClass(), TEXT(#v)); \
	const TCHAR* DoRepPropertyName_##c_##v(TEXT(#v)); \
	const NetworkingPrivate::FRepPropertyDescriptor PropertyDescriptor_##c_##v(DoRepPropertyName_##c_##v, (int32)c::ENetFields_Private::v, 1); \
	RegisterReplicatedLifetimeProperty(PropertyDescriptor_##c_##v, OutLifetimeProps, params); \
}

#define DOREPLIFETIME_WITH_PARAMS(c,v,params) \
{ \
	FProperty* ReplicatedProperty = GetReplicatedProperty(StaticClass(), c::StaticClass(),GET_MEMBER_NAME_CHECKED(c,v)); \
	RegisterReplicatedLifetimeProperty(ReplicatedProperty, OutLifetimeProps, params); \
}

可以发现,则两个宏都需要FDoRepLifetimeParams,来作为宏的第三个参数

struct ENGINE_API FDoRepLifetimeParams
{
	/** Replication Condition. The property will only be replicated to connections where this condition is met. */
	ELifetimeCondition Condition = COND_None;
	
	/**
	 * RepNotify Condition. The property will only trigger a RepNotify if this condition is met, and has been
	 * properly set up to handle RepNotifies.
	 */
	ELifetimeRepNotifyCondition RepNotifyCondition = REPNOTIFY_OnChanged;
	
	/** Whether or not this property uses Push Model. See PushModel.h */
	bool bIsPushBased = false;
};

在FDoRepLifetimeParams结构体中,bIsPushBased即代表是否对当前Proertyt启用PushModel功能,同时EPIC的程序大佬也给出了使用实例,在PushModel.h中,可以作为参考;
以同步属性APlayerstate::Score举例,首先在Playerstate.h中定义:

UPROPERTY(ReplicatedUsing=OnRep_Score, BlueprintReadOnly, Category=PlayerState)
	float Score;

同时在APlayerState::GetLifetimeReplicatedProps函数中:

FDoRepLifetimeParams SharedParams;
	SharedParams.bIsPushBased = true;

	DOREPLIFETIME_WITH_PARAMS_FAST(APlayerState, Score, SharedParams);

可以看出,针对Score属性,启用了PushModel功能,(PushModel是以属性为单位的,在同一个Actor内,多个不同的同步属性,可以部分使用PushModel功能,也可以全部使用PushModel功能),在设置Score的时候:

void APlayerState::SetScore(const float NewScore)
{
	MARK_PROPERTY_DIRTY_FROM_NAME(APlayerState, Score, this);
	Score = NewScore;
}

即标记该属性已更改,至此,PushModel则正常使用。

猜你喜欢

转载自blog.csdn.net/u014391423/article/details/106843424