所有Unreal网游开发者都应该看的文章:使用虚幻引擎4年,再谈UE的网络架构( 五 )


, UObject类型同步属性的更新可能就是在发包前更新的(这块是一个坑 , 要注意) , 具体可以参考我的文章“【《Exploring in UE4》网络同步原理深入(下)】[2]” 中的第五部分第8小节 。

最后 , 我们再总结一些在同步中经常会遇到的问题 。

  1. Client的RPC并不能保证一定在客户端执行 。 在服务器上 , 如果有一个没有connection信息的actor(比如不是同步的 , 完全由AI控制的 。 或者说他的remote role等于none) , 那么他的clientRPC只会在自己的客户端上面执行 。 最后可能造成的后果就是函数调用栈的无限循环进而崩溃 。
  2. beginplay在客户端服务器都会执行 , 如果在beginplay执行另外一个actor的生成 。 可能会触发客户端和服务器都生成一遍自己的actor , 结果客户端存在了两个Actor(一个自己生成的 , 一个服务器生产的) 。 之后在调用RPC的时候很可能会出现RPC执行失败 , 因为本地生成的Actor没有任何connection信息 。
  3. 客户端上对象的Beginplay是可能执行多次 。 在unreal中 , 如果一个actor是服务器创建并同步给客户端 , 那么服务器可以随时关闭这个对象的同步 。 一旦这个对象距离玩家角色非常远或者服务器主动关闭同步 , 客户端上的对象就会被删除掉 。 后期如果玩家又靠近了这个对象 , 那么就会重新同步到客户端 , 再执行一次Beginplay 。 这样某些数据进行两次初始化 , 可能不是我们想要的 。
  4. 我们经常会遇到“游戏状态恢复”的场景 , 比如网络游戏中的断线重连 。 然后你就可能会遇到一些对象在重连后状态不对 , 因为很多对象的变化是通过RPC去做的 , RPC是一次性的 。 当你重连后 , RPC不会再执行一次 , 所以客户端重连的状态与服务器其实是不同的 。 这时候需要使用属性同步来解决问题 , 但是属性回调在断线重连的时候你也并不一定想执行 , 所以要重新审视一下回调函数里面的内容 。
  5. 不要把随时可能被destroyed的对象传进RPC的参数里面 , RPC参数里面没有判断对象是否是合法的 。 如果传递的过程中对象被destroy掉 , 后续可能触发序列化找不到NETGUID的相关崩溃 。
  6. 一般情况下 , onrep回调的执行顺序在同一个character内是严格按照属性的声明顺序的 , 不同actor无法保证先后
  7. 一般回调会调到的函数 , 要注意里面有没有判空return的情况 , 这个时候其他actor的指针是有可能为空的 。
  8. 一个UObject指针类型的数组属性 , 可能会触发多次回调 , 最后一次可以确保所有指针都有值 。
  9. 属性回调执行的前提是客户端与服务器的值不同 , 如果你本地先修改一个值 , 然后服务器修改的与客户端相同 , 那么是不会触发回调的 。 也可以采用DOREPLIFETIME_CONDITION_NOTIFY( AActor, XXX, COND_Custom, REPNOTIFY_Always ); 宏来强制客户端执行
  10. 一般来说当Actor与PC解绑后 , Actor就无法保证RPC的执行了 。 这种情况往往发生在角色死亡后执行unpossess时 , 所以在这时应该注意RPC的执行情况 。
  11. 如果属性没有同步到客户端或者不执行回调 , 注意一下是否使用了自定义的条件属性
  12. 所有设置定时器来判断同步属性是否收到的逻辑都是不规范的 , 一旦服务器或者客户端变卡(一开始没有表现 , 但是随着游戏内容的增加可能出现各种诡异的bug)就可能导致信息丢失

注:

[1]守望先锋架构与网络同步

https://gameinstitute.qq.com/community/detail/114516

[2]《Exploring in UE4》网络同步原理深入(下)

https://zhuanlan.zhihu.com/p/55596030


推荐阅读