/** * [CSRD] Uptime Limiter * * There seems to be a memory leak somewhere in the server. Definitely not a handle leak. * Supposedly, it's caused by SourceTV. * * Because I can't be bothered to figure out the full cause at the moment, I'll just let the * server restart itself every day to avoid it filling up swap and getting OOM killed. * * Disconnecting an actively connected user would be rude, so we'll wait until the server is * empty. */ #pragma semicolon 1 #include #pragma newdecls required #define PLUGIN_VERSION "0.2.1" public Plugin myinfo = { name = "[CSRD] Uptime Limiter", author = "nosoop", description = "Forces a server to auto-restart after a certain uptime when empty.", version = PLUGIN_VERSION, url = "https://git.csrd.science/" } int g_nMaxUptimeLimit = 60 * 60 * 12; public void OnPluginStart() { RegAdminCmd("csrd_uptime", AdminCmd_GetUptime, ADMFLAG_ROOT, "Outputs the server's current uptime."); } /** * Command to output current uptime. */ public Action AdminCmd_GetUptime(int client, int argc) { char uptime[64], limit[64]; FormatDuration(uptime, sizeof(uptime), GetUptime()); FormatDuration(limit, sizeof(limit), g_nMaxUptimeLimit); ReplyToCommand(client, "Uptime: %s (limit %s)", uptime, limit); return Plugin_Handled; } /** * Pretty-prints a duration of nSeconds as hours / minutes / seconds. */ void FormatDuration(char[] buffer, int maxlen, int nSeconds) { Format(buffer, maxlen, "%d hours, %d minutes, %d seconds", nSeconds / 3600, (nSeconds % 3600) / 60, nSeconds % 60); } /** * Called when the Waiting for Players round state begins. * At least one client, human or bot, must be connected for this forward to be called. * * Considering the server runs bots, we can use this forward to check if any human players are * connected to the server, and if not, we can restart the server when desirable. */ public void TF2_OnWaitingForPlayersStart() { if (GetUptime() > g_nMaxUptimeLimit) { if (!IsHumanConnected()) { LogMessage("Server has reached an uptime of %d seconds and is currently empty. " ... "Restarting...", GetUptime()); ServerCommand("quit"); } } } /** * Checks if a human player is connected to the server. * This always returns false between the OnMapEnd and OnMapStart / OnConfigsExecuted callbacks. */ bool IsHumanConnected() { for (int i = 1; i < MaxClients; i++) { if (IsClientConnected(i) && !IsFakeClient(i)) { return true; } } return (GetClientCount(false) - GetClientCount(true)) != 0; } /** * Engine time is effectively the amount of time since server startup, as far as I'm * concerned. */ int GetUptime() { float flEngineTime = GetEngineTime(); return RoundToFloor(flEngineTime); }