写在前面
Iris 从进入 Roadmap 到现在已经过了一段时间了,但是网上相关内容不多,正值 5.2 版本正式发布, Lyra 范例项目也更新了可使用 Iris 的版本
这里根据 Lyra 的配置方式,在作者的项目中启用成功
下面我会将成功启动同步的配置方式列出,再逐一的探索解释每个配置的用途
希望对大家有所帮助
以下内容全部基于 UE 5.2.0 版本
阅读时需有一些 UE 网络同步相关的基础知识
启用 Iris Replication
编译时
uproject 文件中,添加 plugin
1 2 3 4 5 6 7 8 9
| {
"Name": "Iris",
"Enabled": true
}
|
Build.cs 文件中,添加调用
配置
DefaultEngine.ini
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| [/Script/Engine.Engine]
!IrisNetDriverConfigs=ClearArray
+IrisNetDriverConfigs=(NetDriverDefinition="你的NetDriver名",NetDriverName="你的NetDriver名",NetDriverWildcardName="你的NetDriver名*",bEnableIris=true)
[/Script/Engine.NetDriver]
+ChannelDefinitions=(ChannelName=DataStream, ClassName=/Script/Engine.DataStreamChannel, StaticChannelIndex=2, bTickOnCreate=true, bServerOpen=true, bClientOpen=true, bInitialServer=true, bInitialClient=true)
[/Script/IrisCore.PartialNetObjectAttachmentHandlerConfig]
MaxPartCount=4096
[/Script/IrisCore.NetBlobHandlerDefinitions]
+NetBlobHandlerDefinitions=(ClassName=NetRPCHandler)
+NetBlobHandlerDefinitions=(ClassName=PartialNetObjectAttachmentHandler )
+NetBlobHandlerDefinitions=(ClassName=NetObjectBlobHandler)
[/Script/IrisCore.DataStreamDefinitions]
+DataStreamDefinitions=(DataStreamName=NetToken, ClassName=/Script/IrisCore.NetTokenDataStream, DefaultSendStatus=EDataStreamSendStatus::Send, bAutoCreate=true)
+DataStreamDefinitions=(DataStreamName=Replication, ClassName=/Script/IrisCore.ReplicationDataStream, DefaultSendStatus=EDataStreamSendStatus::Send, bAutoCreate=true)
[/Script/IrisCore.NetObjectPrioritizerDefinitions]
+NetObjectPrioritizerDefinitions=(PrioritizerName=Default, ClassName=/Script/IrisCore.SphereNetObjectPrioritizer, ConfigClassName=/Script/IrisCore.SphereNetObjectPrioritizerConfig)
+NetObjectPrioritizerDefinitions=(PrioritizerName=PlayerState, ClassName=/Script/IrisCore.NetObjectCountLimiter, ConfigClassName=/Script/Engine.PlayerStateCountLimiterConfig)
[/Script/IrisCore.NetObjectFilterDefinitions]
+NetObjectFilterDefinitions=(FilterName=Spatial, ClassName=/Script/IrisCore.NetObjectGridFilter, ConfigClassName=/Script/IrisCore.NetObjectGridFilterConfig)
+NetObjectFilterDefinitions=(FilterName=NotRouted, ClassName=/Script/IrisCore.FilterOutNetObjectFilter, ConfigClassName=/Script/IrisCore.FilterOutNetObjectFilterConfig)
[/Script/IrisCore.ReplicationStateDescriptorConfig]
+SupportsStructNetSerializerList=(StructName=GameplayCueParameters)
+SupportsStructNetSerializerList=(StructName=GameplayAbilityTargetData_LocationInfo)
+SupportsStructNetSerializerList=(StructName=GameplayAbilityTargetData_ActorArray)
+SupportsStructNetSerializerList=(StructName=GameplayAbilityTargetData_SingleTargetHit)
+SupportsStructNetSerializerList=(StructName=LyraGameplayAbilityTargetData_SingleTargetHit)
+SupportsStructNetSerializerList=(StructName=NetLevelVisibilityTransactionId)
+SupportsStructNetSerializerList=(StructName=Vector2D)
+SupportsStructNetSerializerList=(StructName=GameplayDebuggerNetPack)
[/Script/IrisCore.ObjectReplicationBridgeConfig]
DefaultSpatialFilterName=Spatial
!FilterConfigs=ClearArray
+FilterConfigs=(ClassName=/Script/Engine.LevelScriptActor, DynamicFilterName=NotRouted)
+FilterConfigs=(ClassName=/Script/Engine.Actor, DynamicFilterName=None))
+FilterConfigs=(ClassName=/Script/Engine.Info, DynamicFilterName=None)
+FilterConfigs=(ClassName=/Script/Engine.PlayerState, DynamicFilterName=None)
+FilterConfigs=(ClassName=/Script/Engine.Pawn, DynamicFilterName=Spatial))
+FilterConfigs=(ClassName=/Script/EntityActor.SimObject, DynamicFilterName=None))
+PrioritizerConfigs=(ClassName=/Script/Engine.PlayerState, PrioritizerName=PlayerState)
+DeltaCompressionConfigs=(ClassName=/Script/Engine.Pawn))
+DeltaCompressionConfigs=(ClassName=/Script/Engine.PlayerState))
|
自定义 Replication Bridge
DefaultEngine.ini
1 2 3 4 5
| [Script/你的NetDriver]
ReplicationBridgeClassName=你的ReplicationBridge类
|
不配置则使用 UActorReplicationBridge
默认使用 ReplicateSubObjectList
DefaultEngine.ini
1 2 3 4 5
| [SystemSettings]
net.SubObjects.DefaultUseSubObjectReplicationList=1
|
如果没有设置这个,则会使用默认版本的 ReplicateSubobjects 函数来同步
因为 Iris 使用 SubObjectReplicationList 来同步,所以如果没有配置的话,会弹出 Ensure
并 Log Warning LogIrisBridge
启动时
命令行参数添加
或者
控制台修改
1 2 3
| net.Iris.UseIrisReplication1
|
或者在 PostEngineInit 回调中加入
1 2 3 4 5 6 7 8 9
| #ifUE_WITH_IRIS
UE::Net::SetUseIrisReplication(true);
#endif
|
启动项目后,开始成功同步
配置类型分析
现在我们来分析配置中用到的类型,从而为学习 Iris 同步的实现方式找一个抓手
配置项同步桥配置 UObjectReplicationBridgeConfig
此类型用于每种不同的类型的过滤和优先级等配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| [/Script/IrisCore.ObjectReplicationBridgeConfig]
DefaultSpatialFilterName=Spatial
!FilterConfigs=ClearArray
+FilterConfigs=(ClassName=/Script/Engine.LevelScriptActor, DynamicFilterName=NotRouted)
+FilterConfigs=(ClassName=/Script/Engine.Actor, DynamicFilterName=None))
+FilterConfigs=(ClassName=/Script/Engine.Info, DynamicFilterName=None)
+FilterConfigs=(ClassName=/Script/Engine.PlayerState, DynamicFilterName=None)
+FilterConfigs=(ClassName=/Script/Engine.Pawn, DynamicFilterName=Spatial))
+FilterConfigs=(ClassName=/Script/EntityActor.SimObject, DynamicFilterName=None))
+PrioritizerConfigs=(ClassName=/Script/Engine.PlayerState, PrioritizerName=PlayerState)
+DeltaCompressionConfigs=(ClassName=/Script/Engine.Pawn))
+DeltaCompressionConfigs=(ClassName=/Script/Engine.PlayerState))
|
从配置内容来看,此类似于 Replication Graph 中初始化各 Actor 的同步节点,同步优先级等内容
用于控制不同类型的对象,在同步的时候同步到哪一些连接,以及同步优先级,压缩等内容
现在进一步查看类型里面的可配置成员
同步轮询周期
用于控制类型查询是否需要同步的帧数周期
1 2 3 4 5 6 7
|
UPROPERTY(Config)
TArray<FObjectReplicationBridgePollConfig> PollConfigs;
|
其中具体配置有
- ClassName:使用此配置的类型,Actor 以及 UObject 不允许配置
- PollFramePeriod:轮询间隔帧数
- bIncludeSubclasses:是否对子类用相同配置
类型过滤器配置
用于控制类型的角色需要同步到哪些连接,例如分块同步
1 2 3 4 5 6 7
|
UPROPERTY(Config)
TArray<FObjectReplicationBridgeFilterConfig> FilterConfigs;
|
其中具体配置有
- ClassName:使用此配置的类型
- DynamicFilterName:过滤器名称
同步优先级配置
用于配置类型同步的优先级,例如距离优先等
1 2 3 4 5 6 7
|
UPROPERTY(Config)
TArray<FObjectReplicationBridgePrioritizerConfig> PrioritizerConfigs;
|
其中具体配置有
- ClassName:使用此配置的类型
- PrioritizerName:使用的优先级控制器名称,Default 会使用默认 spatial prioritizer
增量同步压缩配置
用于控制是否开启类型的增量同步压缩
1 2 3 4 5 6 7
|
UPROPERTY(Config)
TArray<FObjectReplicationBridgeDeltaCompressionConfig> DeltaCompressionConfigs;
|
其中具体的配置有
- ClassName:使用此配置的类型
- bEnableDeltaCompression:是否使用增量压缩(子类都会使用此配置)
默认分块同步的过滤器名称
由此可知,Iris 的默认同步过滤逻辑还是分块
1 2 3 4 5
| UPROPERTY(Config)
FName DefaultSpatialFilterName;
|
需要的 NetDriverChannel 名称
必须要使用的 NetDriverChannel 名称,按注释必须要有这个配置的 Channel 才能让此配置生效,但我没有找到这个逻辑生效的地方
1 2 3 4 5
| UPROPERTY(Config)
FName RequiredNetDriverChannelClassName;
|
配置项过滤器定义 UNetObjectFilterDefinitions
此类型用于配置过滤器列表的定义
1 2 3 4 5 6 7
| [/Script/IrisCore.NetObjectFilterDefinitions]
+NetObjectFilterDefinitions=(FilterName=Spatial, ClassName=/Script/IrisCore.NetObjectGridFilter, ConfigClassName=/Script/IrisCore.NetObjectGridFilterConfig)
+NetObjectFilterDefinitions=(FilterName=NotRouted, ClassName=/Script/IrisCore.FilterOutNetObjectFilter, ConfigClassName=/Script/IrisCore.FilterOutNetObjectFilterConfig)
|
其中
- FilterName :上面 UObjectReplicationBridgeConfig 中用到的过滤器 Name
- ClassName :过滤器类型
- ConfigClassName :过滤器配置的类型
过滤器基类 UNetObjectFilter
过滤器类型用于处理那些对象同步到哪些连接的问题
类型中声明了一些可覆写的空函数
包括初始化,添加连接,移除连接,添加同步对象,移除同步对象,以及过滤相关的内容
我们可以通过实现自己的过滤逻辑来自定义同步规则,类似于 Replication Graph 中的同步节点编写
下面我们看一些具体的实现类型
默认分块同步过滤器 UNetObjectGridFilter
实现目的应该是同 Replication Graph 的分块同步
使用网络裁切距离和位置,确定对象可以被同步的 Grid Cell 列表
过滤所有过滤器 UFilterOutNetObjectFilter
过滤掉所有东西,不同步
不过滤任何内容 UNopNetObjectFilter
不过滤任何东西,全部同步
过滤器配置基类 UNetObjectFilterConfig
这是每种过滤器配置的积累,单独提出一个类型,可以方便的在 DefaultEngine.ini 中进行配置
当前有以下类型
分块同步配置 UNetObjectGridFilterConfig
用于分块同步过滤器,配置分块大小,最大默认同步距离等
过滤任何内容 UFilterOutNetObjectFilterConfig
无需配置,占位,其实无用
不过滤任何内容 UNopNetObjectFilterConfig
无需配置,占位,其实无用
配置项优先级控制器定义 UNetObjectPrioritizerDefinitions
用于定义项目中的优先级控制器
1 2 3 4 5 6 7
| [/Script/IrisCore.NetObjectPrioritizerDefinitions]
+NetObjectPrioritizerDefinitions=(PrioritizerName=Default, ClassName=/Script/IrisCore.SphereNetObjectPrioritizer, ConfigClassName=/Script/IrisCore.SphereNetObjectPrioritizerConfig)
+NetObjectPrioritizerDefinitions=(PrioritizerName=PlayerState, ClassName=/Script/IrisCore.NetObjectCountLimiter, ConfigClassName=/Script/Engine.PlayerStateCountLimiterConfig)
|
其中配置项
- PrioritizerName :配置的优先级处理器名称,用于配置 Replication Bridge
- ClassName :同步器的类型
- ConfigClassName :同步器的配置类型
优先级处理器基类 UNetObjectPrioritizer
用于处理同步对象的优先级
同过滤器基类,有一些空的虚函数,可自行扩展
我们来看一些具体类型
ULocationBasedNetObjectPrioritizer
基于位置的优先级处理器,没有实际处理优先级的部分,只是处理了位置信息的设置,所以只作为基类存在
USphereNetObjectPrioritizer
ULocationBasedNetObjectPrioritizer 的子类
会根据不同个数的 View 位置来进行不同的优先级设置
总体来说是根据和 View 的距离来设置不同的优先级,在一定范围内则优先级高,在外则低,一定距离外非常低
USphereWithOwnerBoostNetObjectPrioritizer
USphereNetObjectPrioritizer 的子类
在其基础上,对于 Connection 的 Owning Object 附加一定的优先级
UNetObjectCountLimiter
根据配置的对象个数来限制同步频率
有两种模式
- RoundRobin : 每次同步轮流同步后面的 N 个对象
- Fill :每次同步的时候,同步最久没有被同步的 N 个对象
UPlayerStateCountLimiterConfig
UNetObjectCountLimiter 的子类,作为同步 PlayerState 的 Limiter
没有具体逻辑,只是对父类的一些参数做特化
优先级处理器配置类 UNetObjectPrioritizerConfig
用于配置优先级处理器的 Config,与过滤器 Config 类似
每种优先级处理器都有其专用的类型
具体的子类此略
配置项数据流定义 UDataStreamDefinitions
Iris 使用数据流 DataStream 的方式来在 Bunch 的基础上传输数据
在这个里面,我们定义项目中使用到的数据流类型
在启用 Iris 之后,数据同步内容均经由 ReplicationDataStream 来传输
其中配置如下
1 2 3 4 5 6 7
| [/Script/IrisCore.DataStreamDefinitions]
+DataStreamDefinitions=(DataStreamName=NetToken, ClassName=/Script/IrisCore.NetTokenDataStream, DefaultSendStatus=EDataStreamSendStatus::Send, bAutoCreate=true)
+DataStreamDefinitions=(DataStreamName=Replication, ClassName=/Script/IrisCore.ReplicationDataStream, DefaultSendStatus=EDataStreamSendStatus::Send, bAutoCreate=true)
|
- DataStreamName :数据流名称
- ClassName : 数据流的类
- DefaultSendStatus:创建时默认的发送状态
- bAutoCreate:是否为每个连接自动创建,如果不是 true 则需要手动创建
配置项 NetBlob 处理器定义 UNetBlobHandlerDefinitions
Iris 在传输上使用数据块 FNetBlob 来传输
每个 NetBlob 会有一个 FNetBlobCreationInfo CreationInfo 来标识其创建 Flag 和 Blob 的类型
以便使用特定的 Blob 处理器来处理
此处配置 NetBlob 的处理器定义列表
1 2 3 4 5 6 7 8 9
| [/Script/IrisCore.NetBlobHandlerDefinitions]
+NetBlobHandlerDefinitions=(ClassName=NetRPCHandler)
+NetBlobHandlerDefinitions=(ClassName=PartialNetObjectAttachmentHandler )
+NetBlobHandlerDefinitions=(ClassName=NetObjectBlobHandler)
|
其中
- UNetPRCHandler 用于处理 RPC
- PartialNetObjectAttachmentHandler 用于处理分块大型 Blob
- UNetObjectBlobHandler 用于处理 NetObjectBlob
使用的同步 Channel DataStreamChannel
Iris 使用 DataSteam Channel 用于同步数据流
所以需要添加配置
1 2 3 4 5
| [/Script/Engine.NetDriver]
+ChannelDefinitions=(ChannelName=DataStream, ClassName=/Script/Engine.DataStreamChannel, StaticChannelIndex=2, bTickOnCreate=true, bServerOpen=true, bClientOpen=true, bInitialServer=true, bInitialClient=true)
|
在 NetDriver 上添加 DataStreamChannel 以开启通道
配置项自定义序列化 UReplicationStateDescriptorConfig
配置 Struct 是否可以使用 Iris 默认的 StructNetSerializer
因为 Iris 在序列化 Struct 的时候,会默认使用 StructNetSerializer
如果需要自定义序列化的话,用从前的 TStructOpsTypeTraits WithNetSerializer Trait 是不行的
需要自己去使用 UE_NET_IMPLEMENT_SERIALIZER 来定义自定义序列化处理器
如果有使用了 WithNetSerializer Trait 自定义序列化的内容,却没有用新的方式去实现的话,会提示 Warning
所以这个配置仅用于使用了 NetSerialize Trait
但是可以使用 Iris 自己创建的同步信息
不想要提示 Warning 的情况
如果提示 Warning 了,可检查对应 Struct 的同步功能是否正常,正常则加入此配置中
否则需要重新写自己的对应类型的 Serializer
配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| [/Script/IrisCore.ReplicationStateDescriptorConfig]
+SupportsStructNetSerializerList=(StructName=GameplayCueParameters)
+SupportsStructNetSerializerList=(StructName=GameplayAbilityTargetData_LocationInfo)
+SupportsStructNetSerializerList=(StructName=GameplayAbilityTargetData_ActorArray)
+SupportsStructNetSerializerList=(StructName=GameplayAbilityTargetData_SingleTargetHit)
+SupportsStructNetSerializerList=(StructName=LyraGameplayAbilityTargetData_SingleTargetHit)
+SupportsStructNetSerializerList=(StructName=NetLevelVisibilityTransactionId)
+SupportsStructNetSerializerList=(StructName=Vector2D)
+SupportsStructNetSerializerList=(StructName=GameplayDebuggerNetPack)
|
结尾
本文通过对成功启动 Iris 的配置的内容分析
揭开了 Iris 机制的冰山一角
后续我将继续分享 Iris 同步的其他内容