Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement server draining #549

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions NorthstarDLL/engine/hoststate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ void, __fastcall, (CHostState* self))
if (g_pServerAuthentication->m_bNeedLocalAuthForNewgame)
SetCurrentPlaylist("tdm");

if (g_pServerPresence->IsDraining())
{
spdlog::info("server drain complete (server is changing map/mode), quitting");
Cbuf_AddText(Cbuf_GetCurrentPlayer(), "quit", cmd_source_t::kCommandSrcCode);
Cbuf_Execute();
return; // TODO: this is broken; there has to be a better way to do it
}

ServerStartingOrChangingMap();

double dStartTime = Tier0::Plat_FloatTime();
Expand Down Expand Up @@ -124,6 +132,14 @@ void, __fastcall, (CHostState* self))
{
spdlog::info("HostState: ChangeLevelMP");

if (g_pServerPresence->IsDraining())
{
spdlog::info("server drain complete (server is changing map/mode), quitting");
Cbuf_AddText(Cbuf_GetCurrentPlayer(), "quit", cmd_source_t::kCommandSrcCode);
Cbuf_Execute();
return; // TODO: this is broken; there has to be a better way to do it
}

ServerStartingOrChangingMap();

double dStartTime = Tier0::Plat_FloatTime();
Expand Down
8 changes: 6 additions & 2 deletions NorthstarDLL/masterserver/masterserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,8 +817,11 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data)
if (obj.HasMember("username") && obj["username"].IsString())
username = obj["username"].GetString();


std::string reject;
if (!g_pBanSystem->IsUIDAllowed(uid))
if (g_pServerPresence->IsDraining())
reject = "Server is shutting down.";
else if (!g_pBanSystem->IsUIDAllowed(uid))
reject = "Banned from this server.";

std::string pdata;
Expand Down Expand Up @@ -1356,7 +1359,7 @@ void MasterServerPresenceReporter::InternalUpdateServer(const ServerPresence* pS
fmt::format(
"{}/server/"
"update_values?id={}&port={}&authPort=udp&name={}&description={}&map={}&playlist={}&playerCount={}&"
"maxPlayers={}&password={}",
"maxPlayers={}&isDraining={}&password={}",
hostname.c_str(),
serverId.c_str(),
threadedPresence.m_iPort,
Expand All @@ -1366,6 +1369,7 @@ void MasterServerPresenceReporter::InternalUpdateServer(const ServerPresence* pS
playlistEscaped,
threadedPresence.m_iPlayerCount,
threadedPresence.m_iMaxPlayers,
threadedPresence.m_bIsDraining,
passwordEscaped)
.c_str());

Expand Down
11 changes: 10 additions & 1 deletion NorthstarDLL/server/auth/serverauthentication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ bool,, (R2::CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer,

if (!bFakePlayer)
{
if (!g_pServerAuthentication->VerifyPlayerName(pNextPlayerToken, pName, pVerifiedName))
if (g_pServerPresence->IsDraining())
pAuthenticationFailure = "Server is shutting down.";
else if (!g_pServerAuthentication->VerifyPlayerName(pNextPlayerToken, pName, pVerifiedName))
pAuthenticationFailure = "Invalid Name.";
else if (!g_pBanSystem->IsUIDAllowed(iNextPlayerUid))
pAuthenticationFailure = "Banned From server.";
Expand Down Expand Up @@ -328,6 +330,13 @@ void,, (R2::CBaseClient* self, uint32_t unknownButAlways1, const char* pReason,

g_pServerPresence->SetPlayerCount(g_pServerAuthentication->m_PlayerAuthenticationData.size());

if (g_pServerPresence->IsDraining() && !g_pServerAuthentication->m_PlayerAuthenticationData.size())
{
spdlog::info("server drain complete (server is empty), quitting");
R2::Cbuf_AddText(R2::Cbuf_GetCurrentPlayer(), "quit", R2::cmd_source_t::kCommandSrcCode);
R2::Cbuf_Execute();
}

_CBaseClient__Disconnect(self, unknownButAlways1, buf);
}

Expand Down
20 changes: 20 additions & 0 deletions NorthstarDLL/server/serverpresence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,28 @@ void ServerPresenceManager::SetPlayerCount(const int iPlayerCount)
m_ServerPresence.m_iPlayerCount = iPlayerCount;
}

void ServerPresenceManager::SetIsDraining(bool bIsDraining)
{
m_ServerPresence.m_bIsDraining = bIsDraining;
}

bool ServerPresenceManager::IsDraining() const
{
// TODO: is there a better place for this?
return m_ServerPresence.m_bIsDraining;
}

ON_DLL_LOAD_RELIESON("engine.dll", ServerPresence, ConVar, (CModule module))
{
g_pServerPresence->CreateConVars();
Cvar_hostname = module.Offset(0x1315BAE8).Deref().RCast<ConVar*>();
}

ADD_SQFUNC("void", NSDrainServer, "bool drain, int timeout", "", ScriptContext::SERVER) {
bool drain = g_pSquirrel<ScriptContext::SERVER>->getbool(sqvm, 1);
int timeout = g_pSquirrel<ScriptContext::SERVER>->getinteger(sqvm, 2);
g_pServerPresence->SetIsDraining(drain);
// TODO: notify the connected clients when this is set?
// TODO: auto exit after a timeout or match end or player count reaches zero (use the quit command for a graceful exit)
return SQRESULT_NULL;
}
8 changes: 8 additions & 0 deletions NorthstarDLL/server/serverpresence.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ struct ServerPresence
int m_iPlayerCount;
int m_iMaxPlayers;

bool m_bIsDraining;

ServerPresence()
{
memset(this, 0, sizeof(this));
Expand All @@ -39,6 +41,8 @@ struct ServerPresence

m_iPlayerCount = obj->m_iPlayerCount;
m_iMaxPlayers = obj->m_iMaxPlayers;

m_bIsDraining = obj->m_bIsDraining;
}
};

Expand Down Expand Up @@ -72,6 +76,7 @@ class ServerPresenceManager
ConVar* Cvar_ns_report_sp_server_to_masterserver;

public:

void AddPresenceReporter(ServerPresenceReporter* reporter);

void CreateConVars();
Expand All @@ -89,6 +94,9 @@ class ServerPresenceManager
void SetMap(const char* pMapName, bool isInitialising = false);
void SetPlaylist(const char* pPlaylistName);
void SetPlayerCount(const int iPlayerCount);

void SetIsDraining(bool bIsDraining);
bool IsDraining() const;
};

extern ServerPresenceManager* g_pServerPresence;