Главный ключ - убедиться, что ваша игровая логика не зависит от вашей модели потоков.
Таким образом, большинство игровых серверов выглядят примерно так:
main() {
gGlobalReadOnlyStuff = LoadReadOnlyStuff();
SpawnThreads(numCores); // could be another limiting resource...
WaitForThreadsToBeReadyToGo();
while(1) {
WaitForNetworkInput(networkInput);
switch(networkInput.msg) {
case ADMIN_THING: // start/stop websever, dump logs, whatever...
DoAdminThing(networkInput.params);
break;
case SPAWN_GAME: // replace 'game' with 'zone' or 'instance' as needed
idThread = ChooseBestThread(); // round robin, random, etc
PostStartGameMessageToThread(idThread, networkInput.msg);
break;
// ...
}
}
}
void ThreadUpdate() {
threadLocalStuff = LoadThreadLocalStuff();
SignalThreadIsReadyToGo();
while(1) {
lock(myThreadsMessageQueue);
// copy messages to keep lock short
localMessageQueue = threadsMessageQueue;
unlock(myThreadsMessageQueue);
foreach(message in localMessageQueue) {
switch(message.msg) {
case SPAWN_GAME:
threadLocalStuff.games.MakeNewGame(message.params));
break;
case ADMIN_THING__LET_EVERYONE_KNOW_ABOUT_SERVER_RESET:
...;
break;
// etc...
}
}
foreach(game in threadLocalStuff.games) {
game.Update(); // game will handle its own network communication
}
}
Два жесткихтогда вещи «приходят с разделом (игра, зона, экземпляр, что угодно), подходящим для вашей игры» и «переносят вещи (игроки, шаровые молнии, эпический лутц) через эти границы» Один типичный ответ - «сериализовать его через базу данных», но вы можете использовать сокеты / сообщения / файлы / что угодно.Но да, где и как сделать эти разделы и свести к минимуму то, что может выйти за границы, тесно связано с вашим игровым дизайном.
(И да, в зависимости от ваших настроек, возможно, есть несколько «общих» систем(ведение журнала, память), для которого может потребоваться многопоточная обработка (или даже лучше, просто иметь один регистратор / кучу на поток))