In my multiplayer sandbox game, I send entire entities only when creating. Each entity has a UUID (normally supposed to be 128 bits but I used 64 because it’s just a long and easier to work with). When removing it’ll send the UUID of the to-be-removed entity (if the entity with the UUID doesn’t exist for some reason the client will ignore the packet). Updating entities’ positions is merely an array of UUIDs and another array of floats that correspond for each entity’s position.
If you are using Kryonet, the below will be a breeze because Kryonet can serialize and deserialize object graphs over the network extremely efficiently. If not, I suggest you do try it and see how you like it.
As for render data, that’s client-side only. I can mark fields as not-needed to be sent over the network by using the transient
keyword. Of course, in order for Kryonet to create objects they will need an empty constructor where it can be instantiated and then the rest of the information can be filled in.
You won’t need to assign IDs for each entity. IDs for that are really a pain because if you remove a type then you have an annoying gap in your sequence of numbers. With Kryonet you can merely register the entity’s class and it’ll tell the serializers how to work with that type of object.
Kryonet was designed to be really fast and efficient, so it’s perfect for games. The only time you’re sending an entire entity’s worth of data is when it’s being created. Anything else merely uses the UUID to look up the entity.
I hope that helps!