[Kryonet] How to efficiently send movement updates?

Hey all,

So I’m implementing multiplayer movement of other characters in my game now, I have the server getting new players logging in and storing them in a local copy of the player. My question now is how to do the movement updating. I know how to do it, just create a packet and send it over the server to everyone to update. But, I don’t want to be sending a huge number of packets every second for every player. That just seems like it will overload my server and crash.

My question to you all is: how could I go about doing this efficiently?

I’m posting a snippet of my movement code below:

    public void updatePlayer(int delta)
    {
        boolean isWalking = false;
        float xChange = 0, yChange = 0;
        Input input = gc.getInput();
  
        int runMod = 1;
        if (input.isKeyDown(Input.KEY_LSHIFT))
        {
            runMod = 2;
        }
        if(input.isKeyDown(Input.KEY_A))
        {
            //LEFT
            sprite = walkingAnimLeft;
            sprite.start();
            xChange -= speed * runMod * delta;
            isWalking = true;
            facing = "left";
        }
  
        if(input.isKeyDown(Input.KEY_D))
        {
            //RIGHT
            sprite = walkingAnimRight;
            sprite.start();
            xChange += speed * runMod * delta;
            isWalking = true;
            facing = "right";
        }
  
        if(input.isKeyDown(Input.KEY_W))
        {
            //UP
            sprite = walkingAnimUp;
            sprite.start();
            yChange -= speed * runMod * delta;
            isWalking = true;
            facing = "up";
        }
        if(input.isKeyDown(Input.KEY_S))
        {
            //DOWN
            sprite = walkingAnimDown;
            sprite.start();
            yChange += speed * runMod * delta;
            isWalking = true;
            facing = "down";
        }
        if (input.isKeyPressed(input.KEY_ENTER))
        {
            if (chat.isChatting())
            {
                chat.sendText();
            }
            else
            {
                chat.setChatting(true);
            }
            //chat.setChatting();
        }
        if(input.isKeyPressed(input.KEY_E))
        {
            toggleEquip();
        }
        //If the player is not walking, stop the animation
        if (isWalking && !currentMap.blocked(x+xChange, y+yChange, facing))
        {
            x += xChange;
            y += yChange;
            //Here's where I would put it, but as you can see updatePlayer is called all the time, so I'd be sending a packet all the time for each player.
            
        }
        if (!isWalking)
        {
            sprite.setCurrentFrame(1);
            sprite.stop();
        }
        isWalking = false;
    }

I was thinking of using some sort of timer and basically lumping the movements into one packet. I.e., aggregating movement updates across X milliseconds into one packet and sending those at once. But this would require a timer of some sort to count every, 20 milliseconds, let’s say. The problem there is, I would need the timer to be accurate on each and every client. And no, I haven’t just tried sending it every update, because I’m scared of it crashing hardcore.

Any advice?

From my experience, sending them every frame probably isn’t as bad as you think, unless you’re really strained for resources, e.g. making an MMO (In which case you should probably use something faster than Kryonet).

You should probably try and send around 6-10 packets a second. To counteract the jumpy-ness this causes you should probably use some sort of interpolation. You can do linear interpolation, but I find something like the following is sufficient:

public void clientUpdate() {
draw_x += (msg_x-draw_x)/10;
draw_y += (msg_y-draw_y)/10;
}

Where msg_x and msg_y are the last known location of the object, according to server messages, and draw_x and draw_y are the location you want to use for drawing. You may need to change the 10 at the end to suit how often you receive messages - Use a higher number if the time between messages is longer, use a lower number if it’s shorter.

10% interpolation is a good idea.

Faster how? :slight_smile:

From my knowledge Kryonet serializes every object before sending it. While it’s serialization is pretty fast, it still creates a decent amount of overhead and takes additional computing time compared to simply sending a dozen bytes over UDP. That wouldn’t matter too much for games with a few players at once, but I can imagine it’d strain the servers if you had heaps of players at once.

PS: I don’t really know anything about making MMOs :P. I’ve never made one before, and I never intend to. The only networking I’ve ever done is with the java.net.Socket and java.net.DatagramPacket classes, and I used a lot of overhead (16 or so bytes IIRC)

You need to get your data to bytes somehow, no matter how you are doing your networking, so there will always be some overhead there. :slight_smile:

KryoNet uses Kryo for serialization. When automatically serializing your objects, Kryo is almost as fast as hand written serialization code. It generates bytecodes instead of using reflection when possible. Kryo can optionally use Unsafe on Sun VMs to directly access object memory, which is extremely, ridiculously fast for arrays of primitive types.

Kryo serialization is pluggable, so you can hand write serialization code and Kryo has utilities for making this easy. Hand written serialization code using Kryo is generally faster and smaller than hand written serialization code using java.io.Externalizable. Here are benchmarks. It’s a lot of data, so I’ll pluck out the interesting parts:

“kryo” in this chart is using automatic serialization. “java-built-in” is Java’s automatic serialization. Here’s another:

The “kryo-manual” in this chart is hand written serialization code. The “java-manual” is hand written Externalizable code. I won’t spam more charts, but the “size” charts are also cool, showing Kryo is also size efficient. :slight_smile: Of course the benchmark data is small and string heavy, so likely not terribly meaningful unless you run it with your own actual data.

TLDR; Kryo is super awesome, fast serialization. :smiley: Back on topic though, KryoNet does have some limitations, mostly with threading. KryoNet is limited to one network thread. Objects are serialized on any thread that calls send() and bytes are usually sent immediately from that thread, though they may be queued for sending later from the network thread. That part is fine, but bytes are always received and queued on the network thread, and deserialization happens on that thread as well. Once you get the deserialized object you can process it on another thread, but doing the deserialization on the network thread limits throughput. This starts to become an issue when exceeding 1Gbit/s.

KryoNet is an easy to use API on top of NIO. The API doesn’t really care how the networking is done though. I have a version of KryoNet that uses Netty under the covers, which allows for more threading flexibility. It doesn’t have all the minor features of KryoNet though, and I haven’t found the time to finish it. :frowning:

Showoff :smiley:
Well what I’m lacking is network programming experience, especially with games.
For example I would send/poll positions of everything, every frame. Using UDP i guess but still maybe overkill. So I guess I need general high performance networking knowledge - nothing to do with kryonet
Gotta read a book or something.

Wow! Thanks for all the replies :slight_smile:
Learning network stuff is definitely a trial by fire for me, but you guys help is much appreciated. :slight_smile:

Btw, cero, I’m doing the same thing. :stuck_out_tongue: But after reading all this I’m gonna keep trying what I’m doing until I notice some issues.

A very quick optimization you can make here is to only send player positions for players who moved during that frame. If a client gets a packet that makes no mention of player_foo then player_foo much be in the same place he was last frame. Another trick is to know how little data you can get away with sending, for example, can you use a short instead of a float to update the clients?

Unless you have some sort of client-side interpolation, the game is going to look jumpy since networks are unreliable. The better your interpolation is, the slower the server can run and clients won’t notice it. I highly recommend taking the time to read some common tricks that games use to hide the instability and delays of a network. I would suggest these for reading:

https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization

Even though these methods are used by a 3d game, they translate over just as well to a 2d game.