about summary refs log tree commit diff
path: root/src/engine/server/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/server/server.cpp')
-rw-r--r--src/engine/server/server.cpp186
1 files changed, 178 insertions, 8 deletions
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index 65affc64..8958a405 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -361,6 +361,8 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
 	m_numLoggedInAdmins = 0;
 	
 	m_Votebans = NULL;
+	m_InfoTexts = NULL;
+	m_InfoTextInterval = -1;
 	
 	Init();
 }
@@ -374,9 +376,34 @@ CServer::~CServer()
 		delete m_Votebans;
 		m_Votebans = tmp;
 	}
+	
+	// delte info texts
+	while(m_InfoTexts != NULL)
+	{
+		CInfoText *tmp = m_InfoTexts->m_Next;
+		delete m_InfoTexts;
+		m_InfoTexts = tmp;
+	}
 }
 
 
+void CServer::UpdateLoggedInAdmins()
+{
+	bool gotAny = (m_numLoggedInAdmins > 0);
+	m_numLoggedInAdmins = 0;
+	for(int i = 0; i < MAX_CLIENTS; ++i)
+	{
+		if(m_aClients[i].m_State == CClient::STATE_INGAME && m_aClients[i].m_Authed >= AUTHED_SUBADMIN)
+		{
+			++m_numLoggedInAdmins;
+		}
+	}
+	if(gotAny != (m_numLoggedInAdmins > 0))
+	{
+		UpdateServerInfo();
+	}
+}
+
 int CServer::TrySetClientName(int ClientID, const char *pName)
 {
 	char aTrimmedName[64];
@@ -794,11 +821,6 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
 	// notify the mod about the drop
 	if(pThis->m_aClients[ClientID].m_State >= CClient::STATE_READY)
 		pThis->GameServer()->OnClientDrop(ClientID, pReason);
-	
-	// check if dropped player is admin
-	if (pThis->IsAuthed(ClientID)) {
-		pThis->DecreaseLoggedInAdmins();
-	}
 
 	pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY;
 	pThis->m_aClients[ClientID].m_aName[0] = 0;
@@ -808,6 +830,10 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
 	pThis->m_aClients[ClientID].m_AuthTries = 0;
 	pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
 	pThis->m_aClients[ClientID].m_Snapshots.PurgeAll();
+	
+	// could have been an admin
+	pThis->UpdateLoggedInAdmins();
+	
 	return 0;
 }
 
@@ -1125,7 +1151,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					char aBuf[256];
 					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID);
 					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
-					IncreaseLoggedInAdmins();
+					UpdateLoggedInAdmins();
 				}
 				else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0)
 				{
@@ -1165,7 +1191,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					char aBuf[256];
 					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (subadmin:%s)", ClientID, loginit->first.c_str());
 					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
-					IncreaseLoggedInAdmins();
+					UpdateLoggedInAdmins();
 				}
 				else if(g_Config.m_SvRconMaxTries)
 				{
@@ -1820,6 +1846,145 @@ void CServer::ConRemoveLogin(IConsole::IResult *pResult, void *pUser)
 	}
 }
 
+void CServer::ConAddInfo(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	int interval = pResult->GetInteger(0);
+	if(interval < 1 || interval > 1440)
+	{
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Interval must be between 1 and 1440.");
+		return;
+	}
+	
+	// add info text
+	CInfoText *t = new CInfoText;
+	t->m_Interval = interval;
+	t->m_Text = std::string(pResult->GetString(1));
+	// insert front
+	t->m_Next = pThis->m_InfoTexts;
+	pThis->m_InfoTexts = t;
+	
+	pThis->UpdateInfoTexts();
+	
+	// message to console
+	char aBuf[128];
+	str_format(aBuf, sizeof(aBuf), "Added the following info text: %s", t->m_Text.c_str());
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+}
+
+void CServer::ConRemoveInfo(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	int i = pResult->GetInteger(0);
+	int count = 0;
+	bool removed = false;
+	
+	CInfoText **t = &(pThis->m_InfoTexts);
+	while(*t != NULL)
+	{
+		if(count++ == i)
+		{
+			// remove
+			CInfoText *next = (*t)->m_Next;
+			delete *t;
+			*t = next;
+			removed = true;
+			break;
+		}
+		t = &((*t)->m_Next);
+	}
+	
+	pThis->UpdateInfoTexts();
+	
+	if(removed)
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text removed");
+	else
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text not found");
+}
+
+void CServer::ConListInfo(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	char aBuf[128];
+	int count = 0;
+	
+	CInfoText *t = pThis->m_InfoTexts;
+	while(t != NULL)
+	{
+		str_format(aBuf, sizeof(aBuf), "#%d interval=%d min text='%s'", count++, t->m_Interval, t->m_Text.c_str());
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+		t = t->m_Next;
+	}
+	
+	str_format(aBuf, sizeof(aBuf), "%d info text(s)", count);
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+}
+
+void CServer::UpdateInfoTexts()
+{
+	// in case that there are no info texts
+	if(m_InfoTexts == NULL)
+	{
+		m_InfoTextInterval = -1; // no interval
+		return;
+	}
+	
+	// need some random numbers later
+	init_rand();
+	
+	// update interval, set it to LCM(all text intervals)
+	m_InfoTextInterval = 1; // lowest possible interval
+	CInfoText *t = m_InfoTexts;
+	while(t != NULL)
+	{
+		m_InfoTextInterval = lcm(m_InfoTextInterval, t->m_Interval);
+		t->m_IntervalTicks = TickSpeed() * 60 * t->m_Interval; // min to ticks
+		t->m_NextTick = rand() % t->m_IntervalTicks; // variance
+		t = t->m_Next;
+	}
+	m_InfoTextInterval *= TickSpeed() * 60; // min to ticks
+	
+	// count total number of messages per interval
+	int numMsg = 0;
+	t = m_InfoTexts;
+	while(t != NULL)
+	{
+		numMsg += m_InfoTextInterval / t->m_IntervalTicks;
+		t = t->m_Next;
+	}
+	
+	// interval between messages
+	m_InfoTextMsgInterval = m_InfoTextInterval / numMsg;
+	// additional pause to sync interval and msg interval
+	m_InfoTextIntervalPause = m_InfoTextInterval % numMsg;
+}
+
+std::string CServer::GetNextInfoText()
+{
+	CInfoText *selectedText = NULL,
+		*t = m_InfoTexts;
+	// the counter r keeps track of how many equally due texts there are and actually helps so that every text has the same chance even though there are r-1 random decisions
+	int r = 1;
+	while(t != NULL)
+	{
+		// use this text if none is selected or this one is more due than the previously selected
+		// in the case that both are equally due, select one random
+		if(selectedText == NULL
+			|| t->m_NextTick < selectedText->m_NextTick
+			|| (t->m_NextTick == selectedText->m_NextTick && (rand() % ++r) == 0))
+			selectedText = t;
+		t = t->m_Next;
+	}
+	
+	// return empty string if no text applies
+	if(selectedText == NULL)
+		return std::string();
+	
+	// update tick and return string
+	selectedText->m_NextTick += selectedText->m_IntervalTicks;
+	return selectedText->m_Text;
+}
+
 void CServer::ConKick(IConsole::IResult *pResult, void *pUser)
 {
 	if(pResult->NumArguments() > 1)
@@ -1859,6 +2024,7 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
 			pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
 		}
 	}
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Quick help: kick <id> <reason=''> | ban <id> <min=5> <reason=''> | voteban <id> <sec=300> | kill <id>");
 }
 
 void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
@@ -1943,7 +2109,7 @@ void CServer::rconLogClientOut(int ClientID, const char *msg)
 		char aBuf[32];
 		str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", ClientID);
 		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
-		DecreaseLoggedInAdmins();
+		UpdateLoggedInAdmins();
 	}
 }
 
@@ -2033,6 +2199,10 @@ void CServer::RegisterCommands()
 	
 	Console()->Register("add_login", "ss", CFGFLAG_SERVER, ConAddLogin, this, "Add a subadmin login. The rcon password will be user:pass with no additional spaces.", IConsole::ACCESS_LEVEL_ADMIN);
 	Console()->Register("remove_login", "s", CFGFLAG_SERVER, ConRemoveLogin, this, "Remove a subadmin login", IConsole::ACCESS_LEVEL_ADMIN);
+	
+	Console()->Register("add_info", "is", CFGFLAG_SERVER, ConAddInfo, this, "Add a info text that is printed in the chat repeatedly in the given interval of minutes.");
+	Console()->Register("remove_info", "i", CFGFLAG_SERVER, ConRemoveInfo, this, "Remove a info text");
+	Console()->Register("list_info", "", CFGFLAG_SERVER, ConListInfo, this, "Show all info texts");
 
 	// register console commands in sub parts
 	m_ServerBan.InitServerBan(Console(), Storage(), this);