I am currently working on a network bomberman game. It is currently very playable over LAN, but I am not sure how well it would do over the internet. The game supports 4 players, but I am thinking of expanding it to 16 or maybe even 32 players.
I am in the process of converting the code from blocking IO to nonblock NIO, which is getting rid of a few ugly threading issues (but of course it creates a few ugly NIO issues). I am using UDP for everything because:
- Bomberman is a pretty ‘twitchy’ game – it needs low latencies to be playable.
- NAT traversal by UDP so that NATed players can host games.
Threads & Networking
With the new NIO code the server is single threaded - including both game logic and networking. Should I split the gamelogic and networking into two threads? This would create more threading hassles and synchronization issues. Also, would it be more efficient to have more than one networking thread (but one Selector)?
ByteBuffer
I am creating a new ByteBuffer every time I want to send or receive data. This seems pretty inefficient, so I was thinking of creating a class to hold a fixed number of direct ByteBuffers to be used and reused. Should I use/reuse direct ByteBuffers for both receives and sends?
Reliability
I am running the same simulations on both the client and the server (50 itr/s). Updates happen every time a player presses or releases a key because that when the simulations would become out of sync. Although I do not need in-order delivery for game messages, I still need the updates to come eventually - it would be irritating for a player to be killed by a bomb that they never saw. I could:
- Have the client ACK every game update they receive and then retransmit updates that have not been ACKed within a time constraint.
- If the client receives update 5 but has not yet received update 4 it starts a countdown which then requests that the server retransmit packet 4.
Any ideas on which method (or any other one) would be best?
Threads & The Client
Like the server, the client is single threaded, except that it will has a few AWT threads (I’d love to use LWJGL, but too many broken OpenGL drivers…) Again, should I use seperate threads - perhaps one for gamelogic, one for graphics, and one for networking? The gamelogic on the client will likely have to do calculations a few times, such as when it receives an update for timestep 4 but it is on timestep 10. It then has to go back to 4, update, then calculate from 4-10.
File IO
When reading a file on the server, such as a map, to send to the client, should I spawn a thread to read in the file to a buffer or byte[] and then notify the main thread that its ready to be sent to the client?
Non Blocking IO
Since non blocking DatagramChannels have a possibility of not sending a packet if the buffer is filled, whenever I want to send a packet I add it to a LinkedList and register the channel for writing. Later, deregister, I remove packets from the linkedlist until its empty or one does not send, in which case I add it back to the list and reregister. Is this an accepted way of doing NBIO?
Thanks for your help,
-Sam