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

Java 处理在线游戏中的玩家速度,java,mmo,Java,Mmo,所以我写这个在线游戏,我有点难以处理多久我应该接受一个移动包。问题是,如果不信任客户提供的一些数据,我就无法使其正常工作。基本上我的想法是: 客户端 /**** [game/client] movePlayer ***/ boolean playerCanMove = Date.now() - player.lastMove > 1000; if(playerCanMove){ player.lastMove = Date.now(); player.move(RI

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

客户端

/**** [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
,服务器会认为播放器移动太快,而这不是问题所在,问题是移动时间不同,服务器保存
播放器。最后一个移动时间有点晚,在这种情况下,误差幅度听起来也不太好

有什么想法吗

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

解决方案

我还没有实现这一点,但我已经考虑过这个退出一点,我找不到任何弱点,请随时评论,如果你这样做

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

添加额外的
&&packet.timeStamp

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


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

您的架构是错误的。

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

服务器端保留游戏的整个状态,从客户端接收用户输入,处理新的游戏状态(验证是否为有效移动),然后向客户端返回游戏的新状态

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

只有在存在某种“撤销”最后一步的情况下,客户“知道”最后一步的想法才有意义


第二点是,如果您使用
http
在客户机-服务器之间传输数据,则服务器不可能在move1之前接收move2。。。http是一种tcp协议,tcp保证交付订单,因此您关于不同延迟导致服务器端错误订单的假设是错误的

我认为客户端不需要保存日期并将其发送到服务器。您可以做的只是单独发送数据包,并在每次从播放机收到数据包时更新服务器上的.lastMove字段。这样你就不需要依赖客户来获取信息

如果您对客户端预测一成不变,那么有多种方法可以实现这一点,而无需客户端发送任何可能导致问题的真实信息

这里有一篇精彩的文章描述了制作这类游戏的技术:

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

在游戏中保持某种时钟。它可以是整个游戏开始后的毫秒,也可以是每个玩家登录后的唯一毫秒

在服务器和客户机上独立地保存此文件。 您可以偶尔使用类似这样的方法来同步它们,但在您的情况下,这可能会有些过头

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

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

如果客户端想要作弊,它不能发送两个时间戳间隔小于1000毫秒的移动。 如果确实如此,服务器将知道忽略移动

您还可以实现一些逻辑,如果检测到数据包同时到达或关闭(100-200ms),但时间戳间隔为1000ms或更大,则停止游戏。 这将是抓住骗子的一个简单方法

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

事实上,根据游戏的速度,您可能希望成批向服务器报告移动,而不是每个移动都单独报告,这既是为了保存数据(如果此游戏用于移动),也是因为这样会更快


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

Im使用这两种方法,服务器是Javascript,客户端是Java。这就是为什么有人会把两个标签都放进去,但有人会编辑它们。但实际上这并不重要,因为这段代码实际上是一段伪代码,使问题变得像posible一样简单。我不确定您要解决的问题是什么。你害怕机器人欺骗你的游戏吗?我这样问是因为我不知道为什么你不能相信前端会这么做。但是,最终,如果您正在编写一个API,该API除了在某个时间间隔之外,实际上无法接受移动请求,那么您必须像现在一样在服务器上保存该时间间隔,如果移动速度超过该时间间隔,则必须拒绝。如果网络延迟使时间间隔变得困难,您编写的前端始终可以自动重新提交。@centenond您的问题太广泛,但您可以查看其他问题,如DCTID或DCTID这是一个快节奏的游戏,客户端移动