I'm making a multiplayer game where players fight in vehicles, and I am doubting my server architecture. As it will be physics, network and AI intensive I would like to split these 3 topics into their own thread. Perhaps even one thread per AI.
The physics thread will run at a fixed time-step and do the same loop over and over.
- Integrate gamestate at fixed timestep of 0,005s (200Hz)
- Solve gamestate for constraints and collisions
One such constraint is a vehicle controller, which is a
structconsisting of throttle, steer, brake etc. is applied to a single vehicle.
- The network is called every 6 physics frames, thus the networking runs at ~33Hz
- The AI is also called every 6 frames.
Note: network and AI can be called in lockstep
The AI threads will calculate the next move on a need-by-need basis.
- Copy gamestate into private memory
- Calculate next move
- Update their vehicle controller in the game state
The network thread will
- Listen for incoming UDP packets, handle them, apply changes to gamestate such as player's vehicle controller, bullet spawn
- When called for, broadcast the new gamestate to clients
- Copy gamestate into private buffer
- Create array of differences from last state
- Vehicle parts removed/added
- Vehicle parts moved/rotated
- Players joined/left
- Projectile impacts and damages
- Pack the differences together and broadcast.
- When a new player joins:
- grab the last private game state buffer and send it whole
- Change gamestate by spawning a vehicle and allocating a controller
What I'm having trouble with:
- Creating threads on the fly has overhead, so I would like to avoid it by pre-creating and "parking" the threads, and calling them when needed. Once called, they do their duty, such as calculate the next move for the AI to make. Then the threads "hibernate". Note that I don't want the threads to wait in a busy loop and read some shared memory for "activation".
- The AI and Network threads need to make private copies of the game state, because the physics run so fast the game state might be changed mid-read.
- Mitigation 1: swapping game state buffers. Still no guarantee.
- Mitigation 2: locking the gamestate. This is a bad idea because the physics should not be held up.
How can I achieve this in C++? Does x86 offer actual interrupts for this? How about other architectures, or are there libraries that do this for me?
Or should I do it another way?