My team and I are working on an upcoming online fighting game using ENet-CSharp (A C# ENet implementation created by nxrighthere), and we’re currently designing the architecture of the server. We would be very glad to hear your suggestions concerning a couple of issues we have been struggling with.
Our current plan is to host a dedicated server for the game, which will handle the logic and game loop of each game instance, and the MonoGame clients will simply deliver the user’s commands to the server, and present the updated game state received from it. However, we are not sure how to correctly use ENet with our division of independent game rooms.
Let’s say, I have 100 concurrent users connected to the server, and 10 independent game rooms, consisting of 10 players each. At first, we thought that we should have a single ENet Host which will handle all of them, and a single independent ENet thread that will simply receive packets from all ends, alerting the corresponding game room to handle it within its game logic. However, it seems a bit unsafe to have one I/O thread shared by multiple different and parallel instances of the game, so our plan is as such:
- For each game room (10 players for that matter), a unique ENet Host will be created, and 2 independent threads will run – one for the game loop, and one for the ENet event polling.
- The ENet thread will call the Service method with a small timeout, expecting to poll one "Receive" event at each iteration, and will queue the commands received from the players.
- The game loop, at the start of each iteration, will dequeue the commands that have been collected since the last iteration, apply them within the game logic, and so on.
Would you guys say this is a good solution to go by?
A question that rose with that: Correct me if I’m wrong, but as far as I understand, the send rate of the outcoming packets corresponds to the rate of calls to either the "Service" or the "Flush" methods. How can I ensure that at the end of each game loop, the new game state will be broadcasted immediately to the clients? Calling the "Flush" method at the end of each iteration seems logically appropriate, but unsafe at the same time (since it will be called outside the ENet dedicated thread).
Any piece of advice would be more than welcome. Thanks in advance!