在在线游戏中处理玩家速度

Dealing with player speed in a online game

所以我正在写这个在线游戏,我有点难以处理我应该多久接受一次移动数据包。问题是,如果不信任客户端一些数据,我就无法使它工作。基本上我的想法是:

客户端

/**** [game/client] movePlayer ***/


boolean playerCanMove = Date.now() - player.lastMove > 1000;

if(playerCanMove){

    player.lastMove = Date.now();
    player.move(RIGHT);
    client.send(new PacketMove(RIGHT));
}

服务器:

/**** [server] handle a move packet ****/
/** The only data received from the client is the direction(RIGHT) **/
/** the server has its own player.lastMove **/

let playerCanMove  = Date.now() - player.lastMove > 1000; 

if(playerCanMove){
    player.lastMove = Date.now();
    player.move(RIGHT);  
}
else{
   error = "Player is moving too fast"; 
}

问题是服务器 player.lastMove 与 client/server 中的服务器不同,因为数据包到达需要时间。

所以如果客户端发送2个移动数据包,第一个移动时间为100ms,第二个移动时间为99ms,服务器会认为玩家移动太快,当这不是问题时,问题是旅行时间变化并且服务器保存 player.lastMove 有点晚,在这种情况下误差范围听起来也不太好。

有什么想法吗?

编辑:发送到服务器的唯一数据是玩家想要移动的方向,为了这个例子,它只是碰巧是相同的变量名。服务器有自己的player.lastMove变量

解决方案

我还没有实现这个,但是我想了想放弃了,我找不到任何弱点,如果你实现了,请随时评论!

我认为可以肯定地说,客户端唯一可以做的就是更改时间戳,他也可以更改时钟,但这会产生相同的效果,所以我只是在假设他正在更改数据包的情况下才想到这一点时间戳

添加一个额外的 && packet.timeStamp < server.clock

boolean isTimeStampValid = packet.timeStamp >= player.lastMove + 1000 && packet.timeStamp < server.clock

不会出错,它会将攻击 #1 isTimeStampValid 标记为 false

你的架构是错误的。

游戏的客户端应该有大约零逻辑处理用户输入...用户输入应该尽可能原始地发送到服务器,客户端保持无状态

服务器端保留游戏的整个状态,接收来自客户端的用户输入,处理新的游戏状态(验证是否是有效移动)然后 returns 到客户端一个新的游戏状态

客户端应该简单地在屏幕上打印新状态。 尽可能保持最小的本地数据

你的客户想法“知道”最后一步只有在有某种“撤消”最后一步

第二点是,如果您使用 http 在客户端-服务器之间传输数据,则服务器无法在 move1 之前接收 move2...http 是一种 tcp 协议,tcp 保证交付顺序,所以你关于不同延迟导致服务器端错误顺序的假设是错误的

这里有一个我认为很容易实现的想法: 不要使用 Date.now() 来计算移动之间的时间。

保持某种游戏时钟。它可以是整个游戏开始后的毫秒数,例如 Unix timestamps,也可以是每个玩家唯一的,例如他们登录后的毫秒数。

将其独立保存在服务器和客户端中。 您可以偶尔使用 SNTP 之类的方法同步它们,尽管在您的情况下这可能有点过分。

每当玩家移动时,让客户端在数据包中插入基于此时钟的时间戳以及移动数据。

然后,让服务器上的逻辑检查这些时间戳的一致性。 这样,移动之间的时间将忽略数据包传输时间。

并且如果客户端想要作弊,则不能发送两个时间戳相隔小于 1000 毫秒的动作。 如果是这样,您的服务器将知道忽略该移动。

您还可以实施一些逻辑,如果它检测到数据包一起到达或关闭(100-200 毫秒)但时间戳相隔 1000 毫秒或更长时间,则会停止游戏。 这将是一个简单的方法来抓住作弊者。

如果你想要一个快节奏的游戏,你不得不在客户端中保持状态,让玩家看到他们移动的结果,而无需在每次击键时等待服务器响应。

事实上,根据您游戏的速度,您可能希望向服务器分批报告走法,而不是每次走法都自己报告,这既是为了节省数据(如果此游戏是移动版的)又是因为这样会更快。

然后您的服务器可以一起验证整个批次的一致性。