Hi everyone,
I’m working on a multiplayer game using Nakama where I aim to host authoritative matches with around 200 clients, all sharing real-time data like player positions and rotations. In addition to players, there are multiple objects in the game world that also need to share their positions and rotations with all clients.
Current Setup:
- Authoritative Matches: I’m using authoritative matches that hold a game state. The game state includes information about all players and objects, structured like this:
{
label: {},
transforms: {
object1: {
position: { x, y, z },
rotation: { x, y, z }
},
object2: {
position: { x, y, z },
rotation: { x, y, z }
},
// ...more objects
},
players: {
player1: {
position: { x, y, z },
rotation: { x, y, z }
},
// ...more players
}
}
- Message Handling: When sending player or object data, each has its own opcode with a JSON payload:
json
Copy code
{
"timeStamp": "2024-11-08T15:24:05.226497+01:00",
"UserId": "1746c806-c306-4e81-a728-a4fda6a7aead",
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0 }
}
- Tick Rate: For my game design, I need a high refresh rate and I’m aiming for a tick rate of 20, updating player and object positions 20 times per second.
- Match Loop: My match loop is based on a tutorial I watched. I loop through incoming messages, use a switch statement depending on the opcode, and only parse JSON when necessary. After processing all incoming messages, I calculate the most current transforms and use
dispatcher.broadcastMessageDeferred()
to share the new state with all clients, then return the updated state.
Problem:
Despite my efforts, I can currently have a maximum of about 15 players in a session who can send and receive game state at a rate of 20 times per second. Beyond that, connections drop, messages can’t be delivered, and socket clients get disconnected.
Current Configuration:
Here is my Nakama configuration:
yaml
Copy code
# name: nakama_de
data_dir: "./data/"
api:
http_port: 7350
address: "0.0.0.0"
logger:
file: "/nakama/logs/logfile.log"
max_size: 100
max_age: 30
rotation: true
runtime:
js_entrypoint: "build/index.js"
env:
- NAKAMA_CORS_ALLOW_ORIGINS=*
- NAKAMA_CORS_ALLOW_METHODS=GET,POST,PUT,DELETE,OPTIONS
- NAKAMA_CORS_ALLOW_HEADERS=Authorization,Content-Type
session:
token_expiry_sec: 7200 # 2 hours
match:
input_queue_size: 8192
call_queue_size: 8192
deferred_queue_size: 8192
socket:
address: "0.0.0.0"
max_message_size_bytes: 262144 # Increased buffer for larger messages
max_request_size_bytes: 262144 # Larger buffer to handle bigger requests
read_buffer_size_bytes: 262144 # Larger read buffer
write_buffer_size_bytes: 262144 # Larger write buffer
outgoing_queue_size: 8192 # Higher queue size to handle more messages per session
# Connection lifecycle settings
idle_timeout_ms: 120000 # Default: 60000
ping_period_ms: 100000 # Default: 15000
pong_wait_ms: 120000 # Default: 25000
write_timeout_ms: 120000 # Default: 10000
read_timeout_ms: 120000 # Default: 10000
write_wait_ms: 120000 # Default: 5000
console:
port: 7351
address: "0.0.0.0"
Questions:
- Configuration Parameters: Are there specific configuration parameters I could adjust further to support a higher number of concurrent players at a high tick rate?
- Best Practices for High Player Count: What are your experiences with accommodating a high number of players in an authoritative match with a complex shared state? Are there patterns or optimizations I should consider?
- Optimizing Message Handling: Is my approach to handling incoming messages and broadcasting updates efficient for this scale? Would it be better to batch updates differently or use a different message format to reduce overhead?
- Scaling Strategies: Should I consider sharding the game state or distributing the load across multiple matches or servers? If so, how can that be achieved with Nakama?
Additional Context:
- The server is running on a machine with sufficient resources (CPU, RAM, bandwidth). Please let me know if hardware specs would be helpful.
- I’m using the JavaScript runtime for Nakama.
- Clients are connected via WebSockets.
- I’m open to using other data formats (e.g., Protobuf) if it would improve performance.
Any insights, experiences, or suggestions would be greatly appreciated!