无论对方法的看法如何,您正在寻找的是被认为是“作弊”的速度阈值。给定距离和时间增量,您可以根据您的作弊阈值轻松查看它们是否“移动得太远”。
time = thisTime - lastTime;
speed = distance / time;
If (speed > threshold) dudeIsCheating();
用于测量的时间是服务器接收数据包的时间。虽然看起来微不足道,但它正在计算每个角色移动的距离,这最终可能会非常昂贵。最佳路线是服务器根据速度计算位置,即角色的位置。客户端从不传达位置或绝对速度,相反,客户端发送“最大百分比”速度。
澄清一下:这只是为了作弊检查。您的代码有可能在服务器上延迟或长时间处理影响您的结果。公式应该是:
maxPlayerSpeed = 300; // = 300 pixels every 1 second
if (maxPlayerSpeed <
(distanceTraveled(oldPos, newPos) / (receiveNewest() - receiveLast()))
{
disconnect(player); //this is illegal!
}
这将玩家的旅行速度与最大旅行速度进行比较。时间戳由您收到数据包的时间决定,而不是由您处理数据的时间决定。您可以使用任何您关心的方法来确定要发送给客户端的更新,但是对于您想要确定作弊的阈值方法,上述不会受到延迟的影响。
在第 1 秒接收数据包 1:位置 1 的字符
在第 100 秒接收数据包 2:位置 3000 的字符
行驶距离 = 2999
时间 = 99
率 = 30
没有发生作弊。
在第 101 秒接收数据包 3:位置 3301 处的字符
行驶距离 = 301
时间 = 1
率 = 301
检测到作弊。
您所说的“延迟峰值”实际上是数据包传递的高延迟。但这并不重要,因为您不会在处理数据时经过,而是在收到每个数据包时经过。如果您保持时间计算独立于您的游戏滴答处理(因为它们应该与“滴答”期间发生的事情一样)高和低延迟只会影响服务器对角色位置的确定程度,您可以使用插值+外推来解决.
如果客户端不同步到他们没有收到对其位置的任何更正并且与服务器严重不同步的情况下,则会出现严重的数据包丢失和高延迟,您的作弊检查将无法解释。您需要通过处理实际网络通信在较低层考虑这一点。
对于任何游戏数据,理想的方法是让除服务器之外的所有系统都落后 100-200ms。假设您每 50 毫秒进行一次预期更新。客户端收到第一个和第二个。客户端在收到第二次更新之前没有任何数据要显示。在接下来的 50 毫秒内,它显示了已经发生的变化进程(即,它处于非常轻微的延迟播放状态)。客户端将其按钮状态发送到服务器。本地客户端还根据这些按钮按下预测移动、效果等,但只向服务器发送“按钮状态”(由于按钮数量有限,表示每个状态所需的比特数量有限,这允许更紧凑的数据包格式)。
服务器是权威模拟,决定实际结果。服务器每隔 50 毫秒向客户端发送一次更新。服务器不是在两个已知帧之间进行插值,而是为任何丢失的数据推断位置等。服务器知道最后的真实位置是什么。当它接收到更新时,发送给每个客户端的下一个数据包包括更新的信息。然后,客户端应该在到达该时间点之前收到此信息,并且玩家会在它发生时做出反应,不会看到任何奇怪的跳跃,因为它从未显示不正确的位置。
可以让客户端对某些事情具有权威性,或者让客户端充当权威服务器。关键是确定对客户的信任有多大影响。
客户端应该定期发送更新,比如每 50 毫秒。这意味着 500 毫秒的“延迟峰值”(数据包接收延迟),在延迟期内发送的所有数据包都将延迟相似的数量,或者数据包将被无序接收。底层网络应该优雅地处理这些延迟(通过丢弃具有过大延迟的数据包,强制按顺序发送数据包等)。最终结果是,通过适当的数据包处理,预期的问题不会发生。此外,不从客户端接收显式字符位置,而是让服务器显式更正客户端并仅从客户端接收控制状态将防止此问题。