MMO中与服务器的低流量客户端同步


22

我正在实施MMO,玩家将在其飞船上的太空中飞行,并使用箭头键控制它并与其他玩家合作。

我想实现它,以便玩家可以躲避火箭或其他东西躲避飞船,所以我试图使用与服务器使用相同的世界模拟算法来预测客户端的整个游戏状态。该游戏世界是用C#编写的,将直接在客户端内部调用(在Unity3D上编写),并通过C ++服务器上的CLR(在Linux下)调用。通过UDP连接。

问题是如何在单个地图上维护1000名玩家(不包括所有其他游戏对象,生物……):假设我将:

  • 每秒将服务器与客户端同步50次
  • 向每个客户发送他能够看到的游戏对象(和玩家)的状态(在一定范围内)
  • 必须在视野范围内向每个玩家发送100个对象
  • 每个游戏对象必须平均发送50个字节(ID,x,y坐标,旋转,状态...)

因此,它将需要具有这样的网络带宽:1000(客户端)* 50(每秒的次数)* 100(要发送给每个播放器的对象)* 50(每个对象的字节数)=每秒250000000字节!不可能!

是否可以通过某种方式降低此值?例如,让客户端完全模拟他们的游戏世界(很长一段时间),然后仅向其他客户端发送输入并同步游戏世界,比如说,每隔几秒钟,但这会由于浮动计算而导致奇怪的不同步问题。

无论如何,如何以通用方式对此类游戏进行编程?谢谢。


1
我只发送有关对象的逻辑信息(世界的位置,当前状态(一个字节)等等)-没有图形。
斯拉夫(Slav)

1
@Slav:太好了!所有这些变化让我想起了我的ASM编程时代。
Randolf Richardson 2011年

1
为什么不“今天”?:)当我在AS3,Java,Lua,C#上编写并且面对如此糟糕的性能时,我想念C ++,并且记得有关ASM的知识。
斯拉夫(Slav)

1
@Slav:嘿,我最近没有做太多ASM。这些天对我来说,大多数事情都使用Java和Perl(主要是mod_perl2),但是我也非常喜欢这些语言。
兰道夫·理查森

2
@Slav,您写道:“当我在AS3,Java,Lua,C#上编写时,面对如此糟糕的性能,我想念C ++,并且回想起了ASM。” 您应该学习如何正确使用Lua和C#,也许您会发现性能降低了。另外,抱怨(据说)最快的脚本语言充其量是唯一的……这是关于实时人类基因组分析的游戏吗?
Raine

Answers:


20

每秒仅需要大约30次更新(甚至更少,也许10或20)。插入客户端移动对象的位置。通常,仅在真正需要时才发送数据。在《魔兽世界》中,您可能会从同组的玩家那里收到比同位置的玩家更多的更新。另外,如果另一个玩家离您很远,您每秒不会收到太多关于他的更新。

然后,仅在每个玩家连接时向其发送一个完整的快照。之后,仅发送游戏对象的更改。如果未发生任何更改,请不要发送。

然后,大量使用BitVectors,但是您可以调用它们来减少不需要的数据量!示例:您也可以尝试仅使用一个字节(在0到1或-1到1的范围内)写一个浮点数,因此只有256或128个不同的值。但是由于插值,玩家不会注意到任何剧烈的运动。

在LidgrenLibrary上查看有关如何压缩数据的示例:http : //code.google.com/p/lidgren-network-gen3/wiki/Optimization

下一步:尝试减小玩家移动时的视野半径,并且仅在该时间内传输重要信息。然后当他们停止时,再次增加其视线半径。您可以使用空间哈希系统或bsp树来减少查找“范围内”对象的开销。对于以下主题,这是一本好书:http : //en.wikipedia.org/wiki/Collision_detection

也压缩数据YOURSELF只有自己知道关于数据结构和在数据中的时间相干性(其可以并且应该被利用)。应该使用诸如Bzip2,Deflate之类的通用算法,但只能作为压缩的最后阶段!

此外,对于非游戏关键信息,您还可以采用其他P2P技术。示例:一个播放器播放“ hello”动画。(只是一种图形效果)播放器将此信息发送到服务器,但是服务器不会将信息中继给其他播放器。而是由播放器本身将此非关键效果发送给范围内的其他客户端。

编辑(由于评论):

减少每个播放器每秒平均位数的其他方法:

  1. 您写道,您发送“对象未更改”。没有理由这样做。如果您担心数据包丢失(并因此而使仿真不同步),请考虑以下事项:在每个固定的时间步长(例如100、200、300、400 ...),对仿真状态进行哈希处理并将其发送到服务器。服务器确认或发送回所有数据的完整快照。

  2. 对于诸如火箭甚至是玩家之类的事物,您不仅可以使用插值法,而且可以采用外推法,以使模拟更加逼真。示例“火箭”:无需使用“现在位于位置x”之类的消息进行更新,只需发送一次包含以下内容的消息即可:“火箭产生:position(vector),时间(产生火箭的模拟步骤),速度(向量)”。因此,您甚至不必包括旋转,因为尖端将始终处于“速度”方向。

  3. 在一条消息中组合多个命令,并且永远不要发送小于16-20字节的消息,因为udp标头将大于消息本身。另外,不要发送大于协议MTU的数据包,因为碎片会减慢传输速度。


哦,一个好主意是比其他对象更频繁地更新某些对象,使用P2P,降低浮点精度,仅发送更改(这对我来说并不重要,因为我打算定期同步对象,但是“对象未更改”是信息太)。经过所有这些修改,整个图片看起来更加逼真!
斯拉夫(Slav)

1
发送“对象未更改”类型通知可能是一种有用的测试技术,您可以在忙碌的时候查看玩家在游戏时的表现,因为它有可能对处理以及网络提出要求,但是还有比这更好的解决方案(例如,创建一个控制实际游戏角色的独立守护程序,然后在不同计算机上多次运行该守护进程)。
Randolf Richardson 2011年

5

这是两种方法:

首先:
切换到确定性物理学,向玩家发送播放器命令,人工智能动作,可见的对象以及所有无法确定的客户端。这必须包括非命令,这是确认,直到某个时间点,只有已发送和接收的命令才适用。

客户端必须同时运行两个或三个模拟。
1:每当缺少下一步数据时都将暂停。
2:继续使用猜测数据,并提供用于渲染的状态。3:每当No 1停止时,此模拟都会复制No 1的状态,赶上当前时间并接管No 2,然后将其丢弃。

如果赶上的速度足够快,您可以忽略2号和3号之间的差异,而立即丢弃旧数据。

第二:
不要使用确定性物理学,与上面相同,但是每几秒钟发送一次“全帧”。您可以轻松地完全省去转移子弹等临时性物品。

在这两种情况下,您可能都想对客户端预测有人死亡的警告保持警惕,看到对手爆炸很愚蠢。

加上+1进行数学运算,太多的人无法进行简单的资源使用估算。


2
“确定性物理学”是否意味着我不能使用浮点值或不同的模拟步骤?我想知道是否会发生严重的不同步,例如,火箭会从客户端上的某个敌人炮塔越过但会在服务器上击中它(由于某些浮点误差),这将导致玩家继续与该炮塔作战,直到下一个传入服务器的同步数据包为止(几秒钟)。
斯拉夫(Slav)

3
它表示整数和固定的时间步长。从理论上讲,您可以模拟浮点数来表现,但是使用整数更简单。对于丢失的导弹示例,您已经有所了解,如果您使用非确定性的物理方法,最好让服务器完全处理死亡问题,并迅速传递死亡/毁坏的案例。
aaaaaaaaaaaaaa

5

先问几个问题。

“火箭或其他东西”是聪明的还是愚蠢的?如果它们很笨,那么您需要的只是时间戳记,起火点和模拟其路径的向量。如果他们很聪明,他们有多聪明?您能在发生火灾时计算它们将要命中或未命中吗?如果是这样,您可以在客户端上模拟整个路径。(“在T13时,导弹将击中飞船,因为比赛失去了闪避投掷/射击者获得了致命一击。”)

总的来说,虽然几乎没有理由:A)时钟频率为50Hz,(大多数射击者逃脱了15-20,而MMO则更少。)B)每帧发送完整状态。(导弹在太空中的旋转是否重要?或者您是否可以假设导弹的“前部”是沿着其传播的方向定向的?)

花时间进行预测和内插,您将看到带宽骤降。我从事的一个项目的更新速率为10Hz,我认为对象状态表示为14个字节。(压缩所有内容!我相信我们使用6位来定义围绕x平面的旋转,然后再使用6位用于在x平面上方/下方倾斜,这看起来与发送实际的旋转矩阵/四元数没有区别。)

您可以做的另一件事是确定对象的优先级。显示,相关集合中可能有100个对象,但是您知道他在服务器上的视锥吗?如果他不认为某些内容,可以将其更新频率降低一个数量级吗?

一般的想法不是在客户端上进行完美的模拟,这是不可能的,其目的是制作一个有趣的游戏,玩家不会注意到这不是完美的模拟。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.