UE4网络中UObject创建和销毁
本文中我们专注ContentBlockPayloadHeader和DeleteObject信息.
问
- UObject DS怎么序列化的? (ContentBlockHeader)
- 客户端怎么创建的? (ContentBlockHeader)
- 既不序列化也不创建, 仅仅是持有指针, 怎么映射的? (GUID)
- DS是怎么判断需要根据GUID创建, 而不是映射呢? (ContentBlockHeader)
简述
首先我们看一下ReplicationActor的简要流程, 从下图可以看出, 其一个Actor进行Replication的时候分成三部分: Replicate自身属性+Replicate ActorComponent属性+Replicate SubObject属性. 但是最终都会调用核心函数FObjectReplicator::ReplicateProperties对属性进行处理. FObjectReplicator::ReplicateProperties流程也是四部曲:UpdateChangeList(更新属性:这帧和上一帧对比)+UpdateChangedHistory(清理合并历史变化)+更新CustomDeltaProperty(FastArray类型)+合并UnreliableFunction.
ContentBlockHeader:但是我们今天要讲的不是这些,
而是ContentBlockHeader
. 它又是何方神圣呢?
先思考一个问题:如果标志当前修改的属性归属于哪个UObject?
只有知道当前要修改哪个UObject, 然后根据属性信息找到对应的属性,
即可做出修改处理.
ContentBlockHeader就是做UObject定位的.它能唯一标识当前针对哪个UObject进行修改.
DS序列化
每个需要Replication
的UObject
都会有一个对应的FObjectReplicator
,
在UObject的属性序列化完成之后, 在添加ContentBlockHeader,
将这些属性做归属, 即属于哪个UObject的修改.
ContentBlockHeader信息序列化
这里还要特殊说明一下,
IsNameStableForNetworking
表明客户端是否可以进行创建,
如果为DefaultSubComponent
或者其他的默认就会创建的,
该属性为1, 表明不允许客户端创建, 只能查询绑定.
具体代码解析:
这里还需要注意一点是,
当第一次创建UObject对应的ObjectReplicator
时,
还将Bunch设置为Reliable. 即该Channel第一次同步(Channel可能会反复创建,
没重新创建Channel会重新生成ObjectReplicator
)该属性则Bunch特意设置为ReliableBunch
.
Delete信息序列化
这个很简单, 就是遍历ReplicationMap中所有成员,
针对NotValid
的成员就视作删除, 填充Delete信息.
客户端反序列化
客户端首先解析ContentBlockHeader, 然后才能确定当前修改的是哪个UObject.
创建
如果SubObj为空, 则直接创建.
bStablyNamed
类型只能Find
,
不能Create
.
删除
在解析ContentBlockHeader时候, 发现如果ClassGUID为0, 就视作删除消息, 直接删除对应UObject.
总结
- UObject的创建和删除时通过ContentBlockHeader表示的.
ReplicationObject
的Owner
需要为其创建, Propertie的网络同步, 以及删除负责, 通过ContentBlockHeader
实现. 其他对象则只有其GUID的使用权.- 自定义UObject进行Replicate请参考文章:自定义UObject进行Replicate, 这里不再赘述.
- 如果仅仅使用GUID, 没有ContentBlockHeader, 则只负责映射, 不进行创建, Propertie的网络同步, 以及删除.
- 网络时序引起的逻辑问题, 要用逻辑去矫正. 比如使用A的Replication先到了, 但是还没创建, 则需要逻辑去保证其正确性.
- 其实Delete消息是ContentBlockHeader的特例而已.
- Channel第一次同步某个UObject的时候(创建
ObjectReplicator
), 会将Bunch设置为Reliable.