25 _listener(config.port),
27 _world(config.width, config.height, config.teamNames, config.seed),
29 _logObserver(_logger),
30 _dispatcher(_clients, _world, _notifier, _config, _scheduler)
32 auto sinks = std::make_unique<CompositeSink>();
48 _world.spawnResources();
55 std::cout <<
"Server listening on port " <<
_config.
port <<
"\n";
58 std::cout <<
"Teams: ";
68 std::vector<int> aiConns;
69 for (
const auto& [pid, p] :
_world.
getPlayers()) aiConns.push_back(p.connectionId);
76 for (
const auto& name :
_config.
teamNames) teams += (teams.empty() ?
"" :
" ") + name;
77 const std::string winner =
_world.
winner().value_or(
"?");
79 _logger.
info(
"GAME",
"========== GAME OVER ==========");
82 _logger.
info(
"GAME",
"Server uptime: " + std::to_string(upSeconds) +
" s (" +
83 std::to_string(upTicks) +
" ticks)");
86 long long joinSeconds = join->elapsed.count() / 1000000;
87 long long joinTicks = std::llround(join->ticks);
88 _logger.
info(
"GAME", winner +
" joined at: " + std::to_string(joinSeconds) +
" s (" +
89 std::to_string(joinTicks) +
" ticks)");
90 _logger.
info(
"GAME", winner +
" took: " + std::to_string(upSeconds - joinSeconds) +
" s (" +
91 std::to_string(upTicks - joinTicks) +
" ticks) to win");
93 upTicks - joinTicks));
95 _logger.
info(
"GAME",
"===============================");
100 std::signal(SIGINT, requestStop);
101 std::signal(SIGTERM, requestStop);
106 while (!g_stopRequested) {
125 }
catch (
const std::exception& e) {
126 std::cerr <<
"[error] " << e.what() <<
"\n";
130 _logger.
info(
"Server",
"Shutdown signal received, closing server");
void disconnect(int connectionId)
Close a client and drop its connection.
PollResult poll(int timeoutMs)
Run one poll cycle (blocks up to timeoutMs); returns this cycle's events.
void addNetworkObserver(INetworkObserver *observer)
Subscribe an observer to connect/disconnect/line events.
std::chrono::microseconds gameElapsed() const
Wall-clock time since server start (single source for stu and the win banner).
double gameTicks() const
Total game ticks elapsed (freq integrated over time). For the win banner.
void onNewConnection(int connectionId)
New socket connected: start its handshake.
void onDisconnect(int connectionId)
Socket dropped: clean up its queue and player.
void dispatch(int connectionId, const std::string &line)
Route one line from a client.
std::optional< GameClock::Stamp > teamJoin(const std::string &team) const
When team's first player joined, or nullopt if it never did.
std::vector< int > drainPendingDisconnects()
Take the list of ids the server should disconnect this cycle.
static std::unique_ptr< FileSink > forRun(const std::string &tag, LogLevel minLevel=LogLevel::Debug)
void broadcast(const std::string &msg)
void info(std::string_view component, std::string_view msg)
void setSink(std::unique_ptr< ILogSink > sink)
void schedule(std::chrono::milliseconds delay, std::function< void()> cb)
void clear()
Drop all pending events (e.g. on game end, to freeze the world instantly).
int msUntilNext() const
Milliseconds until the next event. Pass directly to poll() as timeout. Returns -1 if the queue is emp...
CommandDispatcher _dispatcher
Server(const ServerConfig &config)
static constexpr int RESPAWN_INTERVAL_MS
Resources respawn every 20 time units (subject spec).
void _scheduleRespawn()
(Re)schedule the periodic world resource respawn.
void run()
Run the game loop until the process is stopped.
void _handleGameOver()
Freeze the world and log the winner banner. Runs once when a team wins.
const std::unordered_map< int, Player > & getPlayers() const
void spawnInitialEggs(int countPerTeam)
Spawn countPerTeam eggs for every team at random tiles (server startup).
void addWorldObserver(IWorldObserver *observer)
std::vector< std::pair< int, int > > spawnResources()
bool isGameEnded() const
True once a team has won. Game logic stops reacting to AI commands.
const std::optional< std::string > & winner() const
Winning team name, set when isGameEnded() becomes true.
std::string gwt(const std::string &team, int seconds, long long ticks)
volatile std::sig_atomic_t g_stopRequested
std::vector< int > disconnectedIds
std::vector< int > newConnections
std::vector< std::pair< int, std::string > > lines
Represents the configuration for the server application, described by:
std::vector< std::string > teamNames