0%

UE网络同步模块

UE移动组件以及相关网络同步

UE网络同步

网络游戏万事通(基本概念+引擎技术栈+底层原理) | Coding中。。。栏目内从新人的角度讨论了游戏通用网络同步技术的基础概念以及部分历史发展,其中涉及到的虚幻相关的网络同步技术只涉及到了UE中的“通用复制系统”的最基础部分,由于工作的原因,长时间处于研究UI系统、脚本系统和Slate相关概念,已经长时间和之前想走的GamePlay方向渐行渐远,现在再重看UE的网络模块,发现UE为此做了相当多的处理,例如复制图表系统Iris复制系统以及移动同步组件等等,所以现在抽时间研究研究文档,并稍微看下代码,为之后做Demo打下基础。

 

基础概念

首先是网络模式NetMode,虚幻引擎中定义了一个游戏会话的四种模式:

  • NM_Standalone:可以直接理解成单机,理论上也有服务器逻辑,但不允许客户端连接,也可以考虑多人本地游戏。
  • NM_DedicatedServer:既DS连接,服务器单独运行,没有客户端的图形、声音、输入等逻辑,允许客户端连接。
  • NM_ListenServer:既LS连接,服务器和客户端同时运行在一个会话中,允许其他客户端连接,优点是成本低,不需要额外的服务器会话,缺点是存在竞技公平性问题,且不适合网络负载高的游戏。
  • NM_Client:连接到远程的客户端,没有服务端逻辑。

复制:属性复制,Actor复制,Rpc调用。一般情况下,启用复制后,actor的创建,销毁,移动都会自动处理,但其他功能需要手动处理,例如属性、函数、组件与子对象(及其属性函数等)。

在虚幻的概念中,通常这些功能需要客户端自行运行:

  • 网格
  • 材质
  • 动画蓝图
  • 粒子系统
  • 声音
  • 物理对象

这些功能一般由同步过来的某个属性来进行驱动。

Actor复制中的一些概念:休眠(Dormancy)优先级(Priority)相关性(Relevancy)

pZiueAg.png

 

网络连接中心、连接、网络通道

NetDriver存有所有Connection的引用,对于服务器来说,是一个ServerConnection,对一个客户端来说,是一个ClientConnection,每当有一个客户端连接到服务器,就相当于NetDriver多了一个ClientConnection。客户端开始再服务器上运行时,客户端的玩家控制器会立即同步到一个Pawn以控制。

Actor的相关性值哪些Connection来同步这个Actor的复制,对于玩家控制器来说,只和自己的Connection有高相关性,所以只有自己会收到自己的玩家控制器的同步(bOnlyRelevantToOwner)。

Actor可以通过GetOwner获取其“所有者”,如果某些Actor的所有者为控制器,那么这个Actor的关联Connection为控制器的Connection。

 

网络休眠

官方文档上提示可以手动设置Actor休眠来让他不进入复制流程中。一般情况下,考虑不可见的Actor或者某些时段下对玩家影响不大的Actor进行休眠可以保证网络性能和流畅度。

 

优先级

如果UE的网络传输流量达到饱和,那么就会触发优先级机制。

优先级确定逻辑:AActor初始值为1.0,APawn初始值为2.0,APlayerController初始值为3.0,越大意味着分配的带宽越多。虚幻引擎中的Actor优先级 | 虚幻引擎 5.7 文档 | Epic Developer Community

 

相关性

 

Actor复制流程

网络复制的“Main”函数为UNetDriver::ServerReplicateActors(每帧调用),它会收集并决定哪些Actor进行复制,并发送他们“被改变的属性”,然后调用UActorChannel::ReplicateActor将Actor复制到特定通道。

int32 UNetDriver::ServerReplicateActors(float DeltaSeconds){
    ...
    TArray<FNetworkObjectInfo*> ConsiderList;
    ConsiderList.Reserve( GetNetworkObjectList().GetActiveObjects().Num() );

// Build the consider list (actors that are ready to replicate)
ServerReplicateActors_BuildConsiderList( ConsiderList, ServerTickTime );
TSet&lt;UNetConnection*&gt; ConnectionsToClose;
...
for ( int32 i=0; i &lt; ClientConnections.Num(); i++ )
{
    UNetConnection* Connection = ClientConnections[i];
    //1、对Connection内所有Actor做属性检查,例如“休眠”“每帧更新”等等属性值。
    //2、对Connection内所有Actor做相关性检查,按照优先级排序。
    //3、进一步做筛选,例如是否有对应通道等。
    //4、如某连接没加载需要同步的Actor所在关卡,那么不会同步此Actor,还会关闭通道。
    //5、每秒都会调用`AActor::IsNetRelevantFor`检查相关性,不相关就关闭通道,相关则开启通道
    //6、满足条件的调用UActorChannel::ReplicateActor将其复制到连接里面
}

}

Role和RemoteRole

例如有一个客户端控制的角色和网络同步的NPC,那么这两个Actor的Role都是ROLE_Authority,意思是引擎负责这两个actor复制;并且客户端角色的RemoteRole 是 ROLE_AutonomousProxy,NPC是ROLE_SimulatedProxy,意思是客户端角色为会用一些真人的输入内容来加上其他推算来算出最终信息,而NPC为完全模拟,会通过上次获得的速率进行移动推算,这个推算会保证在更新间歇进行本地移动模拟来保证运动的丝滑。

 

属性复制

  • Replicated
  • ReplicatedUsing(带回调)
  • NotReplicated(例如某个结构体中用这个)

 

RPC

 

Iris复制系统

虚幻引擎中的Iris简介 | 虚幻引擎 5.7 文档 | Epic Developer Community

 

复制图表

虚幻引擎Replication Graph | 虚幻引擎 5.7 文档 | Epic Developer Community

 

UE移动组件

这一部分文档介绍的非常少。

移动的本质:移动基础组件的坐标移动,一般都把胶囊体设置为移动基础组件,可以设置成别的,但至少要是继承USceneComponent组件。

img

玩家输入流程:InputComponent组件绑定的一个按钮,响应时直接调用到Pawn的AddMovementInput接口,再调用到UPawnMovementComponent::AddInputVector函数。一次移动输入相当于设置移动加速度,然后会根据移动模式、速度和时间来算出最终位置。

UCharacterMovementComponent

MovementMode

Walking

img

Falling

Jump

Swiming

Flying

移动同步的流程

参考:(99+ 封私信 / 70 条消息) UE4移动同步流程 - 知乎

要分为“自治移动(ROLE_AutonomousProxy)”和“模拟移动(ROLE_SimulatedProxy)”,前者就是类似客户端自己操作的角色,后者就是要同步给其他客户端的角色。针对DS服务器来说,所有的角色都是需要通过模拟过来的,包括自治移动。

自治移动

pZiGRXj.png

每帧都会将新的数据通过RPC传给服务端,同时也会进行模拟移动。其中SavedMove列表在弱网的情况下超过96个会自动清理。

图片歧义1:如果收到ClientAdjustPositon后,会清除服务器回传包的时间戳之前的包,后面的包不会清除,并在这个地方进行重播。

图片歧义2:标明“现在”的时间戳在图中示意为客户端的时间戳,收到包的时间也确实是“现在”,但收到的包体时间戳可能是过去的任意一个时间点,

模拟移动

pZiGzAx.png

模拟移动的时候,实际位置胶囊体和Mesh是分开的。