【发布时间】:2018-11-17 22:54:19
【问题描述】:
所以我写了这个在线游戏,我有点难以处理我应该多久接受一次移动包。问题是我无法让这个工作不信任客户端的一些数据。基本上我的想法是:
客户
/**** [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 在客户端/服务器中将不一样,因为数据包到达所需的时间。
因此,如果客户端发送 2 个移动数据包,第一个传输时间为 100ms 的第二个传输时间为 99ms 服务器会认为玩家移动太快,而这不是问题, 问题是旅行时间不同,服务器保存player.lastMove 有点晚,在这种情况下,误差幅度听起来也不太好。
有什么想法吗?
编辑:发送到服务器的唯一数据是为了示例,玩家想要移动的方向,它只是碰巧是相同的变量名。服务器有自己的player.lastMove变量
解决方案 Thanks to @Lev M.
我还没有实现这个,但是我已经考虑过这个了,我找不到任何弱点,如果你这样做,请随时发表评论!
我认为可以肯定地说,客户端唯一可以做的就是更改时间戳,他也可以更改时钟,但这会产生相同的效果,所以我考虑这个只是假设他正在更改数据包时间戳
添加一个额外的&& packet.timeStamp < server.clock
到
boolean isTimeStampValid = packet.timeStamp >= player.lastMove + 1000 && packet.timeStamp < server.clock
不会出错,它会将攻击 #1 isTimeStampValid 标记为错误
【问题讨论】:
-
我两者都用,服务器是Javascript,客户端是Java。这就是为什么放置两个标签但有人编辑它们的原因。但实际上这并不重要,因为代码实际上是一个伪代码,可以使问题尽可能简单
-
我不确定您要在这里解决什么问题。你害怕机器人欺骗你的游戏吗?我问是因为我不确定你为什么不能信任前端来做这件事。但是,最终,如果您编写的 API 真的不能接受移动请求,除非在某个时间间隔内,那么您将不得不像您一样将时间间隔保存在服务器上,如果移动速度比这更快,则拒绝。如果网络延迟使间隔变得困难,您编写的前端总是可以自动重新提交。
-
@centenond 你的问题太笼统了,不过你可以看看其他问题,比如stackoverflow.com/questions/18114901/…或者stackoverflow.com/questions/2847929/…
-
DCTID 这是一个快节奏的游戏,客户端先移动,然后如果服务器拒绝该位置,则玩家传送回它假设的位置,大多数情况下,如果玩家没有作弊且网络连接良好,前端重发会导致游戏无法玩,会破坏客户端预测的目的。
-
我认为它一点也不宽泛,问题是关于一个具体问题,在这种情况下可能并不少见。