客户端预测如何工作?


33

我已经阅读了Valve + Gafferon和Google的数百页内容,但是出于任何原因,我都无法理解客户预测。

据我了解,基本问题是:

  • 客户端A在以下位置发送输入 T0
  • 服务器在以下位置接收输入 T1
  • 所有客户都在以下位置收到更改 T2

T2然而,使用客户预测,客户端A现在是在合适的位置来T4

在预测服务器将接受移动请求时,如何确保客户端A不在服务器之前?显然,它们一直都在前进,这导致返回到服务器上次看到它们的位置。经过我尝试的所有更正,当您停止时这仍然很明显,因为服务器在您身后停止了

Answers:


35

我为此写了一系列文章。它基于您在其他地方阅读过的相同思想,但是以非常详细且(希望如此)易于理解的方式进行了解释。

特别是有关客户端预测的文章就是这一篇


优秀文章:-)我很想看系列的第四部分。作为一个小建议,在每篇文章末尾链接到下一部分肯定会改善导航。
OR Mapper

5
@ORMapper-我终于写了第四篇文章!gabrielgambetta.com/fpm4.html
ggambett 2013年

您的文章系列的荣誉:-)非常有帮助,谢谢:-)
或Mapper

所有谈论使用存储的快照重建过去的文章(我都能找到)都以拍摄为例。这也适用于运动吗?我可以想象,如果其他玩家能够相互碰撞,那么重新进行运动模拟可以为他们带来很大的不同。假设有两个玩家互相对抗,其中一个停止向碰撞点移动几步。该停止命令由于滞后而迟到,因此如果我们重新模拟世界,则两个玩家的位置将非常不同
Lope

这是一个有趣的问题。不幸的是,我没有确切的答案。我想这取决于动作对游戏的关键程度。你只是撞到别人,什么也没发生?在这种情况下,服务器可能不在乎,它被视为预测错误(我们都已经看到它发生在阻塞点上,对吧?)。您会杀死其他玩家吗?在这种情况下,正确设置更为重要,可能值得重新模拟。请注意,在某些时候,您需要将某些数据包丢弃为“过旧”,否则您可能会随时从t = 0重新模拟。
ggambett 2013年

4

我实际上尚未实现此操作(因此可能有一些我没有立即看到的问题),但我想我会尽力的。

您正在说的是这件事:

客户端A在T0发送输入

服务器在T1接收输入

所有客户都在T2收到更改

但是,在T2,使用客户端预测,客户端A现在处于适合T4的位置。

考虑服务器时间可能会很有用。它(可能)与插值的工作原理非常相似。

每个命令都随服务器时间一起发送。该服务器时间是在比赛开始时通过查询服务器滴答声来计算的,以补偿ping时间。在客户端上,您有自己的本地滴答计数,并且您发送的每个命令都将转换为服务器滴答(这是一个简单的减法操作)

同样,客户端总是渲染“过去”。因此,您假设客户端所看到的世界比服务器的实际时间晚了100毫秒。

因此,让我们用服务器时间(由S指定)重新说明您的示例。

客户端在服务器时间为S0的T0发送输入(我猜这实际上是“服务器时间减去插值时间的客户端表示形式”)。客户端不等待服务器的响应,而是立即移动。

服务器在T1接收输入。服务器计算出客户端在给定的服务器时间S0上的客户端权威位置。将其发送给客户端。

客户在T2处获得权威位置(仍然指定服务器时间S0)。客户跟踪过去事件的过去时间量(可能只是所有未确认的预测的队列)。

如果服务器在S0处发回的预测位置/速度/值与客户端在S0中存储的内容不同,则客户端会以某种方式进行处理。通过将播放器恢复到过去的位置,或者重新模拟先前的输入,或者可能是我没有想到的其他方式。


3
除了过去关于客户端渲染的一点点,这都是正确的。相对于服务器,客户端实际上是在将来渲染!服务器知道从每个客户端那里获得的信息都是旧的,并且此后每个客户端将已经更改。
Kylotan'1

2

实际上,在github中有一个开源实现,展示了如何实现。看看Lance.gg

github仓库:https : //github.com/lance-gg/lance

客户端预测代码在称为的模块中实现 src/syncStrategies/ExtrapolateStrategy.js

除了外推,我上面没有提到两个概念:

  1. 增量弯曲。 基本上,不是一次全部应用服务器校正,而是让增量以较小的增量应用。这样,远程对象将逐渐调整其位置以匹配服务器位置。有位置弯曲,速度弯曲,角弯曲和角速度弯曲。同样,对于不同的对象,您可能需要不同的弯曲系数。
  2. 步骤重新制定。 数据已过去这一事实意味着您可以将时间回滚到服务器数据时间,然后从该时间重新启动。当然,您仍然需要转向新的位置,而不是跳到这个位置。

1

客户端A始终领先于服务器-但这无关紧要。仅当服务器说报告的位置有问题时,才需要重新挂起客户端,这时客户端将重新运行自错误以来的所有更改并使用更正后的值,以使其状态兼容与服务器。

为此,客户端需要记住其过去的状态和过去的更新。这可能只是一些简单的值,例如位置,速度,方向等。服务器将定期发送确认,确认各种客户端更新是合法的,这意味着现在可以将其从客户端中忘记。但是,如果服务器报告更新无效,则客户端状态将回滚到该点,并且将来的更改将应用​​于该已修改状态。

Valve文章底部有一些其他链接值得一读-这是其中之一:https : //developer.valvesoftware.com/wiki/Prediction


因此,我是否认为客户端(at t=4)收到有关的信息是正确的t=2,所以它会重置状态,t=2然后重新运行更新以将对象从t=2引入t=4
乔治·达基特

由于某种原因,我仍然没有掌握它。服务器不会被告知播放器的位置,而只会被告知输入。因此,播放器正在从服务器所说的最后位置移动。输入已应用。服务器已通知。服务器确认输入给所有人。假设所有命令都被接受,服务器仍将位于客户端A的后面-因此,当客户端A停止时,其角色将立即停止,然后在收到停止确认后滑回服务器位置。
克里斯·埃文斯

@GeorgeDuckett:是的(尽管不必一定是t = 4,但是只要检测到差异就可以,并且可以有任意数量的重新应用的更新。)
Kylotan 2012年

@ChrisEvans:已知状态+基于输入的更改无论如何都等于发送状态。至于停止示例,它本身就是输入,并且服务器仍在模拟移动,直到它接收到该输入。假定持续的等待时间,服务器将停止玩家在其停止移动时所看到的相同位置的播放器,因为客户端在服务器之前。(在现实世界中,延迟会有所不同,因此您需要进行插值以使其平滑。)
Kylotan 2012年
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.