https://www.zhihu.com/question/36258781
dota 类游戏是如何解决网络延迟同步的?
像dota类的游戏,dota2,魔兽rpg dota,英雄联盟 等游戏 .他们的同步非常稳定.
英雄联盟中,人物在很短的时间内做的快速操作能很好的同步到其他客户端上显示出来,请问这是如何做到的呢?他们用了怎么样的方法实现的.
英雄联盟中,人物在很短的时间内做的快速操作能很好的同步到其他客户端上显示出来,请问这是如何做到的呢?他们用了怎么样的方法实现的.
3 条评论
按投票排序
按时间排序
17 个回答
主流的同步方案有两种:帧同步和CS同步。
正好这两天在整理这块的东西,就一并分享一下!也希望能够得到一些讨论的机会。
看到评论,补充一个观点: CS和帧同步其实各有有优缺点,并不是某一项方案一定能够取代另一项方案,当游戏类型对实时性要求很高时(比如,实时格斗、体育竞技类游戏(NBA2K)),帧同步可能就是唯一的方案了。
以下是正式答案
1 ArenaServer
2 ArenaServer[预表现层]
3 ArenaClient:ArenaInput+ArenaRender
4 FrameServer
=======一早上都在画这三个图,最后求个赞~~~=======
正好这两天在整理这块的东西,就一并分享一下!也希望能够得到一些讨论的机会。
看到评论,补充一个观点: CS和帧同步其实各有有优缺点,并不是某一项方案一定能够取代另一项方案,当游戏类型对实时性要求很高时(比如,实时格斗、体育竞技类游戏(NBA2K)),帧同步可能就是唯一的方案了。
以下是正式答案
概念定义:
1 ArenaServer
- 战斗核心逻辑及数据所在
- 不关心表现
- 由客户端的输入驱动运行
- CS同步架构里,这个部分是在服务器的
- 帧同步架构里,这个部分是在客户端的。
2 ArenaServer[预表现层]
- 战斗的预表现层,一定在客户端
- 对于一些需要本地预表现的逻辑,如行走。需要先在这里模拟实现。
- ArenaServer的真实数据反馈到预表现层后,会修改本地数据。
- ArenaClient只知道预表现层,并不知道真正的ArenaServer的存在。
- 所以,当游戏要改变同步方案时,Client层并不需要修改。
3 ArenaClient:ArenaInput+ArenaRender
- 负责客户端输入和渲染
- 只与预表现层交互。
4 FrameServer
- 以每秒30次(假设)的频率,收集各个客户端上报上来的ClientInput。
- 组装为FrameInput,广播给各个客户端。
- 即为帧同步的服务器所有逻辑



=======一早上都在画这三个图,最后求个赞~~~=======
楼上大部分答主都提到了帧同步要把逻辑放在客户端。其实我们以前在实现的时候,帧同步一样也是把逻辑放在服务器端的。只不过在客户端接受完毕输入的时候,预先播放动画效果。在同步帧真正到来的时候做结算。
这样的好处就是所有逻辑可控,同时可以非常完美的实现战争迷雾和开全图外挂,因为迷雾里面的单位状态服务器端根本就不会发送到客户端。
当然这样做对网络延迟的要求很高。因此我也来分享一下网络延迟的几个解决方案。
1. 用UDP,推荐使用libenet库。功能强大,可以分channel,支持可靠与否,顺序与否的选项。合理的分channel可以大大提高性能。比如说占比最大的移动包就可以丢到非可靠channel里面。
2. 合包。争取最大的压缩比。
3. 降低移动的封包,在移动上的优化一点点都会对网络提升很大。
4. TCP和UDP双连接。不停换端口。补充说明:不停换端口是客户端的行为。指的是客户端连接断开以后,尝试连接服务器的另一个网关端口。这样可以防止某些网吧或者ISP因为流量控制而断开连接。
5. 全国部署服务器。
这样的好处就是所有逻辑可控,同时可以非常完美的实现战争迷雾和开全图外挂,因为迷雾里面的单位状态服务器端根本就不会发送到客户端。
当然这样做对网络延迟的要求很高。因此我也来分享一下网络延迟的几个解决方案。
1. 用UDP,推荐使用libenet库。功能强大,可以分channel,支持可靠与否,顺序与否的选项。合理的分channel可以大大提高性能。比如说占比最大的移动包就可以丢到非可靠channel里面。
2. 合包。争取最大的压缩比。
3. 降低移动的封包,在移动上的优化一点点都会对网络提升很大。
4. TCP和UDP双连接。不停换端口。补充说明:不停换端口是客户端的行为。指的是客户端连接断开以后,尝试连接服务器的另一个网关端口。这样可以防止某些网吧或者ISP因为流量控制而断开连接。
5. 全国部署服务器。
Source Multiplayer Networking
Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization
Quake Source Code Review
盗图一张,侵删:
以上是几个关于lag compensating 和 client prediction的资料。简单点说就是同步的时候加个时间戳,然后根据时间戳客户端和服务器(wow就有server 的 lag compensating)做一下处理。
以dota2为例,原则就是保证玩家控制自己的角色时尽量流畅准确。至于别人的角色老实说玩家的感觉并没那么敏锐,从转身啊动作前摇后摇啊挤点时间出来就行了,像潮汐的攻击前摇有0.6秒(记得好像是),这一点也不“快速”,你玩潮汐也许会控制时机补刀,别人的潮汐你才不会去老老实实算他的攻击前摇是不是摇够了0.6秒呢。
另外就是网络环境要保证大部分玩家可以满足游戏设计的最大延迟了,没做过运维,这方面不懂,之前看过资料说用靠近玩家的网关服务器加vpn来实现,不过地址也找不到了。
注:
dota2的例子纯属思维实验,实际验证估计要找个网络不好的地方双开试一下。
Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization
Quake Source Code Review
盗图一张,侵删:

以上是几个关于lag compensating 和 client prediction的资料。简单点说就是同步的时候加个时间戳,然后根据时间戳客户端和服务器(wow就有server 的 lag compensating)做一下处理。
以dota2为例,原则就是保证玩家控制自己的角色时尽量流畅准确。至于别人的角色老实说玩家的感觉并没那么敏锐,从转身啊动作前摇后摇啊挤点时间出来就行了,像潮汐的攻击前摇有0.6秒(记得好像是),这一点也不“快速”,你玩潮汐也许会控制时机补刀,别人的潮汐你才不会去老老实实算他的攻击前摇是不是摇够了0.6秒呢。
另外就是网络环境要保证大部分玩家可以满足游戏设计的最大延迟了,没做过运维,这方面不懂,之前看过资料说用靠近玩家的网关服务器加vpn来实现,不过地址也找不到了。
注:
dota2的例子纯属思维实验,实际验证估计要找个网络不好的地方双开试一下。
RTS游戏有很多,可能大家比较熟悉的有Warcraft III (dota)和 StarCraft,
早期西木的沙丘,红色警戒更是rts游戏的鼻祖,带给我们无限的欢乐和回忆。
还有当下比较流行lol与dota2,实际上都是孙子辈的游戏了。
那么他们到底是怎么做到高频操作又同步的呢?
同步机制
假设游戏中A,B两个玩家移动,并同时向对方发出射击指令
如果没有合适的同步机制
那么可能出现的情况有
1 A屏幕显示B已经被杀死,B屏幕显示A已经被杀死
2 或者在瞄准后确打不到对方
图中玩家Plyaer1,Plyaer2在两个不同的客户端,表现出不同效果
因为网络是有延时的,而每个玩家的网络情况都不尽相同。
还有每帧渲染的延迟(早期的计算机性能不够好的时候会出现这个问题)
同步机制最重要的作用就是解决延迟等可能发生不一致的情况。
同步机制的分类
Peer-to-peer模式: 没有服务器,每个玩家互相连接,各自模拟整个流程.典型的lockstep模式
优点:减少主机带来的延时
缺点:容易作弊
Client-Server模式
所有的操作需经过服务器确认后才能进行客户端模拟,如arpg传奇类都是此架构,如果延时高就会有明显的卡顿。
优点:服务器是绝对的权威,可以防止作弊,可以做更多的管理与限制
缺点:服务器变的更复杂,服务器断线,所有玩家断线,属于服务器依赖型。
早期的RTS游戏大多采用Lockstep方案来设计,像罗马帝国,沙丘之类。
Lockstep最早用于军队中
就是说玩家的数据每个时间段同步一次,同步的走。
标准的lockstep模式
1 每个玩家互相连接,整个游戏过程划分成一组turn指令帧,由玩家自我模拟
2 游戏速度取决于网络最慢的那个玩家
3 一个玩家掉线不会影响到其他玩家
什么是Turn?
一个turn可以理解成1个回合,相信大家都玩过回合制游戏吧
只是这个turn非常短,大概100MS-200MS
玩家相互之间发送的指令在每个turn间隔发出
每个玩家只需要接收指令,并在本地播放指令就可以啦
War3如何运算伤害?
玩家到底是发送什么指令到主机,主机到底参与了什么计算呢?
实际上玩家都只需要发送基本的指令如选择单位,移动单位,使用技能1234,点击物品栏1-6,可以通过APM查看软件看到一些基本操作事件
也就是说所有的一切伤害计算都是在本地计算完成的
包括伤害,暴击,命中,刷怪等,只要初始化好随机数种子就可以啦
玩家只是发送操作指令,如点击坐标(0,1, 0),左键框选(100,100,50,50)等
每个玩家都在模拟全部的流程
那么War3到底算不算使用lockstep模式,或者是特殊的client-server?
其实可以通过几个问题判断出
1 非主机玩家卡是否可以影响到其他玩家,如果不会,那么更可能是client-server模式
2 可以通过抓包工具拦截网络数据包的流向,来判断是否是peer to peer的连接方式还是只连接到主机(或通过主机强制掉线方式判断)。
一个外国朋友的回答
个人也认为War3是基于Client-Server的一种的特殊模式,主机肯定需要验证一些逻辑。
主机负责广播每个client的指令
这存在两个问题
第一个问题
还有一种可能,客户端得知之前的turn没有发送成功,把当前这轮的指令和上一轮的指令进行合并,然后一起发出,这样本地客户端就不会有任何的异样了。
例如玩家移动到A后再移动到B
上个turn的指令是移动到A点,但是没有发成功,下个turn的指令先移动到A,再移动到B,这样在客户端就不会有丢失的感觉啦,还是可以正常的模拟而不会影响到其他玩家。
2. 收其他玩家的指令超时,那么属于我们自身网络的问题,如果丢弃必将导致游戏进程不同步,所以服务器必须将他们的turn指令都缓存起来,
或者缓存一部分turn指令集,在我网络稳定的时候,把丢失的那一部分turn指令集发给我,而我只需要下载那个list加快gameupdate就好啦。
有些朋友问到外挂的问题
相信玩过魔兽的人基本都用过,实际上像战争迷雾,显示单位等只会保存一个状态值在内存中,只要定位到内存地址,改一下变量值就好了,一般是服务器是不会检测这个的。
而攻击力,道具数量等,由于大家都需要模拟,你本地修改了,会影响到其他人,程序就会发生蝴蝶效应。
开图挂应该是这类游戏最常见的了。
至于现在非常流行的 Dota2 和 英雄联盟,会额外的加入更多服务器来验证和计算一些外部数据,
但内部原理是一致的,早期的游戏与现在的网游不可同日而语。
欢迎各游戏圈朋友加-Q群 512746636 讨论吹水
早期西木的沙丘,红色警戒更是rts游戏的鼻祖,带给我们无限的欢乐和回忆。
还有当下比较流行lol与dota2,实际上都是孙子辈的游戏了。
那么他们到底是怎么做到高频操作又同步的呢?
同步机制
假设游戏中A,B两个玩家移动,并同时向对方发出射击指令
如果没有合适的同步机制
那么可能出现的情况有
1 A屏幕显示B已经被杀死,B屏幕显示A已经被杀死
2 或者在瞄准后确打不到对方
图中玩家Plyaer1,Plyaer2在两个不同的客户端,表现出不同效果

因为网络是有延时的,而每个玩家的网络情况都不尽相同。
还有每帧渲染的延迟(早期的计算机性能不够好的时候会出现这个问题)
同步机制最重要的作用就是解决延迟等可能发生不一致的情况。
同步机制的分类
Peer-to-peer模式: 没有服务器,每个玩家互相连接,各自模拟整个流程.典型的lockstep模式
优点:减少主机带来的延时
缺点:容易作弊

Client-Server模式
所有的操作需经过服务器确认后才能进行客户端模拟,如arpg传奇类都是此架构,如果延时高就会有明显的卡顿。
优点:服务器是绝对的权威,可以防止作弊,可以做更多的管理与限制
缺点:服务器变的更复杂,服务器断线,所有玩家断线,属于服务器依赖型。

早期的RTS游戏大多采用Lockstep方案来设计,像罗马帝国,沙丘之类。
Lockstep最早用于军队中

就是说玩家的数据每个时间段同步一次,同步的走。
标准的lockstep模式
1 每个玩家互相连接,整个游戏过程划分成一组turn指令帧,由玩家自我模拟
2 游戏速度取决于网络最慢的那个玩家
3 一个玩家掉线不会影响到其他玩家
什么是Turn?
一个turn可以理解成1个回合,相信大家都玩过回合制游戏吧
只是这个turn非常短,大概100MS-200MS
玩家相互之间发送的指令在每个turn间隔发出

War3如何运算伤害?
玩家到底是发送什么指令到主机,主机到底参与了什么计算呢?
实际上玩家都只需要发送基本的指令如选择单位,移动单位,使用技能1234,点击物品栏1-6,可以通过APM查看软件看到一些基本操作事件

也就是说所有的一切伤害计算都是在本地计算完成的
包括伤害,暴击,命中,刷怪等,只要初始化好随机数种子就可以啦
玩家只是发送操作指令,如点击坐标(0,1, 0),左键框选(100,100,50,50)等
每个玩家都在模拟全部的流程
那么War3到底算不算使用lockstep模式,或者是特殊的client-server?
其实可以通过几个问题判断出
1 非主机玩家卡是否可以影响到其他玩家,如果不会,那么更可能是client-server模式
2 可以通过抓包工具拦截网络数据包的流向,来判断是否是peer to peer的连接方式还是只连接到主机(或通过主机强制掉线方式判断)。
一个外国朋友的回答

个人也认为War3是基于Client-Server的一种的特殊模式,主机肯定需要验证一些逻辑。
主机负责广播每个client的指令
这存在两个问题
- 本机(非主机)发出的指令,如果超时或者丢包,是否直接丢弃?
- 其他玩家的指令,主机转发未成功确认,如何处理?
第一个问题
- 如果是本机(非主机)发出的指令超时,可以直接丢弃.(如果不丢弃,其他玩家就必须等待结果,这样会导致挂起,而且会非常频繁,这里还有udp协议容易丢包的原因,但是war3好像并没有经常性的挂起)
还有一种可能,客户端得知之前的turn没有发送成功,把当前这轮的指令和上一轮的指令进行合并,然后一起发出,这样本地客户端就不会有任何的异样了。
例如玩家移动到A后再移动到B
上个turn的指令是移动到A点,但是没有发成功,下个turn的指令先移动到A,再移动到B,这样在客户端就不会有丢失的感觉啦,还是可以正常的模拟而不会影响到其他玩家。
2. 收其他玩家的指令超时,那么属于我们自身网络的问题,如果丢弃必将导致游戏进程不同步,所以服务器必须将他们的turn指令都缓存起来,
或者缓存一部分turn指令集,在我网络稳定的时候,把丢失的那一部分turn指令集发给我,而我只需要下载那个list加快gameupdate就好啦。
有些朋友问到外挂的问题
相信玩过魔兽的人基本都用过,实际上像战争迷雾,显示单位等只会保存一个状态值在内存中,只要定位到内存地址,改一下变量值就好了,一般是服务器是不会检测这个的。
而攻击力,道具数量等,由于大家都需要模拟,你本地修改了,会影响到其他人,程序就会发生蝴蝶效应。
开图挂应该是这类游戏最常见的了。


至于现在非常流行的 Dota2 和 英雄联盟,会额外的加入更多服务器来验证和计算一些外部数据,
但内部原理是一致的,早期的游戏与现在的网游不可同日而语。
欢迎各游戏圈朋友加-Q群 512746636 讨论吹水
魔兽系的是帧同步(真*同步)
LOL据说用的是状态同步, 而不是帧同步, 为的就是在糟糕环境下, 也可以同步
大家都会有一个统一的队列, 在同一个时间点执行同样的操作, 所有人的操作都要进入这个队列, 然后广播给所有人
大概是这样
LOL据说用的是状态同步, 而不是帧同步, 为的就是在糟糕环境下, 也可以同步
大家都会有一个统一的队列, 在同一个时间点执行同样的操作, 所有人的操作都要进入这个队列, 然后广播给所有人
大概是这样
不管是帧同步还是状态同步(楼上所谓cs同步),都需要考虑“低延迟高并发传输系统”,即如何在最短时间内同时把大量数据投递给所有玩家。而libenet却是上个世纪的技术了,无法承当这个重任。所以贩卖一下我的 KCP 传输协议:
GitHub - skywind3000/kcp: KCP
libenet的协议设计是非常落后的,基本上就是90年代教科书上那种标准ARQ协议实现,很难在复杂的网络条件下提供可靠的低延迟传输效果。而KCP具备更多现代传输协议的特点,诸如:
流量换延迟,快速重传,流控优化,una/ack优化等。
基于kcp的开源项目也不少,比如:
不管是何种同步算法,都需要更先进的网络传输技术,而使用libenet这种20年前的老技术,没法很好的解决这一问题,我们需要更加先进现代的传输协议,来达到这个目标。
----
本专业学通信的,闲着没事喜欢折腾各种传输协议。
更多阅读:
reliable_udp_bench_mark: Test reliable udp for situation of realtime pvp game by wireless.
通过KCP协议加速科学上网
--
libenet的协议设计是非常落后的,基本上就是90年代教科书上那种标准ARQ协议实现,很难在复杂的网络条件下提供可靠的低延迟传输效果。而KCP具备更多现代传输协议的特点,诸如:
流量换延迟,快速重传,流控优化,una/ack优化等。
在内网这种几乎理想的环境里直接比较,大家都差不多,但是放到公网上,放到3G/4G网络情况下,或者使用内网丢包模拟,差距就很明显了。公网在高峰期有平均接近10%的丢包,wifi/3g/4g下更糟糕,这些都会让传输变卡。
asio-kcp 的作者对 KCP 与 enet, udt 做过的一次横向评测,结论是KCP比 libenet,udt更适合实时PVP游戏,特别是使用手机的3G,4G网络的情况下:
- ASIO-KCP has good performace in wifi and phone network(3G, 4G).
- The kcp is the first choice for realtime pvp game.
- The lag is less than 1 second when network lag happen. 3 times better than enet when lag happen.
- The enet is a good choice if your game allow 2 second lag.
- UDT is a bad idea. It always sink into badly situation of more than serval seconds lag. And the recovery is not expected.
- enet has the problem of lack of doc. And it has lots of functions that you may intrest.
- kcp's doc is chinese. Good thing is the function detail which is writen in code is english. And you can use asio_kcp which is a good wrap.
- The kcp is a simple thing. You will write more code if you want more feature.
- UDT has a perfect doc. UDT may has more bug than others as I feeling.
基于kcp的开源项目也不少,比如:
- kcptun: 基于 kcp-go做的高速远程端口转发(隧道) ,配合ssh -D,可以比 shadowsocks 更流畅的看 youtube视频。
- kcp-go: 高安全性的kcp的 GO语言实现,包含 UDP会话管理的简单实现,可以作为后续开发的基础库。
- asio-kcp: 使用 KCP的完整 UDP网络库,完整实现了基于 UDP的链接状态管理,会话控制,KCP协议调度等
- v2ray: Shadowsocks 代替者,1.17后集成了 kcp协议,使用UDP传输,无数据包特征。
- dog-tunnel: GO开发的网络隧道,使用 KCP极大的改进了传输速度
不管是何种同步算法,都需要更先进的网络传输技术,而使用libenet这种20年前的老技术,没法很好的解决这一问题,我们需要更加先进现代的传输协议,来达到这个目标。
----
本专业学通信的,闲着没事喜欢折腾各种传输协议。
更多阅读:
reliable_udp_bench_mark: Test reliable udp for situation of realtime pvp game by wireless.
通过KCP协议加速科学上网
--
另,具体同步算法我回答过无数遍了,不再复述:
FPS游戏中,在玩家的延时都不一样的情况下是如何做到游戏的同步性的? - 韦易笑的回答
--
网络同步问题,本质上是因为存在网络延迟而导致的,解决这个问题最终需要在 一致性和操控及时性之间寻求平衡。
追求游戏一致性最高的经典模式是回合制游戏的模式,所有玩家发出命令,等待回合时间到,所有客户端统一执行回合命令。
追求操控的及时性,极致则是fps游戏,例如CS, quake,通过客户端预测,服务器补偿的方式,使玩家的操控可以立即得到反馈,但是会削弱表现的一致性,同时代码复杂度大大上升。
同步问题解决思路分为几个流派:
1:流派一 FPS游戏, quake,cs 流派
FPS类游戏,追求操控及时反馈,每个实体的所有状态存储在一个结构体中,每一帧50ms,从服务器同步一次游戏每个实体的状态到客户端,每帧同步的是客户端和服务器之间状态的差diff, 因此服务器上面需要存储多帧对象状态,以方便和客户端的状态做diff,求出差异,从而同步给客户端。
服务器上角色的动画,移动,hp等状态都是通过这种方式同步。
对于火箭炮等惯性运动物体,则可以通过客户端预测对象的移动。
在服务器上,做子弹碰撞判定的时候,会根据延迟,将对象位置补偿插值到子弹发出的时刻,从而修正结果。
理想的客户端实现,只对服务器发送来的状态做展现,而没有其它逻辑,但是因为网络延迟的存在,单纯展现的客户端,对用户的操作反馈不够及时,对于FPS这种快节奏游戏来讲,是不能接受的,因此需要客户端预测。
参考:
Source Multiplayer Networking
Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization
总结:这个流派将游戏状态,以每50ms帧,离散化存储,在需要的时候在帧之间进行插值,和外插值,来进行预测和补偿。在客户端上为预测,在服务器上为补偿。
这个流派在UDP协议之上,构建网络架构。通过应用层设计,使UDP可以实现可靠性,和顺序性,接着通过不同报文的需求,选择不同的特性组合,降低报文收发的延迟。
2:流派2 RTS游戏, 帝国时代,红色警戒, warcraft3, supreme commander
Gamasutra - 1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond
https://blog.forrestthewoods.com/synchronous-rts-engines-and-a-tale-of-desyncs-9d8c3e48b2be#.4lyc937ax
RTS游戏对操作的响应及时性比FPS低,RTS 一帧时间大概100ms左右.
在RTS游戏,所有客户端每一帧发出命令将会被收集起来,在所有客户端都收到命令之后,才一起执行,例如在 帝国时代中,是隔一帧执行命令,例如,在1000帧的时候,客户端发出命令,在1002帧所有客户端开始执行该命令,
RTS游戏引擎,通常需要做分层设计,下层为模拟层,帧率为10hz,上层为表现层,需要动画,移动尽量光滑。
表现层状态需要和模拟层状态进行同步,表现层需要能够对用户的操作做出比较及时的反馈,因此表现层的实现还是相当复杂的。
RTS游戏网络传输的是命令,或者事件,而不是状态,这是和FPS游戏不同之处,RTS只传输向某个位置移动,攻击某个目标等这种命令,而状态同步是通过游戏引擎自身的确定性来保证的,相同的命令流,通过游戏引擎执行,最终得到相同的结果,这个就是游戏引擎的确定性。
RTS后期进一步发展为曲线化技术,根据存储的离散游戏状态,将游戏对象的整个生命周期,构建成一条曲线,通过调整曲线的时间,甚至可以实现游戏的反向播放。
参考:
https://blog.forrestthewoods.com/the-tech-of-planetary-annihilation-chronocam-292e3d6b169a#feab.ii834tfxl
3:流派三 介于两者之间 MMO, Halo, Unreal
网络同步涉及到三个问题:
复制,状态复制和命令同步;
权属,属性由谁控制?
预测。
网络结构划分为多层,
传输层(TCP, UDP),
信道(可靠,不可靠,顺序),
复制属性的特征,仅服务端,仅客户端,仅自己,其它条件复制,复制处理函数;
游戏业务逻辑层;
状态复制是单向从服务器到客户端;
事件或者RPC是不可靠的,双向;
更多细节参考下面文章
参考:
Game Network Programming
http://downloads.bungie.net/presentations/David_Aldridge_Programming_Gameplay_Networking_Halo_final_pub_without_video.pptx
http://gamedevs.org/uploads/tribes-networking-model.pdf
https://docs.unrealengine.com/latest/INT/Gameplay/Networking/index.html
4:流派4 synchost
服务器做消息中转分发,不做游戏业务逻辑
参考:
http://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2011/06/introductiontosynchost.pdf
5: 时空一致性
参考:
Replication in networked games: Latency (Part 2)
游戏服务器的架构,从传统的单线程,到根据职职责划分的多进程,bigworld模式,再到actor模式。
Building Halo 4, a Video Game, Using the Actor Model
Building the Halo 4 Services with Orleans
最后,根据前面的分析可以做一种简化的网络模型:
大部分协议使用简单的可靠性传输;
客户端发起的命令,等服务器确认之后再执行事件;
服务器发送的同步状态广播给所有客户端都是一样的;
客户端两个层次,模拟层和表现层
使用RTS模式定帧同步命令和状态
降低发送者的速度,加速接受者的速度
追求游戏一致性最高的经典模式是回合制游戏的模式,所有玩家发出命令,等待回合时间到,所有客户端统一执行回合命令。
追求操控的及时性,极致则是fps游戏,例如CS, quake,通过客户端预测,服务器补偿的方式,使玩家的操控可以立即得到反馈,但是会削弱表现的一致性,同时代码复杂度大大上升。
同步问题解决思路分为几个流派:
1:流派一 FPS游戏, quake,cs 流派
FPS类游戏,追求操控及时反馈,每个实体的所有状态存储在一个结构体中,每一帧50ms,从服务器同步一次游戏每个实体的状态到客户端,每帧同步的是客户端和服务器之间状态的差diff, 因此服务器上面需要存储多帧对象状态,以方便和客户端的状态做diff,求出差异,从而同步给客户端。
服务器上角色的动画,移动,hp等状态都是通过这种方式同步。
对于火箭炮等惯性运动物体,则可以通过客户端预测对象的移动。
在服务器上,做子弹碰撞判定的时候,会根据延迟,将对象位置补偿插值到子弹发出的时刻,从而修正结果。
理想的客户端实现,只对服务器发送来的状态做展现,而没有其它逻辑,但是因为网络延迟的存在,单纯展现的客户端,对用户的操作反馈不够及时,对于FPS这种快节奏游戏来讲,是不能接受的,因此需要客户端预测。
参考:
Source Multiplayer Networking
Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization
总结:这个流派将游戏状态,以每50ms帧,离散化存储,在需要的时候在帧之间进行插值,和外插值,来进行预测和补偿。在客户端上为预测,在服务器上为补偿。
这个流派在UDP协议之上,构建网络架构。通过应用层设计,使UDP可以实现可靠性,和顺序性,接着通过不同报文的需求,选择不同的特性组合,降低报文收发的延迟。
2:流派2 RTS游戏, 帝国时代,红色警戒, warcraft3, supreme commander
Gamasutra - 1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond
https://blog.forrestthewoods.com/synchronous-rts-engines-and-a-tale-of-desyncs-9d8c3e48b2be#.4lyc937ax
RTS游戏对操作的响应及时性比FPS低,RTS 一帧时间大概100ms左右.
在RTS游戏,所有客户端每一帧发出命令将会被收集起来,在所有客户端都收到命令之后,才一起执行,例如在 帝国时代中,是隔一帧执行命令,例如,在1000帧的时候,客户端发出命令,在1002帧所有客户端开始执行该命令,
RTS游戏引擎,通常需要做分层设计,下层为模拟层,帧率为10hz,上层为表现层,需要动画,移动尽量光滑。
表现层状态需要和模拟层状态进行同步,表现层需要能够对用户的操作做出比较及时的反馈,因此表现层的实现还是相当复杂的。
RTS游戏网络传输的是命令,或者事件,而不是状态,这是和FPS游戏不同之处,RTS只传输向某个位置移动,攻击某个目标等这种命令,而状态同步是通过游戏引擎自身的确定性来保证的,相同的命令流,通过游戏引擎执行,最终得到相同的结果,这个就是游戏引擎的确定性。
RTS后期进一步发展为曲线化技术,根据存储的离散游戏状态,将游戏对象的整个生命周期,构建成一条曲线,通过调整曲线的时间,甚至可以实现游戏的反向播放。
参考:
https://blog.forrestthewoods.com/the-tech-of-planetary-annihilation-chronocam-292e3d6b169a#feab.ii834tfxl
3:流派三 介于两者之间 MMO, Halo, Unreal
网络同步涉及到三个问题:
复制,状态复制和命令同步;
权属,属性由谁控制?
预测。
网络结构划分为多层,
传输层(TCP, UDP),
信道(可靠,不可靠,顺序),
复制属性的特征,仅服务端,仅客户端,仅自己,其它条件复制,复制处理函数;
游戏业务逻辑层;
状态复制是单向从服务器到客户端;
事件或者RPC是不可靠的,双向;
更多细节参考下面文章
参考:
Game Network Programming
http://downloads.bungie.net/presentations/David_Aldridge_Programming_Gameplay_Networking_Halo_final_pub_without_video.pptx
http://gamedevs.org/uploads/tribes-networking-model.pdf
https://docs.unrealengine.com/latest/INT/Gameplay/Networking/index.html
4:流派4 synchost
服务器做消息中转分发,不做游戏业务逻辑
参考:
http://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2011/06/introductiontosynchost.pdf
5: 时空一致性
参考:
Replication in networked games: Latency (Part 2)
游戏服务器的架构,从传统的单线程,到根据职职责划分的多进程,bigworld模式,再到actor模式。
Building Halo 4, a Video Game, Using the Actor Model
Building the Halo 4 Services with Orleans
最后,根据前面的分析可以做一种简化的网络模型:
大部分协议使用简单的可靠性传输;
客户端发起的命令,等服务器确认之后再执行事件;
服务器发送的同步状态广播给所有客户端都是一样的;
客户端两个层次,模拟层和表现层
使用RTS模式定帧同步命令和状态
降低发送者的速度,加速接受者的速度
类似星际,魔兽:选择一个客户端作为服务器。
客户端和服务器的通信包括确认部分,完全确认完毕后再进行操作。一般每秒同步10次。任何一个客户端cpu负载满后,都会拖慢所有人的帧率。
类似dota2:可以选择一个客户端起服务器,也可以选择官网的独立服务器
客户端和服务端的通信不包括确认,服务器只管处理已经接受的指令,只管发送处理完毕的同步信息。同样每秒同步10次多数。除非服务器cpu负载满以后影响每秒同步次数从而拖慢游戏甚至不拖慢游戏仅仅影响准确率,其他情况下,只有网速慢的人会有操作误差(譬如lag)
客户端和服务器的通信包括确认部分,完全确认完毕后再进行操作。一般每秒同步10次。任何一个客户端cpu负载满后,都会拖慢所有人的帧率。
类似dota2:可以选择一个客户端起服务器,也可以选择官网的独立服务器
客户端和服务端的通信不包括确认,服务器只管处理已经接受的指令,只管发送处理完毕的同步信息。同样每秒同步10次多数。除非服务器cpu负载满以后影响每秒同步次数从而拖慢游戏甚至不拖慢游戏仅仅影响准确率,其他情况下,只有网速慢的人会有操作误差(譬如lag)
我猜题主是想问,“那么光辉绚烂的战场,数据量想必是个天文数字,凭什么能用普通的宽带毫无迟滞地愉快玩耍”。
办法就是: 压缩流量,只传递实际操作。
比如牛头跳大,非常宏大的场面,客户端之间同步的内容仅仅是:
题主可以估算一下10个APM300的高手能造成的数据流量大约是多少。网络传输优先级足够高的话,300K的带宽也基本足够了。
办法就是: 压缩流量,只传递实际操作。
比如牛头跳大,非常宏大的场面,客户端之间同步的内容仅仅是:
- 跳:time=5:31.1234,player=1,operation=物品栏1,target=(345.55,8272.44)
- 大:time=5:31.1456,player=1,operation=C
- 看,我的跳刀出得很早吧?
题主可以估算一下10个APM300的高手能造成的数据流量大约是多少。网络传输优先级足够高的话,300K的带宽也基本足够了。
一般RTS游戏里帧同步比较多一些,例如:WAR3,帝国时代等。
帧同步的游戏也利于做录像回放。所以你会发现WAR3的录像文件都特别小,因为文件里记录的都是玩家操作的数据:鼠标点击事件,技能按键事件等。
帧同步的游戏也利于做录像回放。所以你会发现WAR3的录像文件都特别小,因为文件里记录的都是玩家操作的数据:鼠标点击事件,技能按键事件等。
war3使用的是lockstep,这个是明确的,包括星际争霸,还有风暴英雄,从他重连的时候重头开始计算基本可以推断处理都是用此方式。
lol是状态同步的,即状态变化的时候发送消息,协议会更加复杂,不过断线重连也会更加好做。
补充下后续答案,早期绝大部分游戏都是每段时间发送输入数据,由特定主机或者专属服务器转发所有输入帧数据,然后每个客户端需要这个数据才能跑每个帧,主要原因是rts游戏单位数量太多了,其他方案都没这个简单方便。这个方案即lockstep。
当然这种方案在每个游戏中都有不一样的实现,比如帝国时代,主机转发输入数据的频率是由网络最烂的客机决定的,即主机需要收到所有客机数据数据才转发,而在魔兽争霸中并不是这样的,服务器到一定时间必然转发所有输入数据,如果没有就假设你没有输入。
这个方案得细节还有很多,可以查询网络,比如如何定好那个固定时间时长,保证所有机器计算确定性,做好缓冲,加速等。
对于大型网络游戏来说,就往往不是这么做的了,这里就包含了楼主说的dota2和lol,找时间再细聊。
lol是状态同步的,即状态变化的时候发送消息,协议会更加复杂,不过断线重连也会更加好做。
补充下后续答案,早期绝大部分游戏都是每段时间发送输入数据,由特定主机或者专属服务器转发所有输入帧数据,然后每个客户端需要这个数据才能跑每个帧,主要原因是rts游戏单位数量太多了,其他方案都没这个简单方便。这个方案即lockstep。
当然这种方案在每个游戏中都有不一样的实现,比如帝国时代,主机转发输入数据的频率是由网络最烂的客机决定的,即主机需要收到所有客机数据数据才转发,而在魔兽争霸中并不是这样的,服务器到一定时间必然转发所有输入数据,如果没有就假设你没有输入。
这个方案得细节还有很多,可以查询网络,比如如何定好那个固定时间时长,保证所有机器计算确定性,做好缓冲,加速等。
对于大型网络游戏来说,就往往不是这么做的了,这里就包含了楼主说的dota2和lol,找时间再细聊。
匿名用户
你google 搜索“帧同步 游戏”可以得到一堆参考,这种游戏的客户端同步几乎没啥技术难度了,唯一困难的部分是服务器的低延迟响应,国内网络延迟的平均时间是200ms,这个延迟对于这种类型的游戏还是有点高的,所以降低延迟是关键,要做到双线50ms左右的延迟,这涉及到机房、服务器效率等问题。
帧同步这种过时的玩意没什么必要去看,之所以有是因为帧同步做起来简单而已,因为那个年代的外网环境没那么好,解决局域网同步帧同步就能完成。
看看新出的游戏,都一律是服务端逻辑,谁也不会傻不拉叽把逻辑丢客户端了。
客户端就管两件事
1.发送玩家操作信息
2.响应服务端的同步数据,并表现到客户端。
当然不可能所有数据都往下发,基于数据策略,也就有所谓的约定事件逻辑,用于减少数据量。
服务端要做的事情就多了,因为客户端不管复杂逻辑,所有的逻辑都在服务端。按mvc模式的话,mc都在服务端。没客户端什么事了。
另外说一个全球的问题,所谓的全球玩家是不可能都连一个服务器的,这样必然延迟高,连入最近的网关服务器,然后通过内部服务器转发可以保证大部分的玩家延迟一致,毕竟机房和机房间的延迟是相当低的
看看新出的游戏,都一律是服务端逻辑,谁也不会傻不拉叽把逻辑丢客户端了。
客户端就管两件事
1.发送玩家操作信息
2.响应服务端的同步数据,并表现到客户端。
当然不可能所有数据都往下发,基于数据策略,也就有所谓的约定事件逻辑,用于减少数据量。
服务端要做的事情就多了,因为客户端不管复杂逻辑,所有的逻辑都在服务端。按mvc模式的话,mc都在服务端。没客户端什么事了。
另外说一个全球的问题,所谓的全球玩家是不可能都连一个服务器的,这样必然延迟高,连入最近的网关服务器,然后通过内部服务器转发可以保证大部分的玩家延迟一致,毕竟机房和机房间的延迟是相当低的
无非就是两个方向,逻辑放在客户端(帧同步)和逻辑放在服务端(cs同步),如果是帧同步的话,服务器只负责转发用户操作数据,并且加时间戳,客户端接收到操作数据后进行逻辑计算。这样可以保证每个客户端的游戏逻辑是相同的。如果是cs同步的话,服务器接收操作数据,然后进行逻辑计算,将计算后的结果发送客户端。
匿名用户
简单一句话概括那就是幕前显示与幕后计算分离不就结了?
有一次听ob直播,说早些年龙神8老板他们打职业的时候,eh有一种黑科技可以降低线下比赛的延迟,具体怎么做没讲,后来8老板也承认了。