Here, it’s worth starting with the general architecture of the application that serves as a game server. It was decided to use the following scheme:

In parallel, messages are received from different players via websocket and are laid down for processing by the main thread, which updates the game logic. The main stream works in iterations of 40ms, within which it updates movement, visibility, NPC respawn, the progress of using abilities, etc.

Data is written to the database asynchronously – the game logic update thread queues messages to another background thread, which groups them and writes to the database in batches.

Serialization and sending messages to players also occurs asynchronously – this is done by the next background thread, to which messages are written to the queue for processing as part of the iteration, and at the end of the iteration, messages are grouped for each user and sent to the client in a batch.