3

So im writing this online game and im kinda having a hard time dealing with how often I should accept a move packet. The problem is that I can't get this to work without trusting the client with some data. Basically my idea was:

Client

/**** [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:

/**** [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"; 
}

The problem with this is that server player.lastMove won't be the same in the client/server because of the time it takes for the packet to arrive.

So if the client send 2 move packets, the first one with a travel time of 100ms and the second one with a travel time of 99ms server will think the player is moving too fast, when that's not the problem, problem is that the travel time varies and server is saving the player.lastMove a bit late, a margin of error doesn't sound too good in this case neither.

enter image description here

Any ideas?

EDIT: The only data that's being sent to the server is the direction the player wants to move for the sake of the example,It only happens to be the same variable names. The server has its own player.lastMove variable

SOLUTION Thanks to @Lev M.

I havent implemented this yet, but I have thought about this quit a bit, and I can't find any weakness, please feel free to comment if you do!

I think is safe to say that the only thing the client can do is change the timestamp, well he can change the clock too but that will have the same effect, so I thought about this only assuming he's changing the packet timestamp

enter image description here

adding an extra && packet.timeStamp < server.clock

to

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

can't go wrong and it will mark attack #1 isTimeStampValid as false

centenond
  • 1,170
  • 1
  • 8
  • 23
  • Im using both, server is Javascript and client is in Java. That's why a put both tags but some one edit them. But really it doesn't matter as the code is practically a pseudo code to make the question as simple as posible – centenond Nov 17 '18 at 23:04
  • I'm not sure what problem you're trying to solve here. Are you afraid of bots scamming your game? I ask because I'm not sure why you couldn't trust the front end to do this. But, ultimately if you are writing an API that really can't accept move requests except at a certain interval, then you would have to save the interval on the server like you are and reject if moves are faster than that. The front end you write could always auto resubmit if network latency was making the interval difficult. – DCTID Nov 17 '18 at 23:10
  • @centenond Your question is too broad, but you can look at other questions like https://stackoverflow.com/questions/18114901/multiplayer-game-movement-synchronization?rq=1 or https://stackoverflow.com/questions/2847929/how-online-game-clients-are-able-to-exchange-data-through-internet-so-fast?rq=1 – Progman Nov 17 '18 at 23:17
  • DCTID this is a fast paced game, the client move first and then if the server rejects the position, the player teleports back to the position it suppose to be, most of the time this wont happen if the player isnt cheating and have a good internet connection, front-end resubmitting will make the game unplayable, and it will defeat the purpose of client side prediction. – centenond Nov 17 '18 at 23:18
  • 3
    I don't think it's broad at all, the question is about *one specific issue* which probably isn't all that uncommon in a situation like this. – CertainPerformance Nov 17 '18 at 23:22

2 Answers2

2

Here is an idea that I think is simple to implement: Don't use Date.now() to calculate time between moves.

Keep some kind of in game clock. It can be milliseconds since the whole game started, like Unix timestamps, or it could be unique for each player, milliseconds since they logged in.

Keep this independently on the server and in the client. You can synchronize them once in a while using something like SNTP, though that might be overkill in your case.

Whenever player makes a move, have the client insert a timestamp based on this clock in the packet, along with the move data.

Then, have logic on the server check consistency of these time stamps. This way, the time between moves ignores packet travel time.

And if the client wants to cheat, it can not send two moves with timestamps less then 1000 milliseconds apart. If it does, your server will know to ignore the move.

You can also implement some logic that will stop the game if it detects packets arriving together or close (100-200ms) but with timestamps of 1000ms apart or more. This will be an easy way to catch cheaters.

If you want a fast paced game, you can't help but keep state in the client, to let the player see results of their moves without waiting for server response on every keystroke.

In fact, depending on the speed of your game, you may want to report moves to the server in batches, instead of every move on its own, both to save data (if this game is for mobile) and because this would be faster.

Your server can then validate the consistency of the whole batch together.

Community
  • 1
  • 1
Lev M.
  • 6,088
  • 1
  • 10
  • 23
  • I was starting to think no one understood the question, you seem to do, thanks for replying!! This seems like a solid idea, I will get back to you when I implement and test this – centenond Nov 18 '18 at 06:53
-1

Your archtecture is wrong.

the client side of the game should have about zero logic processing the user input... the user input should be sent to server as raw as possible and the client side KEEPS NO STATE

the server side keeps the whole state of the game, receive the user input from client, process the new game state (validating if was or not a valid move) then returns to the client a new state of the game

the client should simple print the new state at screen. keeping as minium local data as possible

your idea of client "know" the last move only makes sense if there is some kind of "undo" last move

the second point is, if you are using http to transport data between client-server there is no way server would receive move2 before move1... http is a tcp protocol and tcp garantee the delivery order, so your assumption about different delays resulting in wrong order at server side is wrong

Rafael Lima
  • 3,079
  • 3
  • 41
  • 105
  • Thanks for replying, If it was a slow-paced game like chess or checkers I would go with the dumb-client method and this would make sense, but it isn't, client side prediction is a most in my game. The client should know when and if it can move there, also I didn't say server would receive `move2` before `move1`, my example was that if `move1` took 100ms to arrive and `move2` took 99ms to arrive `boolean playerCanMove = Date.now() - player.lastMove > 1000;` in the server will result in `false`, since `player.lastMove` will be affected by the time it takes the packet to arrive – centenond Nov 18 '18 at 01:20
  • Your idea means that Ill have to wait for the server response to move the player, which again it's fine with a game like chess or checkers, not an MMO or any fast paced game – centenond Nov 18 '18 at 01:30
  • I will not keep explaining what I've already said... You need to read about transport protocols for distributed systems... If you are using top there is NO WAY you can achieve this, even if you wanted to... – Rafael Lima Nov 18 '18 at 01:31
  • You HAVE TO wait the server to respond the request in order to move the otherwise you will inevitably create an inconsistent scenario "what player sees" agains "what is really happening in the morning world" or even allow someone to reverse engineer your client and then do all kind of non allowed moves, since your "logic" is client side – Rafael Lima Nov 18 '18 at 01:33
  • In real mmorpg the client side should do the collision detection basically everything else should be server processed... You can "speed up" the processing by assuming the server will allow your movement and then "print" it to your user... But again... Cliente side shall keep minimum data... – Rafael Lima Nov 18 '18 at 01:38
  • I have a clear Idea what should I trust the client with, that's why this question is here in the first place(because I don't want to trust the client side `player.lastMove`), also I didn't said my server doesn't have a game "logic" you can see that my server code is also checking if the player can move with its own data. Im sorry if my english isn't good enough to share my problem, but for some reason you keep assuming things that I have never said or implied. Im sorry for the down vote but your reply isn't even related with the question – centenond Nov 18 '18 at 02:14