about summary refs log tree commit diff
diff options
context:
space:
mode:
authoroy <Tom_Adams@web.de>2015-03-19 09:57:47 +0100
committerLearath <learath2@gmail.com>2018-08-20 15:27:59 +0300
commit3f3abebebf20e8901376b929e2afcc6bdb404a3b (patch)
tree6e8f5c8c46f73487d62fa3e12ff89e969d0ea8e8
parentfc6d8b4d154049e6e3d6df9039669580f8ff747c (diff)
downloadzcatch-3f3abebebf20e8901376b929e2afcc6bdb404a3b.tar.gz
zcatch-3f3abebebf20e8901376b929e2afcc6bdb404a3b.zip
force vital check on essential cl/srv messages and added additional sequence checking
-rw-r--r--src/engine/client/client.cpp25
-rw-r--r--src/engine/server/server.cpp97
-rw-r--r--src/engine/shared/network.cpp2
-rw-r--r--src/engine/shared/network.h1
-rw-r--r--src/engine/shared/network_conn.cpp14
-rw-r--r--src/game/server/entities/character.cpp6
6 files changed, 81 insertions, 64 deletions
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index 30f92eb0..b58b1b5a 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -1027,7 +1027,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 	if(Sys)
 	{
 		// system message
-		if(Msg == NETMSG_MAP_CHANGE)
+		if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_CHANGE)
 		{
 			const char *pMap = Unpacker.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES);
 			int MapCrc = Unpacker.GetInt();
@@ -1090,7 +1090,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 				}
 			}
 		}
-		else if(Msg == NETMSG_MAP_DATA)
+		else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_DATA)
 		{
 			int Last = Unpacker.GetInt();
 			int MapCRC = Unpacker.GetInt();
@@ -1144,7 +1144,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 				}
 			}
 		}
-		else if(Msg == NETMSG_CON_READY)
+		else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_CON_READY)
 		{
 			GameClient()->OnConnected();
 		}
@@ -1153,7 +1153,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 			CMsgPacker Msg(NETMSG_PING_REPLY);
 			SendMsgEx(&Msg, 0);
 		}
-		else if(Msg == NETMSG_RCON_CMD_ADD)
+		else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_ADD)
 		{
 			const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
 			const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC);
@@ -1161,13 +1161,13 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 			if(Unpacker.Error() == 0)
 				m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp);
 		}
-		else if(Msg == NETMSG_RCON_CMD_REM)
+		else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_REM)
 		{
 			const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
 			if(Unpacker.Error() == 0)
 				m_pConsole->DeregisterTemp(pName);
 		}
-		else if(Msg == NETMSG_RCON_AUTH_STATUS)
+		else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_STATUS)
 		{
 			int Result = Unpacker.GetInt();
 			if(Unpacker.Error() == 0)
@@ -1179,7 +1179,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 			if(Old != 0 && m_UseTempRconCommands == 0)
 				m_pConsole->DeregisterTempAll();
 		}
-		else if(Msg == NETMSG_RCON_LINE)
+		else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_LINE)
 		{
 			const char *pLine = Unpacker.GetString();
 			if(Unpacker.Error() == 0)
@@ -1401,11 +1401,14 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 	}
 	else
 	{
-		// game message
-		if(m_DemoRecorder.IsRecording())
-			m_DemoRecorder.RecordMessage(pPacket->m_pData, pPacket->m_DataSize);
+		if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0)
+		{
+			// game message
+			if(m_DemoRecorder.IsRecording())
+				m_DemoRecorder.RecordMessage(pPacket->m_pData, pPacket->m_DataSize);
 
-		GameClient()->OnMessage(Msg, &Unpacker);
+			GameClient()->OnMessage(Msg, &Unpacker);
+		}
 	}
 }
 
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index f4adb967..6bcffae3 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -271,7 +271,7 @@ void CServerBan::ConBanExt(IConsole::IResult *pResult, void *pUser)
 	const char *pStr = pResult->GetString(0);
 	int Minutes = pResult->NumArguments()>1 ? clamp(pResult->GetInteger(1), 0, 44640) : defaultMinutes;
 	const char *pReason = pResult->NumArguments()>2 ? pResult->GetString(2) : "No reason given";
-	
+
 	// check if time was given or a reason instead
 	const char *time;
 	if(pResult->NumArguments() > 1)
@@ -360,14 +360,14 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
 
 	m_RconClientID = IServer::RCON_CID_SERV;
 	m_RconAuthLevel = AUTHED_SUBADMIN;
-	
+
 	// when starting there are no admins
 	m_numLoggedInAdmins = 0;
-	
+
 	m_Votebans = NULL;
 	m_InfoTexts = NULL;
 	m_InfoTextInterval = -1;
-	
+
 	Init();
 }
 
@@ -380,7 +380,7 @@ CServer::~CServer()
 		delete m_Votebans;
 		m_Votebans = tmp;
 	}
-	
+
 	// delte info texts
 	while(m_InfoTexts != NULL)
 	{
@@ -834,10 +834,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;
 }
 
@@ -931,7 +931,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 		// system message
 		if(Msg == NETMSG_INFO)
 		{
-			if(m_aClients[ClientID].m_State == CClient::STATE_AUTH)
+			if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_AUTH)
 			{
 				const char *pVersion = Unpacker.GetString(CUnpacker::SANITIZE_CC);
 				if(str_comp(pVersion, GameServer()->NetVersion()) != 0)
@@ -957,7 +957,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 		}
 		else if(Msg == NETMSG_REQUEST_MAP_DATA)
 		{
-			if(m_aClients[ClientID].m_State < CClient::STATE_CONNECTING)
+			if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) == 0 || m_aClients[ClientID].m_State < CClient::STATE_CONNECTING)
 				return;
 
 			int Chunk = Unpacker.GetInt();
@@ -994,7 +994,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 		}
 		else if(Msg == NETMSG_READY)
 		{
-			if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTING)
+			if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_CONNECTING)
 			{
 				char aAddrStr[NETADDR_MAXSTRSIZE];
 				net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
@@ -1009,7 +1009,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 		}
 		else if(Msg == NETMSG_ENTERGAME)
 		{
-			if(m_aClients[ClientID].m_State == CClient::STATE_READY && GameServer()->IsClientReady(ClientID))
+			if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_READY && GameServer()->IsClientReady(ClientID))
 			{
 				char aAddrStr[NETADDR_MAXSTRSIZE];
 				net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
@@ -1077,12 +1077,12 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 		{
 			const char *pCmd = Unpacker.GetString();
 
-			if(Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed)
+			if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed)
 			{
-				
+
 				// try to find first space
 				const char *delimiter = strchr(pCmd, ' ');
-				
+
 				if(m_aClients[ClientID].m_Authed != AUTHED_SUBADMIN
 					|| (
 						m_aClients[ClientID].m_Authed == AUTHED_SUBADMIN
@@ -1122,7 +1122,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 			const char *pPw;
 			Unpacker.GetString(); // login name, not used
 			pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC);
-			
+
 			// try matching username:password login
 			const char *delimiter = strchr(pPw, ':');
 			std::string username, password;
@@ -1133,8 +1133,8 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 				username.assign(pPw, delimiter - pPw);
 				password.assign(delimiter + 1);
 			}
-			
-			if(Unpacker.Error() == 0)
+
+			if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0)
 			{
 				if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0 && logins.empty())
 				{
@@ -1146,7 +1146,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					Msg.AddInt(1);	//authed
 					Msg.AddInt(1);	//cmdlist
 					SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
-					
+
 					m_aClients[ClientID].m_Authed = AUTHED_ADMIN;
 					int SendRconCmds = Unpacker.GetInt();
 					if(Unpacker.Error() == 0 && SendRconCmds)
@@ -1182,12 +1182,12 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					Msg.AddInt(1);	//authed
 					Msg.AddInt(1);	//cmdlist
 					SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
-					
+
 					m_aClients[ClientID].m_Authed = AUTHED_SUBADMIN;
 					m_aClients[ClientID].m_SubAdminAuthName = loginit->first;
 					m_aClients[ClientID].m_SubAdminAuthPass = loginit->second;
 					m_aClients[ClientID].m_SubAdminCommandPassFails = 0;
-					
+
 					int SendRconCmds = Unpacker.GetInt();
 					if(Unpacker.Error() == 0 && SendRconCmds)
 						m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_SUBADMIN, CFGFLAG_SERVER);
@@ -1247,7 +1247,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 	else
 	{
 		// game message
-		if(m_aClients[ClientID].m_State >= CClient::STATE_READY)
+		if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State >= CClient::STATE_READY)
 			GameServer()->OnMessage(Msg, &Unpacker, ClientID);
 	}
 }
@@ -1738,10 +1738,10 @@ void CServer::ConVoteban(IConsole::IResult *pResult, void *pUser)
 void CServer::ConUnvoteban(IConsole::IResult *pResult, void *pUser)
 {
 	CServer* pThis = static_cast<CServer *>(pUser);
-	
+
 	// index to unvoteban
 	int index = pResult->GetInteger(0);
-	
+
 	CVoteban **v = &pThis->m_Votebans;
 	for(int c = 0; *v != NULL; ++c)
 	{
@@ -1760,7 +1760,7 @@ void CServer::ConUnvoteban(IConsole::IResult *pResult, void *pUser)
 		}
 		v = &(*v)->m_Next;
 	}
-	
+
 	// not found
 	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "index was not found, please use 'votebans' to obtain an index");
 }
@@ -1788,7 +1788,7 @@ void CServer::ConVotebans(IConsole::IResult *pResult, void *pUser)
 	char aAddrStr[NETADDR_MAXSTRSIZE];
 	int time;
 	int count = 0;
-	
+
 	pThis->CleanVotebans();
 	CVoteban *v = pThis->m_Votebans;
 	NETADDR addr;
@@ -1802,7 +1802,7 @@ void CServer::ConVotebans(IConsole::IResult *pResult, void *pUser)
 		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
 		v = v->m_Next;
 	}
-	
+
 	str_format(aBuf, sizeof(aBuf), "%d votebanned ip(s)", count);
 	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
 }
@@ -1813,12 +1813,12 @@ void CServer::ConAddLogin(IConsole::IResult *pResult, void *pUser)
 	char aBuf[128];
 	std::string username(pResult->GetString(0)),
 		password(pResult->GetString(1));
-	
+
 	// insert if doesn't exist
 	if(pThis->logins.find(username) == pThis->logins.end())
 	{
 		pThis->logins[username] = password;
-		
+
 		str_format(aBuf, sizeof(aBuf), "Added login for '%s'.", username.c_str());
 		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
 	}
@@ -1834,7 +1834,7 @@ void CServer::ConRemoveLogin(IConsole::IResult *pResult, void *pUser)
 	char aBuf[128];
 	loginiterator loginit;
 	std::string username(pResult->GetString(0));
-	
+
 	// delete if exists
 	if((loginit = pThis->logins.find(username)) != pThis->logins.end())
 	{
@@ -1846,10 +1846,10 @@ void CServer::ConRemoveLogin(IConsole::IResult *pResult, void *pUser)
 				pThis->rconLogClientOut(i, "You were logged out.");
 			}
 		}
-		
+
 		// finally delete
 		pThis->logins.erase(loginit);
-		
+
 		str_format(aBuf, sizeof(aBuf), "Removed login '%s'.", username.c_str());
 		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
 	}
@@ -1868,7 +1868,7 @@ void CServer::ConAddInfo(IConsole::IResult *pResult, void *pUser)
 		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;
@@ -1876,9 +1876,9 @@ void CServer::ConAddInfo(IConsole::IResult *pResult, void *pUser)
 	// 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());
@@ -1891,7 +1891,7 @@ void CServer::ConRemoveInfo(IConsole::IResult *pResult, void *pUser)
 	int i = pResult->GetInteger(0);
 	int count = 0;
 	bool removed = false;
-	
+
 	CInfoText **t = &(pThis->m_InfoTexts);
 	while(*t != NULL)
 	{
@@ -1906,9 +1906,9 @@ void CServer::ConRemoveInfo(IConsole::IResult *pResult, void *pUser)
 		}
 		t = &((*t)->m_Next);
 	}
-	
+
 	pThis->UpdateInfoTexts();
-	
+
 	if(removed)
 		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text removed");
 	else
@@ -1920,7 +1920,7 @@ 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)
 	{
@@ -1928,7 +1928,7 @@ void CServer::ConListInfo(IConsole::IResult *pResult, void *pUser)
 		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);
 }
@@ -1941,10 +1941,10 @@ void CServer::UpdateInfoTexts()
 		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;
@@ -1956,7 +1956,7 @@ void CServer::UpdateInfoTexts()
 		t = t->m_Next;
 	}
 	m_InfoTextInterval *= TickSpeed() * 60; // min to ticks
-	
+
 	// count total number of messages per interval
 	int numMsg = 0;
 	t = m_InfoTexts;
@@ -1965,7 +1965,7 @@ void CServer::UpdateInfoTexts()
 		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
@@ -1988,11 +1988,11 @@ std::string CServer::GetNextInfoText()
 			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;
@@ -2204,15 +2204,15 @@ void CServer::RegisterCommands()
 	Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this);
 	Console()->Chain("mod_command", ConchainModCommandUpdate, this);
 	Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this);
-	
+
 	Console()->Register("voteban", "i?i", CFGFLAG_SERVER, ConVoteban, this, "Voteban a player by id");
 	Console()->Register("unvoteban", "i", CFGFLAG_SERVER, ConUnvoteban, this, "Remove voteban by index in list votebans");
 	Console()->Register("unvoteban_client", "i", CFGFLAG_SERVER, ConUnvotebanClient, this, "Remove voteban by player id");
 	Console()->Register("votebans", "", CFGFLAG_SERVER, ConVotebans, this, "Show all votebans");
-	
+
 	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");
@@ -2343,4 +2343,3 @@ int main(int argc, const char **argv) // ignore_convention
 	delete pConfig;
 	return 0;
 }
-
diff --git a/src/engine/shared/network.cpp b/src/engine/shared/network.cpp
index ada4b18a..13d62077 100644
--- a/src/engine/shared/network.cpp
+++ b/src/engine/shared/network.cpp
@@ -80,7 +80,7 @@ int CNetRecvUnpacker::FetchChunk(CNetChunk *pChunk)
 		// fill in the info
 		pChunk->m_ClientID = m_ClientID;
 		pChunk->m_Address = m_Addr;
-		pChunk->m_Flags = 0;
+		pChunk->m_Flags = Header.m_Flags;
 		pChunk->m_DataSize = Header.m_Size;
 		pChunk->m_pData = pData;
 		return 1;
diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h
index 259d600f..cbc6e560 100644
--- a/src/engine/shared/network.h
+++ b/src/engine/shared/network.h
@@ -136,6 +136,7 @@ class CNetConnection
 private:
 	unsigned short m_Sequence;
 	unsigned short m_Ack;
+	unsigned short m_PeerAck;
 	unsigned m_State;
 
 	int m_Token;
diff --git a/src/engine/shared/network_conn.cpp b/src/engine/shared/network_conn.cpp
index cd2df048..7d76d585 100644
--- a/src/engine/shared/network_conn.cpp
+++ b/src/engine/shared/network_conn.cpp
@@ -13,6 +13,7 @@ void CNetConnection::Reset()
 {
 	m_Sequence = 0;
 	m_Ack = 0;
+	m_PeerAck = 0;
 	m_RemoteClosed = 0;
 
 	m_State = NET_CONNSTATE_OFFLINE;
@@ -196,6 +197,19 @@ void CNetConnection::Disconnect(const char *pReason)
 
 int CNetConnection::Feed(CNetPacketConstruct *pPacket, NETADDR *pAddr)
 {
+	// check if actual ack value is valid(own sequence..latest peer ack)
+	if(m_Sequence >= m_PeerAck)
+	{
+		if(pPacket->m_Ack < m_PeerAck || pPacket->m_Ack > m_Sequence)
+			return 0;
+	}
+	else
+	{
+		if(pPacket->m_Ack < m_PeerAck && pPacket->m_Ack > m_Sequence)
+			return 0;
+	}
+	m_PeerAck = pPacket->m_Ack;
+
 	int64 Now = time_get();
 
 	// check if resend is requested
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index 30e32a92..cc51d856 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -440,7 +440,7 @@ void CCharacter::FireWeapon()
 			for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++)
 				Msg.AddInt(((int *)&p)[i]);
 
-			Server()->SendMsg(&Msg, 0, m_pPlayer->GetCID());
+			Server()->SendMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID());
 
 			GameServer()->CreateSound(m_Pos, SOUND_GUN_FIRE);
 		} break;
@@ -474,7 +474,7 @@ void CCharacter::FireWeapon()
 					Msg.AddInt(((int *)&p)[i]);
 			}
 
-			Server()->SendMsg(&Msg, 0,m_pPlayer->GetCID());
+			Server()->SendMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID());
 
 			GameServer()->CreateSound(m_Pos, SOUND_SHOTGUN_FIRE);
 		} break;
@@ -500,7 +500,7 @@ void CCharacter::FireWeapon()
 			Msg.AddInt(1);
 			for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++)
 				Msg.AddInt(((int *)&p)[i]);
-			Server()->SendMsg(&Msg, 0, m_pPlayer->GetCID());
+			Server()->SendMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID());
 
 			GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE);
 		} break;