From dd95c5c2477fe0378f3b40c22eb6e5223e9051cf Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 14 Sep 2025 22:38:40 +0300 Subject: [PATCH 01/17] Implement sized-strings in msg, make reliable command sizes/count variable --- libs/breakpad | 2 +- libs/crunch | 2 +- src/engine/client/cg_msgdef.h | 2 +- src/engine/client/cl_cgame.cpp | 19 ++- src/engine/client/cl_download.cpp | 123 ++++++++---------- src/engine/client/cl_input.cpp | 33 +++-- src/engine/client/cl_main.cpp | 63 ++++------ src/engine/client/cl_parse.cpp | 48 +++---- src/engine/client/cl_serverlist.cpp | 22 ++-- src/engine/client/cl_serverstatus.cpp | 72 +++++------ src/engine/client/client.h | 36 +++--- src/engine/framework/Network.cpp | 2 +- src/engine/framework/Network.h | 12 +- src/engine/qcommon/files.cpp | 22 ++-- src/engine/qcommon/msg.cpp | 173 ++++---------------------- src/engine/qcommon/qcommon.h | 11 +- src/engine/server/server.h | 18 +-- src/engine/server/sv_bot.cpp | 9 +- src/engine/server/sv_client.cpp | 86 ++++++------- src/engine/server/sv_main.cpp | 29 +---- src/engine/server/sv_snapshot.cpp | 33 ++--- src/shared/client/cg_api.cpp | 6 +- src/shared/client/cg_api.h | 2 +- 23 files changed, 310 insertions(+), 515 deletions(-) diff --git a/libs/breakpad b/libs/breakpad index ad5451e89c..fd6cc4ce9f 160000 --- a/libs/breakpad +++ b/libs/breakpad @@ -1 +1 @@ -Subproject commit ad5451e89cf451a90f598ab911f59a1458f1ebda +Subproject commit fd6cc4ce9f41047b13ca1e041726ef7dedb594bd diff --git a/libs/crunch b/libs/crunch index e242bb2a7a..371d9f0cf7 160000 --- a/libs/crunch +++ b/libs/crunch @@ -1 +1 @@ -Subproject commit e242bb2a7ae7efc44d144fd5d621b35baddeab25 +Subproject commit 371d9f0cf74ce31c5d210897c2fb366b830558c0 diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 6821a9595b..de294a472a 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -447,7 +447,7 @@ namespace LAN { >; using ResetPingsMsg = IPC::Message, int>; using ServerStatusMsg = IPC::SyncMessage< - IPC::Message, std::string, int>, + IPC::Message, std::string>, IPC::Reply >; using ResetServerStatusMsg = IPC::Message>; diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index abb50789aa..f2fef4c1d0 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -263,11 +263,11 @@ void CL_FillServerCommands(std::vector& commands, int start, int en if ( end > clc.serverCommandSequence ) { - Sys::Drop( "CL_FillServerCommand: requested a command not received" ); + Sys::Drop( "CL_FillServerCommand: requested command not received" ); } - for (int i = start; i <= end; i++) { - const char* s = clc.serverCommands[ i & ( MAX_RELIABLE_COMMANDS - 1 ) ]; + for (int i = start; i < end; i++) { + const char* s = clc.serverCommands[i].c_str(); std::string cmdText = s; if (CL_HandleServerCommand(s, cmdText)) { @@ -312,7 +312,7 @@ bool CL_GetSnapshot( int snapshotNumber, ipcSnapshot_t *snapshot ) snapshot->ps = clSnap->ps; snapshot->b.entities = clSnap->entities; - CL_FillServerCommands(snapshot->b.serverCommands, clc.lastExecutedServerCommand + 1, clSnap->serverCommandNum); + CL_FillServerCommands(snapshot->b.serverCommands, clc.lastExecutedServerCommand, clSnap->serverCommandNum); clc.lastExecutedServerCommand = clSnap->serverCommandNum; return true; @@ -1030,7 +1030,7 @@ void CGameVM::CGameRocketFrame() state.connState = cls.state; Q_strncpyz( state.servername, cls.servername, sizeof( state.servername ) ); Q_strncpyz( state.updateInfoString, cls.updateInfoString, sizeof( state.updateInfoString ) ); - Q_strncpyz( state.messageString, clc.serverMessage, sizeof( state.messageString ) ); + Q_strncpyz( state.messageString, clc.serverMessage.c_str(), sizeof(state.messageString)); state.clientNum = cl.snap.ps.clientNum; this->SendMsg(state); } @@ -1437,17 +1437,14 @@ void CGameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& cha break; case CG_LAN_SERVERSTATUS: - IPC::HandleMsg(channel, std::move(reader), [this] (const std::string& serverAddress, int len, std::string& status, int& res) { - std::unique_ptr buffer(new char[len]); - buffer[0] = '\0'; - res = CL_ServerStatus(serverAddress.c_str(), buffer.get(), len); - status.assign(buffer.get()); + IPC::HandleMsg(channel, std::move(reader), [this] (const std::string& serverAddress, std::string& status, int& res) { + res = CL_ServerStatus(serverAddress, status); }); break; case CG_LAN_RESETSERVERSTATUS: IPC::HandleMsg(channel, std::move(reader), [this] { - CL_ServerStatus(nullptr, nullptr, 0); + CL_ServerStatusReset(); }); break; diff --git a/src/engine/client/cl_download.cpp b/src/engine/client/cl_download.cpp index ce9a6c7baa..63e05f8546 100644 --- a/src/engine/client/cl_download.cpp +++ b/src/engine/client/cl_download.cpp @@ -49,9 +49,9 @@ void CL_ClearStaticDownload() { downloadLogger.Debug("Clearing the download info"); cls.downloadRestart = false; - cls.downloadTempName[ 0 ] = '\0'; - cls.downloadName[ 0 ] = '\0'; - cls.originalDownloadName[ 0 ] = '\0'; + cls.downloadTempName.clear(); + cls.downloadName.clear(); + cls.originalDownloadName.clear(); } /* @@ -121,23 +121,24 @@ Requests a file to download from the server. Stores it in the current game directory. ================= */ -static void CL_BeginDownload( const char *localName, const char *remoteName ) +static void CL_BeginDownload( const std::string& localName, const std::string& remoteName ) { downloadLogger.Debug("Requesting the download of '%s', with remote name '%s'", localName, remoteName); - Q_strncpyz( cls.downloadName, localName, sizeof( cls.downloadName ) ); - Com_sprintf( cls.downloadTempName, sizeof( cls.downloadTempName ), "%s.tmp", localName ); + cls.downloadName = localName; + cls.downloadTempName = localName; + cls.downloadTempName += ".tmp"; // Set so UI gets access to it - Cvar_Set( "cl_downloadName", remoteName ); + Cvar_Set( "cl_downloadName", remoteName.c_str() ); Cvar_Set( "cl_downloadSize", "0" ); - cl_downloadCount.Set(0); + cl_downloadCount.Set( 0 ); Cvar_SetValue( "cl_downloadTime", cls.realtime ); clc.downloadBlock = 0; // Starting new file clc.downloadCount = 0; - CL_AddReliableCommand( va( "download %s", Cmd_QuoteString( remoteName ) ) ); + CL_AddReliableCommand( Str::Format( "download %s", Cmd_QuoteString( remoteName.c_str() ) ).c_str() ); } /* @@ -149,49 +150,39 @@ A download completed or failed */ static void CL_NextDownload() { - char *s; - char *remoteName, *localName; - // We are looking to start a download here - if ( *clc.downloadList ) + if ( clc.downloadList.size() ) { - downloadLogger.Debug("CL_NextDownload downloadList is '%s'", clc.downloadList); - s = clc.downloadList; + downloadLogger.Debug( "CL_NextDownload downloadList is '%s'", clc.downloadList ); // format is: // @remotename@localname@remotename@localname, etc. - if ( *s == '@' ) - { - s++; - } - - remoteName = s; + size_t offset = clc.downloadList[0] == '@' ? 1 : 0; + size_t offset2 = clc.downloadList.find( "@", offset + 1 ); + const std::string remoteName = clc.downloadList.substr( offset, offset2 - offset ); - if ( ( s = strchr( s, '@' ) ) == nullptr ) + if ( offset2 == std::string::npos ) { CL_DownloadsComplete(); return; } - *s++ = 0; - localName = s; + offset = offset2 + 1; + offset2 = clc.downloadList.find( "@", offset2 + 1 ); - if ( ( s = strchr( s, '@' ) ) != nullptr ) - { - *s++ = 0; - } - else - { - s = localName + strlen( localName ); // point at the nul byte - } + const std::string localName = clc.downloadList.substr( offset, offset2 - 1 ); CL_BeginDownload( localName, remoteName ); cls.downloadRestart = true; // move over the rest - memmove( clc.downloadList, s, strlen( s ) + 1 ); + if ( offset2 == std::string::npos ) { + clc.downloadList.clear(); + } else { + clc.downloadList = clc.downloadList.substr( offset2 ); + } return; } @@ -215,17 +206,18 @@ void CL_InitDownloads() clc.bWWWDlAborting = false; CL_ClearStaticDownload(); - if ( cl_allowDownload->integer ) + if ( cl_allowDownload->integer ) { FS_DeletePaksWithBadChecksum(); + } // reset the redirect checksum tracking - clc.redirectedList[ 0 ] = '\0'; + clc.redirectedList.clear(); - if ( cl_allowDownload->integer && FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) ) ) + if ( cl_allowDownload->integer && FS_ComparePaks( clc.downloadList, clc.downloadList.size() ) ) { - downloadLogger.Debug("Need paks: '%s'", clc.downloadList); + downloadLogger.Debug( "Need paks: '%s'", clc.downloadList ); - if ( *clc.downloadList ) + if ( clc.downloadList.size() ) { // if autodownloading is not enabled on the server cls.state = connstate_t::CA_DOWNLOADING; @@ -277,24 +269,17 @@ void CL_WWWDownload() // taken from CL_ParseDownload clc.download = 0; - FS_SV_Rename( cls.downloadTempName, cls.originalDownloadName ); + FS_SV_Rename( cls.downloadTempName.c_str(), cls.originalDownloadName.c_str() ); - *cls.downloadTempName = *cls.downloadName = 0; + cls.downloadTempName.clear(); + cls.downloadName.clear(); Cvar_Set( "cl_downloadName", "" ); CL_AddReliableCommand( "wwwdl done" ); // tracking potential web redirects leading us to wrong checksum - only works in connected mode - if ( strlen( clc.redirectedList ) + strlen( cls.originalDownloadName ) + 1 >= sizeof( clc.redirectedList ) ) - { - // just to be safe - Log::Warn( "redirectedList overflow (%s)", clc.redirectedList ); - } - else - { - strcat( clc.redirectedList, "@" ); - strcat( clc.redirectedList, cls.originalDownloadName ); - } + clc.redirectedList += "@"; + clc.redirectedList += cls.originalDownloadName; } else { @@ -321,19 +306,13 @@ this indicates that the redirect setup is broken, and next dl attempt should NOT */ bool CL_WWWBadChecksum( const char *pakname ) { - if ( strstr( clc.redirectedList, va( "@%s@", pakname ) ) ) + if ( clc.redirectedList.find( Str::Format( "@%s@", pakname ) ) != std::string::npos ) { Log::Warn("file %s obtained through download redirect has wrong checksum" "\tthis likely means the server configuration is broken", pakname ); - if ( strlen( clc.badChecksumList ) + strlen( pakname ) + 1 >= sizeof( clc.badChecksumList ) ) - { - Log::Warn("badChecksumList overflowed (%s)", clc.badChecksumList ); - return false; - } - - strcat( clc.badChecksumList, "@" ); - strcat( clc.badChecksumList, pakname ); + clc.badChecksumList += "@"; + clc.badChecksumList += pakname; Log::Debug( "bad checksums: %s", clc.badChecksumList ); return true; } @@ -354,7 +333,7 @@ void CL_ParseDownload( msg_t *msg ) unsigned char data[ MAX_MSGLEN ]; int block; - if ( !*cls.downloadTempName ) + if ( cls.downloadTempName.empty() ) { Log::Notice( "Server sending download, but no download was requested" ); // Eat the packet anyway @@ -386,13 +365,14 @@ void CL_ParseDownload( msg_t *msg ) if ( !clc.bWWWDl ) { // server is sending us a www download - Q_strncpyz( cls.originalDownloadName, cls.downloadName, sizeof( cls.originalDownloadName ) ); - Q_strncpyz( cls.downloadName, MSG_ReadString( msg ), sizeof( cls.downloadName ) ); + cls.originalDownloadName = cls.downloadName; + cls.downloadName = MSG_ReadString( msg ); + clc.downloadSize = MSG_ReadLong( msg ); int basePathLen = MSG_ReadLong( msg ); - downloadLogger.Debug("Server sent us a new WWW DL '%s', size %i, prefix len %i", - cls.downloadName, clc.downloadSize, basePathLen); + downloadLogger.Debug( "Server sent us a new WWW DL '%s', size %i, prefix len %i", + cls.downloadName, clc.downloadSize, basePathLen ); Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); clc.bWWWDl = true; // activate wwwdl client loop @@ -400,15 +380,14 @@ void CL_ParseDownload( msg_t *msg ) cls.state = connstate_t::CA_DOWNLOADING; // make sure the server is not trying to redirect us again on a bad checksum - if ( strstr( clc.badChecksumList, va( "@%s", cls.originalDownloadName ) ) ) - { + if ( clc.badChecksumList.find( Str::Format( "@%s", cls.originalDownloadName ) ) != std::string::npos ) { Log::Notice( "refusing redirect to %s by server (bad checksum)", cls.downloadName ); CL_AddReliableCommand( "wwwdl fail" ); clc.bWWWDlAborting = true; return; } - if ( !DL_BeginDownload( cls.downloadTempName, cls.downloadName, basePathLen ) ) + if ( !DL_BeginDownload( cls.downloadTempName.c_str(), cls.downloadName.c_str(), basePathLen ) ) { // setting bWWWDl to false after sending the wwwdl fail doesn't work // not sure why, but I suspect we have to eat all remaining block -1 that the server has sent us @@ -424,7 +403,6 @@ void CL_ParseDownload( msg_t *msg ) else { // server keeps sending that message till we ack it, eat and ignore - //MSG_ReadLong( msg ); MSG_ReadString( msg ); MSG_ReadLong( msg ); MSG_ReadLong( msg ); @@ -442,7 +420,7 @@ void CL_ParseDownload( msg_t *msg ) if ( clc.downloadSize < 0 ) { - Sys::Drop( "%s", MSG_ReadString( msg ) ); + Sys::Drop( MSG_ReadString( msg ) ); } } @@ -466,7 +444,7 @@ void CL_ParseDownload( msg_t *msg ) // open the file if not opened yet if ( !clc.download ) { - clc.download = FS_SV_FOpenFileWrite( cls.downloadTempName ); + clc.download = FS_SV_FOpenFileWrite( cls.downloadTempName.c_str() ); if ( !clc.download ) { @@ -500,10 +478,11 @@ void CL_ParseDownload( msg_t *msg ) clc.download = 0; // rename the file - FS_SV_Rename( cls.downloadTempName, cls.downloadName ); + FS_SV_Rename( cls.downloadTempName.c_str(), cls.downloadName.c_str() ); } - *cls.downloadTempName = *cls.downloadName = 0; + cls.downloadTempName.clear(); + cls.downloadName.clear(); Cvar_Set( "cl_downloadName", "" ); // send intentions now diff --git a/src/engine/client/cl_input.cpp b/src/engine/client/cl_input.cpp index e7438b24d0..615fc2fb51 100644 --- a/src/engine/client/cl_input.cpp +++ b/src/engine/client/cl_input.cpp @@ -802,14 +802,16 @@ bool CL_ReadyToSendPacket() } // If we are downloading, we send no less than 50ms between packets - if ( *cls.downloadTempName && cls.realtime - clc.lastPacketSentTime < 50 ) + if ( cls.downloadTempName.size() && cls.realtime - clc.lastPacketSentTime < 50 ) { return false; } // if we don't have a valid gamestate yet, only send // one packet a second - if ( cls.state != connstate_t::CA_ACTIVE && cls.state != connstate_t::CA_PRIMED && !*cls.downloadTempName && cls.realtime - clc.lastPacketSentTime < 1000 ) + if ( cls.state != connstate_t::CA_ACTIVE && cls.state != connstate_t::CA_PRIMED + && cls.downloadTempName.empty() + && cls.realtime - clc.lastPacketSentTime < 1000 ) { return false; } @@ -873,11 +875,6 @@ void CL_WritePacket() { msg_t buf; byte data[ MAX_MSGLEN ]; - int j; - usercmd_t *cmd, *oldcmd; - int packetNum; - int oldPacketNum; - int count; // don't send anything if playing back a demo if ( clc.demoplaying ) @@ -886,7 +883,7 @@ void CL_WritePacket() } usercmd_t nullcmd{}; - oldcmd = &nullcmd; + usercmd_t* oldcmd = &nullcmd; MSG_Init( &buf, data, sizeof( data ) ); @@ -906,11 +903,11 @@ void CL_WritePacket() // write any unacknowledged clientCommands // NOTE TTimo: if you verbose this, you will see that there are quite a few duplicates // typically several unacknowledged cp or userinfo commands stacked up - for ( int i = clc.reliableAcknowledge + 1; i <= clc.reliableSequence; i++ ) + for ( uint32_t i = 0; i < clc.reliableSequence - clc.reliableAcknowledge; i++ ) { MSG_WriteByte( &buf, clc_clientCommand ); - MSG_WriteLong( &buf, i ); - MSG_WriteString( &buf, clc.reliableCommands[ i & ( MAX_RELIABLE_COMMANDS - 1 ) ] ); + MSG_WriteLong( &buf, i + clc.reliableAcknowledge ); + MSG_WriteString( &buf, clc.reliableCommands[i] ); } // we want to send all the usercmds that were generated in the last @@ -925,8 +922,8 @@ void CL_WritePacket() Cvar_Set( "cl_packetdup", "5" ); } - oldPacketNum = ( clc.netchan.outgoingSequence - 1 - cl_packetdup->integer ) & PACKET_MASK; - count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber; + int oldPacketNum = ( clc.netchan.outgoingSequence - 1 - cl_packetdup->integer ) & PACKET_MASK; + int count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber; if ( count > MAX_PACKET_USERCMDS ) { @@ -957,17 +954,15 @@ void CL_WritePacket() // write all the commands, including the predicted command for ( int i = 0; i < count; i++ ) { - j = ( cl.cmdNumber - count + i + 1 ) & CMD_MASK; - cmd = &cl.cmds[ j ]; + int j = ( cl.cmdNumber - count + i + 1 ) & CMD_MASK; + usercmd_t* cmd = &cl.cmds[ j ]; MSG_WriteDeltaUsercmd( &buf, oldcmd, cmd ); oldcmd = cmd; } } - // // deliver the message - // - packetNum = clc.netchan.outgoingSequence & PACKET_MASK; + int packetNum = clc.netchan.outgoingSequence & PACKET_MASK; cl.outPackets[ packetNum ].p_realtime = cls.realtime; cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime; cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber; @@ -975,7 +970,7 @@ void CL_WritePacket() if ( cl_showSend->integer ) { - Log::Notice("%i ", buf.cursize ); + Log::Notice( "%i ", buf.cursize ); } MSG_WriteByte( &buf, clc_EOF ); diff --git a/src/engine/client/cl_main.cpp b/src/engine/client/cl_main.cpp index f80b735470..738f747b13 100644 --- a/src/engine/client/cl_main.cpp +++ b/src/engine/client/cl_main.cpp @@ -206,8 +206,6 @@ not have future usercmd_t executed before it is executed */ void CL_AddReliableCommand( const char *cmd ) { - int index; - // catch empty commands while ( *cmd && *cmd <= ' ' ) { @@ -219,16 +217,9 @@ void CL_AddReliableCommand( const char *cmd ) return; } - // if we would be losing an old command that hasn't been acknowledged, - // we must drop the connection - if ( clc.reliableSequence - clc.reliableAcknowledge > MAX_RELIABLE_COMMANDS ) - { - Sys::Drop( "Client command overflow" ); - } + clc.reliableCommands.push_back( cmd ); clc.reliableSequence++; - index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 ); - Q_strncpyz( clc.reliableCommands[ index ], cmd, sizeof( clc.reliableCommands[ index ] ) ); } /* @@ -376,8 +367,9 @@ std::string GenerateDemoName() void CL_Record(std::string demo_name) { - if ( demo_name.empty() ) - demo_name = GenerateDemoName(); + if ( demo_name.empty() ) { + demo_name = GenerateDemoName(); + } std::string file_name = Str::Format("demos/%s.dm_%d", demo_name, PROTOCOL_VERSION); clc.demofile = FS_FOpenFileWrite(file_name.c_str()); @@ -389,7 +381,7 @@ void CL_Record(std::string demo_name) Log::Notice( "recording to %s.", file_name ); clc.demorecording = true; - Q_strncpyz(clc.demoName, demo_name.c_str(), std::min(demo_name.size(), MAX_QPATH)); + clc.demoName = demo_name; Cvar::SetValueForce(cvar_demo_status_isrecording.Name(), "1"); Cvar::SetValueForce(cvar_demo_status_filename.Name(), demo_name); @@ -419,7 +411,7 @@ void CL_Record(std::string demo_name) MSG_WriteByte( &buf, svc_configstring ); MSG_WriteShort( &buf, i ); - MSG_WriteBigString( &buf, cl.gameState[i].c_str() ); + MSG_WriteString( &buf, cl.gameState[i] ); } // baselines @@ -597,7 +589,7 @@ class DemoPlayCmd: public Cmd::StaticCmd { Sys::Drop("couldn't open %s", name); } - Q_strncpyz(clc.demoName, arg, sizeof(clc.demoName)); + clc.demoName = arg; Con_Close(); @@ -719,7 +711,7 @@ void CL_MapLoading() { cls.state = connstate_t::CA_CONNECTED; // so the connect screen is drawn memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) ); - memset( clc.serverMessage, 0, sizeof( clc.serverMessage ) ); + clc.serverMessage.clear(); cl.gameState.fill(""); clc.lastPacketSentTime = -9999; SCR_UpdateScreen(); @@ -802,7 +794,8 @@ void CL_Disconnect( bool showMainMenu ) clc.download = 0; } - *cls.downloadTempName = *cls.downloadName = 0; + cls.downloadName.clear(); + cls.downloadTempName.clear(); Cvar_Set( "cl_downloadName", "" ); StopVideo(); @@ -1009,7 +1002,7 @@ void CL_Connect_f() Audio::StopAllSounds(); // NERVE - SMF // clear any previous "server full" type messages - clc.serverMessage[ 0 ] = 0; + clc.serverMessage.clear(); if ( com_sv_running.Get() && !strcmp( server, "loopback" ) ) { @@ -1603,7 +1596,6 @@ void CL_CheckForResend() { int port; char info[ MAX_INFO_STRING ]; - char data[ MAX_INFO_STRING ]; // don't send anything if playing back a demo if ( clc.demoplaying ) @@ -1640,15 +1632,21 @@ void CL_CheckForResend() port = Cvar_VariableValue( "net_qport" ); Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO, false ), sizeof( info ) ); - Info_SetValueForKey( info, "protocol", va( "%i", PROTOCOL_VERSION ), false ); - Info_SetValueForKey( info, "qport", va( "%i", port ), false ); + Info_SetValueForKey( info, "protocol", Str::Format( "%i", PROTOCOL_VERSION ).c_str(), false); + Info_SetValueForKey( info, "qport", Str::Format( "%i", port ).c_str(), false); Info_SetValueForKey( info, "challenge", clc.challenge.c_str(), false ); Info_SetValueForKey( info, "pubkey", key, false ); - Com_sprintf( data, sizeof(data), "connect %s", Cmd_QuoteString( info ) ); + std::string data = Str::Format( "connect %s", Cmd_QuoteString( info ) ); + // This will be read by MSG_ReadString, which expects the string length + data.resize( data.size() + 4 ); + std::move( data.data(), data.data() + data.size() - 4, data.data() + 4 ); + + uint32_t* sizeEncode = ( uint32_t* ) data.data(); + *sizeEncode = data.size() - 4; Net::OutOfBandData( netsrc_t::NS_CLIENT, clc.serverAddress, - reinterpret_cast( data ), strlen( data ) ); + reinterpret_cast( data.data() ), data.size() ); // the most current userinfo has been sent, so watch for any // newer changes to userinfo variables cvar_modifiedFlags &= ~CVAR_USERINFO; @@ -1714,21 +1712,14 @@ print OOB are the only messages we handle markups in */ void CL_PrintPacket( msg_t *msg ) { - char *s; + clc.serverMessage = MSG_ReadString( msg ); - s = MSG_ReadBigString( msg ); - - if ( !Q_strnicmp( s, "[err_dialog]", 12 ) ) - { - Q_strncpyz( clc.serverMessage, s + 12, sizeof( clc.serverMessage ) ); - Sys::Drop( "^3Server disconnected:\n^7%s", clc.serverMessage ); - } - else + if ( clc.serverMessage.substr( 12 ) == "[err_dialog]" ) { - Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) ); + Sys::Drop( "^3Server disconnected:\n^7%s", clc.serverMessage.substr( 12, clc.serverMessage.size() ) ); } - Log::Notice("%s", clc.serverMessage ); + Log::Notice( clc.serverMessage ); } /* @@ -1743,7 +1734,7 @@ static void CL_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) MSG_BeginReadingOOB( msg ); MSG_ReadLong( msg ); // skip the -1 - Cmd::Args args(MSG_ReadStringLine( msg )); + Cmd::Args args( MSG_ReadString( msg, false ) ); if ( args.Argc() < 1 ) { @@ -1870,7 +1861,7 @@ static void CL_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) // prints a n error message returned by the server if ( args.Argv(0) == "error" ) { - Log::Warn( MSG_ReadStringLine(msg) ); + Log::Warn( MSG_ReadString( msg, false ) ); return; } diff --git a/src/engine/client/cl_parse.cpp b/src/engine/client/cl_parse.cpp index cf91714f19..850b12a688 100644 --- a/src/engine/client/cl_parse.cpp +++ b/src/engine/client/cl_parse.cpp @@ -179,10 +179,6 @@ void CL_ParseSnapshot( msg_t *msg ) int oldMessageNum; int i, packetNum; - // get the reliable sequence acknowledge number - // NOTE: now sent with all server to client messages - //clc.reliableAcknowledge = MSG_ReadLong( msg ); - // read in the new snapshot to a temporary buffer // we will only copy to cl.snap if it is valid clSnapshot_t newSnap{}; @@ -406,9 +402,6 @@ void CL_ParseGamestate( msg_t *msg ) if ( !cl.reading ) { // wipe local client state CL_ClearState(); - - // a gamestate always marks a server command sequence - clc.serverCommandSequence = MSG_ReadLong( msg ); } // parse all the configstrings and baselines @@ -430,8 +423,7 @@ void CL_ParseGamestate( msg_t *msg ) Sys::Drop( "configstring > MAX_CONFIGSTRINGS" ); } - const char* str = MSG_ReadBigString( msg ); - cl.gameState[i] = str; + cl.gameState[i] = MSG_ReadString( msg ); } else if ( cmd == svc_baseline ) { @@ -483,23 +475,18 @@ when it transitions a snapshot */ void CL_ParseCommandString( msg_t *msg ) { - char *s; - int seq; - int index; + uint32_t seq = MSG_ReadLong( msg ); - seq = MSG_ReadLong( msg ); - s = MSG_ReadString( msg ); - - // see if we have already executed stored it off + // see if we have already executed or stored it off if ( clc.serverCommandSequence >= seq ) { + MSG_ReadString( msg ); // Skip the string return; } - clc.serverCommandSequence = seq; + clc.serverCommands.push_back( MSG_ReadString( msg ) ); - index = seq & ( MAX_RELIABLE_COMMANDS - 1 ); - Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) ); + clc.serverCommandSequence++; } /* @@ -509,11 +496,6 @@ CL_ParseServerMessage */ void CL_ParseServerMessage( msg_t *msg ) { - int cmd; -// msg_t msgback; - -// msgback = *msg; - if ( cl_shownet->integer == 1 ) { Log::Notice("%i ", msg->cursize ); @@ -528,15 +510,19 @@ void CL_ParseServerMessage( msg_t *msg ) // get the reliable sequence acknowledge number clc.reliableAcknowledge = MSG_ReadLong( msg ); - // - if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) - { - clc.reliableAcknowledge = clc.reliableSequence; + if ( clc.reliableAcknowledge != clc.previousAcknowledge ) { + std::vector::iterator start = clc.reliableCommands.begin() + ( clc.reliableSequence - clc.reliableAcknowledge ); + std::vector::iterator end = clc.reliableCommands.end(); + + std::move( start, end, clc.reliableCommands.begin() ); + clc.reliableCommands.erase( start, end ); + + clc.previousAcknowledge = clc.reliableAcknowledge; } - // + clc.reliableSequence = std::max( clc.reliableSequence, clc.reliableAcknowledge ); + // parse the message - // while (true) { if ( msg->readcount > msg->cursize ) @@ -544,7 +530,7 @@ void CL_ParseServerMessage( msg_t *msg ) Sys::Drop( "CL_ParseServerMessage: read past end of server message" ); } - cmd = MSG_ReadByte( msg ); + int cmd = MSG_ReadByte( msg ); if ( cmd < 0 || cmd == svc_EOF ) { diff --git a/src/engine/client/cl_serverlist.cpp b/src/engine/client/cl_serverlist.cpp index 09f99d2e15..cb339c5892 100644 --- a/src/engine/client/cl_serverlist.cpp +++ b/src/engine/client/cl_serverlist.cpp @@ -523,17 +523,14 @@ CL_ServerInfoPacket */ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) { - int i; char info[ MAX_INFO_STRING ]; -// char* str; - char *infoString; int prot; const char *gameName; - infoString = MSG_ReadString( msg ); + std::string infoString = MSG_ReadString( msg ); // if this isn't the correct protocol version, ignore it - prot = atoi( Info_ValueForKey( infoString, "protocol" ) ); + prot = atoi( Info_ValueForKey( infoString.c_str(), "protocol" ) ); if ( prot != PROTOCOL_VERSION ) { @@ -542,7 +539,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) } // Arnout: if this isn't the correct game, ignore it - gameName = Info_ValueForKey( infoString, "gamename" ); + gameName = Info_ValueForKey( infoString.c_str(), "gamename" ); if ( !gameName[ 0 ] || Q_stricmp( gameName, GAMENAME_STRING ) ) { @@ -551,11 +548,11 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) } // iterate servers waiting for ping response - for ( i = 0; i < MAX_PINGREQUESTS; i++ ) + for ( int i = 0; i < MAX_PINGREQUESTS; i++ ) { if ( cl_pinglist[ i ].adr.port && cl_pinglist[ i ].time == -1 && NET_CompareAdr( from, cl_pinglist[i].adr ) ) { - if ( strcmp( cl_pinglist[ i ].challenge, Info_ValueForKey( infoString, "challenge" ) ) ) + if ( strcmp( cl_pinglist[ i ].challenge, Info_ValueForKey( infoString.c_str(), "challenge" ) ) ) { serverInfoLog.Verbose( "wrong challenge for ping response from %s", NET_AdrToString( from ) ); return; @@ -567,7 +564,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) serverInfoLog.Debug( "ping time %dms from %s", cl_pinglist[ i ].time, NET_AdrToString( from ) ); // save of info - Q_strncpyz( cl_pinglist[ i ].info, infoString, sizeof( cl_pinglist[ i ].info ) ); + Q_strncpyz( cl_pinglist[ i ].info, infoString.c_str(), sizeof( cl_pinglist[ i ].info ) ); // tack on the net type switch ( from.type ) @@ -586,7 +583,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) break; } - CL_SetServerInfoByAddress( from, infoString, cl_pinglist[ i ].responseProto, + CL_SetServerInfoByAddress( from, infoString.c_str(), cl_pinglist[ i ].responseProto, pingStatus_t::COMPLETE, cl_pinglist[ i ].time ); return; @@ -599,7 +596,8 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) return; } - for ( i = 0; i < MAX_OTHER_SERVERS; i++ ) + int i = 0; + for ( ; i < MAX_OTHER_SERVERS; i++ ) { // empty slot if ( cls.localServers[ i ].adr.port == 0 ) @@ -629,7 +627,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) cls.localServers[ i ].responseProto = serverResponseProtocol_t::UNKNOWN; cls.localServers[ i ].infoString.clear(); - Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING ); + Q_strncpyz( info, MSG_ReadString( msg ).c_str(), MAX_INFO_STRING ); // TODO when does this happen? if ( info[ 0 ] ) diff --git a/src/engine/client/cl_serverstatus.cpp b/src/engine/client/cl_serverstatus.cpp index c43d065c1b..c6a1d75125 100644 --- a/src/engine/client/cl_serverstatus.cpp +++ b/src/engine/client/cl_serverstatus.cpp @@ -44,7 +44,7 @@ Maryland 20850 USA. struct serverStatus_t { - char string[ BIG_INFO_STRING ]; + std::string string; netadr_t address; int time, startTime; bool pending; @@ -112,16 +112,12 @@ static serverStatus_t *CL_GetServerStatus( const netadr_t& from ) CL_ServerStatus =================== */ -int CL_ServerStatus( const char *serverAddress, char *serverStatusString, int maxLen ) +bool CL_ServerStatus( const std::string& serverAddress, std::string& serverStatusString ) { - int i; - netadr_t to; - serverStatus_t *serverStatus; - // if no server address then reset all server status requests - if ( !serverAddress ) + if ( serverAddress.empty() ) { - for ( i = 0; i < MAX_SERVERSTATUSREQUESTS; i++ ) + for ( int i = 0; i < MAX_SERVERSTATUSREQUESTS; i++ ) { cl_serverStatusList[ i ].address.port = 0; cl_serverStatusList[ i ].retrieved = true; @@ -131,19 +127,13 @@ int CL_ServerStatus( const char *serverAddress, char *serverStatusString, int ma } // get the address - if ( !NET_StringToAdr( serverAddress, &to, netadrtype_t::NA_UNSPEC ) ) + netadr_t to; + if ( !NET_StringToAdr( serverAddress.c_str(), &to, netadrtype_t::NA_UNSPEC ) ) { return false; } - serverStatus = CL_GetServerStatus( to ); - - // if no server status string then reset the server status request for this address - if ( !serverStatusString ) - { - serverStatus->retrieved = true; - return false; - } + serverStatus_t* serverStatus = CL_GetServerStatus( to ); // if this server status request has the same address if ( NET_CompareAdr( to, serverStatus->address ) ) @@ -151,7 +141,7 @@ int CL_ServerStatus( const char *serverAddress, char *serverStatusString, int ma // if we received a response for this server status request if ( !serverStatus->pending ) { - Q_strncpyz( serverStatusString, serverStatus->string, maxLen ); + serverStatusString = serverStatus->string; serverStatus->retrieved = true; serverStatus->startTime = 0; return true; @@ -184,6 +174,13 @@ int CL_ServerStatus( const char *serverAddress, char *serverStatusString, int ma return false; } +void CL_ServerStatusReset() { + for ( int i = 0; i < MAX_SERVERSTATUSREQUESTS; i++ ) { + cl_serverStatusList[i].address.port = 0; + cl_serverStatusList[i].retrieved = true; + } +} + /* =================== CL_ServerStatusResponse @@ -191,14 +188,9 @@ CL_ServerStatusResponse */ void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ) { - const char *s; - int i, score, ping; - int len; - serverStatus_t *serverStatus; - - serverStatus = nullptr; + serverStatus_t *serverStatus = nullptr; - for ( i = 0; i < MAX_SERVERSTATUSREQUESTS; i++ ) + for ( int i = 0; i < MAX_SERVERSTATUSREQUESTS; i++ ) { if ( NET_CompareAdr( from, cl_serverStatusList[ i ].address ) ) { @@ -213,22 +205,18 @@ void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ) return; } - s = MSG_ReadStringLine( msg ); - - len = 0; - Com_sprintf( &serverStatus->string[ len ], sizeof( serverStatus->string ) - len, "%s", s ); + serverStatus->string = MSG_ReadString( msg, false ); if ( serverStatus->print ) { Log::CommandInteractionMessage("Server settings:" ); // print cvars - for (const auto& kv: InfoStringToMap(s)) { + for (const auto& kv: InfoStringToMap( serverStatus->string )) { Log::CommandInteractionMessage(Str::Format("%-24s%s", kv.first, kv.second)); } } - len = strlen( serverStatus->string ); - Com_sprintf( &serverStatus->string[ len ], sizeof( serverStatus->string ) - len, "\\" ); + serverStatus->string += "\\"; if ( serverStatus->print ) { @@ -236,14 +224,23 @@ void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ) Log::CommandInteractionMessage( "num: score: ping: name:" ); } - for ( i = 0, s = MSG_ReadStringLine( msg ); *s; s = MSG_ReadStringLine( msg ), i++ ) + uint32_t i = 0; + while ( true ) { - len = strlen( serverStatus->string ); - Com_sprintf( &serverStatus->string[ len ], sizeof( serverStatus->string ) - len, "\\%s", s ); + const std::string string = MSG_ReadString( msg, false ); + + if ( string.empty() ) { + break; + } + + serverStatus->string += "\\" + string; if ( serverStatus->print ) { - score = ping = 0; + int ping = 0; + int score = 0; + const char* s = string.c_str(); + sscanf( s, "%d %d", &score, &ping ); s = strchr( s, ' ' ); @@ -265,8 +262,7 @@ void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ) } } - len = strlen( serverStatus->string ); - Com_sprintf( &serverStatus->string[ len ], sizeof( serverStatus->string ) - len, "\\" ); + serverStatus->string += "\\"; serverStatus->time = Sys::Milliseconds(); serverStatus->address = from; diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 834a857e56..604e29b6ba 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -182,15 +182,15 @@ struct clientConnection_t netadr_t serverAddress; int connectTime; // for connection retransmits int connectPacketCount; // for display on connection dialog - char serverMessage[ MAX_STRING_TOKENS ]; // for display on connection dialog + std::string serverMessage; // for display on connection dialog std::string challenge; // from the server to use for connecting // these are our reliable messages that go to the server - int reliableSequence; - int reliableAcknowledge; // the last one the server has executed - // TTimo - NOTE: incidentally, reliableCommands[0] is never used (always start at reliableAcknowledge+1) - char reliableCommands[ MAX_RELIABLE_COMMANDS ][ MAX_TOKEN_CHARS ]; + uint32_t reliableSequence; + uint32_t reliableAcknowledge = 0; // the last one the server has executed + uint32_t previousAcknowledge = 0; + std::vector reliableCommands; // server message (unreliable) and command (reliable) sequence // numbers are NOT cleared at level changes, but continue to @@ -201,9 +201,9 @@ struct clientConnection_t int serverMessageSequence; // reliable messages received from server - int serverCommandSequence; + int serverCommandSequence = 0; int lastExecutedServerCommand; // last server command grabbed or executed with CL_GetServerCommand - char serverCommands[ MAX_RELIABLE_COMMANDS ][ MAX_TOKEN_CHARS ]; + std::vector serverCommands; // file transfer from server fileHandle_t download; @@ -211,17 +211,16 @@ struct clientConnection_t int downloadBlock; // block we are waiting for int downloadCount; // how many bytes we got int downloadSize; // how many bytes we got - char downloadList[ MAX_INFO_STRING ]; // list of paks we need to download + std::string downloadList; // list of paks we need to download // www downloading bool bWWWDl; // we have a www download going bool bWWWDlAborting; // disable the CL_WWWDownload until server gets us a gamestate (used for aborts) - char redirectedList[ MAX_INFO_STRING ]; // list of files that we downloaded through a redirect since last FS_ComparePaks - char badChecksumList[ MAX_INFO_STRING ]; // list of files for which wwwdl redirect is broken (wrong checksum) - char newsString[ MAX_NEWS_STRING ]; + std::string redirectedList; // list of files that we downloaded through a redirect since last FS_ComparePaks + std::string badChecksumList; // list of files for which wwwdl redirect is broken (wrong checksum) // demo information - char demoName[ MAX_QPATH ]; + std::string demoName; bool demorecording; bool demoplaying; bool demowaiting; // don't record until a non-delta message is received @@ -312,9 +311,9 @@ struct clientStatic_t // www downloading // in the static stuff since this may have to survive server disconnects (but disconnected dl was removed so this is maybe no longer true?) // if new stuff gets added, CL_ClearStaticDownload code needs to be updated for clear up - char downloadName[ MAX_OSPATH ]; - char downloadTempName[ MAX_OSPATH ]; // in wwwdl mode, this is OS path (it's a qpath otherwise) - char originalDownloadName[ MAX_OSPATH ]; // if we get a redirect, keep a copy of the original file path + std::string downloadName; + std::string downloadTempName; // in wwwdl mode, this is OS path (it's a qpath otherwise) + std::string originalDownloadName; // if we get a redirect, keep a copy of the original file path bool downloadRestart; // if true, we need to do another FS_Restart because we downloaded a pak }; @@ -460,9 +459,10 @@ void CL_Record(std::string demo_name); // // cl_serverstatus.cpp // -int CL_ServerStatus( const char *serverAddress, char *serverStatusString, int maxLen ); -void CL_ServerStatus_f(); -void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ); +bool CL_ServerStatus( const std::string& serverAddress, std::string& serverStatusString ); +void CL_ServerStatusReset(); +void CL_ServerStatus_f(); +void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ); // // cl_keys (for input usage) diff --git a/src/engine/framework/Network.cpp b/src/engine/framework/Network.cpp index ca21b17063..62ecb5488b 100644 --- a/src/engine/framework/Network.cpp +++ b/src/engine/framework/Network.cpp @@ -66,7 +66,7 @@ void OutOfBandData( netsrc_t sock, const netadr_t& adr, byte *data, std::size_t msg_t mbuf{}; mbuf.data = buf; mbuf.cursize = size; - Huff_Compress( &mbuf, 12 ); + Huff_Compress( &mbuf, 16 ); // send the datagram NET_SendPacket( sock, mbuf.cursize, mbuf.data, adr ); } diff --git a/src/engine/framework/Network.h b/src/engine/framework/Network.h index 176ca0da78..ca3ebe333e 100644 --- a/src/engine/framework/Network.h +++ b/src/engine/framework/Network.h @@ -41,7 +41,17 @@ inline const std::string& OOBHeader() template void OutOfBandPrint( netsrc_t net_socket, const netadr_t& adr, Str::StringRef format, Args&&... args ) { - std::string message = OOBHeader() + Str::Format( format, std::forward(args)... ); + std::string message = Str::Format( format, std::forward( args )... ); + + // This will be read by MSG_ReadString, which expects the string length + message.resize( message.size() + 4 ); + std::move( message.data(), message.data() + message.size() - 4, message.data() + 4 ); + + uint32_t* sizeEncode = ( uint32_t* ) message.data(); + *sizeEncode = message.size() - 4; + + message = OOBHeader() + message; + NET_SendPacket( net_socket, message.size(), message.c_str(), adr ); } diff --git a/src/engine/qcommon/files.cpp b/src/engine/qcommon/files.cpp index e2b97a861e..fe22bc2d73 100644 --- a/src/engine/qcommon/files.cpp +++ b/src/engine/qcommon/files.cpp @@ -747,19 +747,21 @@ void FS_DeletePaksWithBadChecksum() { } } -bool FS_ComparePaks(char* neededpaks, int len) +bool FS_ComparePaks( std::string& neededpaks, int len ) { - *neededpaks = '\0'; for (const missingPak_t& x: fs_missingPaks) { - Q_strcat(neededpaks, len, "@"); - Q_strcat(neededpaks, len, FS::MakePakName(x.name, x.version, x.checksum).c_str()); - Q_strcat(neededpaks, len, "@"); - std::string pakName = Str::Format("pkg/%s", FS::MakePakName(x.name, x.version)); - if (FS::HomePath::FileExists(pakName)) - Q_strcat(neededpaks, len, Str::Format("pkg/%s", FS::MakePakName(x.name, x.version, x.checksum)).c_str()); - else - Q_strcat(neededpaks, len, pakName.c_str()); + neededpaks += "@"; + neededpaks += FS::MakePakName( x.name, x.version, x.checksum ); + neededpaks += "@"; + + std::string pakName = Str::Format( "pkg/%s", FS::MakePakName( x.name, x.version ) ); + if ( FS::HomePath::FileExists( pakName ) ) { + neededpaks += Str::Format( "pkg/%s", FS::MakePakName( x.name, x.version, x.checksum ) ); + } else { + neededpaks += pakName; + } } + return !fs_missingPaks.empty(); } #endif // !BUILD_SERVER diff --git a/src/engine/qcommon/msg.cpp b/src/engine/qcommon/msg.cpp index ed72b56b15..b020b5d55e 100644 --- a/src/engine/qcommon/msg.cpp +++ b/src/engine/qcommon/msg.cpp @@ -138,8 +138,6 @@ bit functions // negative bit values include signs void MSG_WriteBits( msg_t *msg, int value, int bits ) { - int i; - msg->uncompsize += bits; // NERVE - SMF - net debugging // this isn't an exact overflow check, but close enough @@ -194,11 +192,9 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) if ( bits & 7 ) { - int nbits; - - nbits = bits & 7; + int nbits = bits & 7; - for ( i = 0; i < nbits; i++ ) + for ( int i = 0; i < nbits; i++ ) { Huff_putBit( ( value & 1 ), msg->data, &msg->bit ); value = ( value >> 1 ); @@ -209,7 +205,7 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) if ( bits ) { - for ( i = 0; i < bits; i += 8 ) + for ( int i = 0; i < bits; i += 8 ) { Huff_offsetTransmit( &msgHuff.compressor, ( value & 0xff ), msg->data, &msg->bit ); value = ( value >> 8 ); @@ -222,13 +218,7 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) int MSG_ReadBits( msg_t *msg, int bits ) { - int value; - int get; bool sgn; - int i; - - value = 0; - if ( bits < 0 ) { bits = -bits; @@ -239,6 +229,7 @@ int MSG_ReadBits( msg_t *msg, int bits ) sgn = false; } + int value = 0; if ( msg->oob ) { if ( bits == 8 ) @@ -270,6 +261,7 @@ int MSG_ReadBits( msg_t *msg, int bits ) } else { + int i; for ( i = 0; i < ( bits & 7 ); i++ ) { value |= ( Huff_getBit( msg->data, &msg->bit ) << i ); @@ -277,6 +269,7 @@ int MSG_ReadBits( msg_t *msg, int bits ) for ( ; i < bits; i += 8 ) { + int get; Huff_offsetReceive( msgHuff.decompressor.tree, &get, msg->data, &msg->bit ); value |= get << i; } @@ -331,9 +324,7 @@ void MSG_WriteByte( msg_t *sb, int c ) void MSG_WriteData( msg_t *buf, const void *data, int length ) { - int i; - - for ( i = 0; i < length; i++ ) + for ( int i = 0; i < length; i++ ) { MSG_WriteByte( buf, ( ( byte * ) data ) [ i ] ); } @@ -370,56 +361,11 @@ void MSG_WriteFloat( msg_t *sb, float f ) MSG_WriteBits( sb, dat.l, 32 ); } -void MSG_WriteString( msg_t *sb, const char *s ) +void MSG_WriteString( msg_t *sb, const std::string& string ) { - if ( !s ) - { - MSG_WriteData( sb, "", 1 ); - } - else - { - int l; - char string[ MAX_STRING_CHARS ]; - - l = strlen( s ); + MSG_WriteLong( sb, string.size() ); - if ( l >= MAX_STRING_CHARS ) - { - Log::Notice( "MSG_WriteString: MAX_STRING_CHARS exceeded" ); - MSG_WriteData( sb, "", 1 ); - return; - } - - Q_strncpyz( string, s, sizeof( string ) ); - - MSG_WriteData( sb, string, l + 1 ); - } -} - -void MSG_WriteBigString( msg_t *sb, const char *s ) -{ - if ( !s ) - { - MSG_WriteData( sb, "", 1 ); - } - else - { - int l; - char string[ BIG_INFO_STRING ]; - - l = strlen( s ); - - if ( l >= BIG_INFO_STRING ) - { - Log::Notice( "MSG_WriteBigString: BIG_INFO_STRING exceeded" ); - MSG_WriteData( sb, "", 1 ); - return; - } - - Q_strncpyz( string, s, sizeof( string ) ); - - MSG_WriteData( sb, string, l + 1 ); - } + MSG_WriteData( sb, string.data(), string.size() ); } //============================================================ @@ -430,9 +376,7 @@ void MSG_WriteBigString( msg_t *sb, const char *s ) int MSG_ReadByte( msg_t *msg ) { - int c; - - c = ( unsigned char ) MSG_ReadBits( msg, 8 ); + int c = ( unsigned char ) MSG_ReadBits( msg, 8 ); if ( msg->readcount > msg->cursize ) { @@ -444,9 +388,7 @@ int MSG_ReadByte( msg_t *msg ) int MSG_ReadShort( msg_t *msg ) { - int c; - - c = ( short ) MSG_ReadBits( msg, 16 ); + int c = ( short ) MSG_ReadBits( msg, 16 ); if ( msg->readcount > msg->cursize ) { @@ -458,9 +400,7 @@ int MSG_ReadShort( msg_t *msg ) int MSG_ReadLong( msg_t *msg ) { - int c; - - c = MSG_ReadBits( msg, 32 ); + int c = MSG_ReadBits( msg, 32 ); if ( msg->readcount > msg->cursize ) { @@ -489,92 +429,33 @@ float MSG_ReadFloat( msg_t *msg ) return dat.f; } -char *MSG_ReadString( msg_t *msg ) -{ - static char string[ MAX_STRING_CHARS ]; - unsigned l; - int c; - - l = 0; - - do - { - c = MSG_ReadByte( msg ); // use ReadByte so -1 is out of bounds - - if ( c == -1 || c == 0 ) - { - break; - } - - string[ l ] = c; - l++; - } - while ( l < sizeof( string ) - 1 ); - - string[ l ] = 0; - - return string; -} - -char *MSG_ReadBigString( msg_t *msg ) +std::string MSG_ReadString( msg_t *msg, const bool allowNewLines ) { - static char string[ BIG_INFO_STRING ]; - unsigned l; - int c; + std::string string; + uint32_t size = MSG_ReadLong( msg ); - l = 0; + string.resize( size ); - do - { - c = MSG_ReadByte( msg ); // use ReadByte so -1 is out of bounds + if ( allowNewLines ) { + MSG_ReadData( msg, string.data(), size ); + } else { + for ( char* write = string.data(); write < string.data() + size; write++ ) { + const int c = MSG_ReadByte( msg ); - if ( c == -1 || c == 0 ) - { - break; - } - - string[ l ] = c; - l++; - } - while ( l < sizeof( string ) - 1 ); - - string[ l ] = 0; - - return string; -} - -char *MSG_ReadStringLine( msg_t *msg ) -{ - static char string[ MAX_STRING_CHARS ]; - unsigned l; - int c; - - l = 0; - - do - { - c = MSG_ReadByte( msg ); // use ReadByte so -1 is out of bounds + if ( c == '\n' ) { + break; + } - if ( c == -1 || c == 0 || c == '\n' ) - { - break; + *write = c; } - - string[ l ] = c; - l++; } - while ( l < sizeof( string ) - 1 ); - - string[ l ] = 0; return string; } void MSG_ReadData( msg_t *msg, void *data, int len ) { - int i; - - for ( i = 0; i < len; i++ ) + for ( int i = 0; i < len; i++ ) { ( ( byte * ) data ) [ i ] = MSG_ReadByte( msg ); } diff --git a/src/engine/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index c3d56f5157..342e00d384 100644 --- a/src/engine/qcommon/qcommon.h +++ b/src/engine/qcommon/qcommon.h @@ -71,8 +71,7 @@ void MSG_WriteByte( msg_t *sb, int c ); void MSG_WriteShort( msg_t *sb, int c ); void MSG_WriteLong( msg_t *sb, int c ); void MSG_WriteFloat( msg_t *sb, float f ); -void MSG_WriteString( msg_t *sb, const char *s ); -void MSG_WriteBigString( msg_t *sb, const char *s ); +void MSG_WriteString( msg_t *sb, const std::string& string ); void MSG_BeginReading( msg_t *sb ); void MSG_BeginReadingOOB( msg_t *sb ); @@ -84,9 +83,7 @@ int MSG_ReadByte( msg_t *sb ); int MSG_ReadShort( msg_t *sb ); int MSG_ReadLong( msg_t *sb ); float MSG_ReadFloat( msg_t *sb ); -char *MSG_ReadString( msg_t *sb ); -char *MSG_ReadBigString( msg_t *sb ); -char *MSG_ReadStringLine( msg_t *sb ); +std::string MSG_ReadString( msg_t *sb, const bool allowNewLines = true ); void MSG_ReadData( msg_t *sb, void *buffer, int size ); void MSG_WriteDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ); @@ -229,7 +226,7 @@ The server you are attempting to join is running an incompatible version of the The server you attempted to join is running an incompatible version of the game.\n\ You or the server may be running older versions of the game." -#define PROTOCOL_VERSION 86 +#define PROTOCOL_VERSION 87 #define URI_SCHEME GAMENAME_STRING "://" #define URI_SCHEME_LENGTH ( ARRAY_LEN( URI_SCHEME ) - 1 ) @@ -436,7 +433,7 @@ bool FS_LoadServerPaks( const char* paks, bool isDemo ); // shutdown and restart the filesystem so changes to fs_gamedir can take effect void FS_DeletePaksWithBadChecksum(); -bool FS_ComparePaks(char* neededpaks, int len); +bool FS_ComparePaks( std::string& neededpaks, int len ); /* ============================================================== diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 514c9f822b..f2185b2bc3 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -137,23 +137,23 @@ struct client_t clientState_t state; char userinfo[ MAX_INFO_STRING ]; // name, etc - char reliableCommands[ MAX_RELIABLE_COMMANDS ][ MAX_STRING_CHARS ]; - int reliableSequence; // last added reliable message, not necessarily sent or acknowledged yet - int reliableAcknowledge; // last acknowledged reliable message - int reliableSent; // last sent reliable message, not necessarily acknowledged yet - int messageAcknowledge; + std::vector reliableCommands; + uint32_t reliableSequence; // last added reliable message, not necessarily sent or acknowledged yet + uint32_t reliableAcknowledge = 0; // last acknowledged reliable message + uint32_t previousAcknowledge = 0; + int messageAcknowledge; int gamestateMessageNum; // netchan->outgoingSequence of gamestate - usercmd_t lastUsercmd; - int lastMessageNum; // for delta compression - int lastClientCommand; // reliable client message sequence + usercmd_t lastUsercmd; + uint32_t lastMessageNum; // for delta compression + uint32_t lastClientCommand; // reliable client message sequence char lastClientCommandString[ MAX_STRING_CHARS ]; sharedEntity_t *gentity; // SV_GentityNum(clientnum) char name[ MAX_NAME_LENGTH ]; // extracted from userinfo, high bits masked // downloading - char downloadName[ MAX_OSPATH ]; // if not empty string, we are downloading + std::string downloadName; // if not empty string, we are downloading FS::File* download; // file being downloaded int downloadSize; // total bytes (can't use EOF because of paks) int downloadCount; // bytes sent diff --git a/src/engine/server/sv_bot.cpp b/src/engine/server/sv_bot.cpp index c5b5fe616b..e4883ab0e3 100644 --- a/src/engine/server/sv_bot.cpp +++ b/src/engine/server/sv_bot.cpp @@ -106,10 +106,7 @@ SV_BotGetConsoleMessage */ int SV_BotGetConsoleMessage( int client, char*, int ) { - client_t *cl; - int index; - - cl = &svs.clients[ client ]; + client_t* cl = &svs.clients[ client ]; cl->lastPacketTime = svs.time; if ( cl->reliableAcknowledge == cl->reliableSequence ) @@ -118,14 +115,12 @@ int SV_BotGetConsoleMessage( int client, char*, int ) } cl->reliableAcknowledge++; - index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ); - if ( !cl->reliableCommands[ index ][ 0 ] ) + if ( !cl->reliableCommands[cl->reliableAcknowledge - 1][0] ) { return false; } - //Q_strncpyz( buf, cl->reliableCommands[index], size ); return true; } diff --git a/src/engine/server/sv_client.cpp b/src/engine/server/sv_client.cpp index 3b6f336754..a149017f7f 100644 --- a/src/engine/server/sv_client.cpp +++ b/src/engine/server/sv_client.cpp @@ -358,7 +358,6 @@ void SV_SendClientGameState( client_t *client ) // send the gamestate MSG_WriteByte( &msg, svc_gamestate ); - MSG_WriteLong( &msg, client->reliableSequence ); // write the configstrings for ( start = 0; start < MAX_CONFIGSTRINGS; start++ ) @@ -367,7 +366,7 @@ void SV_SendClientGameState( client_t *client ) { MSG_WriteByte( &msg, svc_configstring ); MSG_WriteShort( &msg, start ); - MSG_WriteBigString( &msg, sv.configstrings[ start ] ); + MSG_WriteString( &msg, sv.configstrings[ start ] ); } } @@ -452,8 +451,6 @@ clear/free any download vars */ static void SV_CloseDownload( client_t *cl ) { - int i; - // EOF if ( cl->download ) { @@ -461,10 +458,10 @@ static void SV_CloseDownload( client_t *cl ) cl->download = nullptr; } - *cl->downloadName = 0; + cl->downloadName.clear(); // Free the temporary buffer space - for ( i = 0; i < MAX_DOWNLOAD_WINDOW; i++ ) + for ( int i = 0; i < MAX_DOWNLOAD_WINDOW; i++ ) { if ( cl->downloadBlocks[ i ] ) { @@ -483,7 +480,7 @@ Abort a download if in progress */ void SV_StopDownload_f( client_t *cl, const Cmd::Args& ) { - if ( *cl->downloadName ) + if ( cl->downloadName.size() ) { Log::Debug( "clientDownload: %d: file \"%s^*\" aborted", ( int )( cl - svs.clients ), cl->downloadName ); } @@ -570,7 +567,7 @@ void SV_BeginDownload_f( client_t *cl, const Cmd::Args& args ) // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open // the file itself - Q_strncpyz( cl->downloadName, args.Argv(1).c_str(), sizeof( cl->downloadName ) ); + cl->downloadName = args.Argv( 1 ); } /* @@ -590,7 +587,7 @@ void SV_WWWDownload_f( client_t *cl, const Cmd::Args& args ) if ( !cl->bWWWDl ) { Log::Notice( "SV_WWWDownload: unexpected wwwdl '%s^*' for client '%s^*'", subcmd, cl->name ); - SV_DropClient( cl, va( "SV_WWWDownload: unexpected wwwdl %s", subcmd ) ); + SV_DropClient( cl, Str::Format( "SV_WWWDownload: unexpected wwwdl %s", subcmd ).c_str() ); return; } @@ -609,19 +606,19 @@ void SV_WWWDownload_f( client_t *cl, const Cmd::Args& args ) if ( !cl->bWWWing ) { Log::Notice( "SV_WWWDownload: unexpected wwwdl '%s^*' for client '%s^*'", subcmd, cl->name ); - SV_DropClient( cl, va( "SV_WWWDownload: unexpected wwwdl %s", subcmd ) ); + SV_DropClient( cl, Str::Format( "SV_WWWDownload: unexpected wwwdl %s", subcmd ).c_str() ); return; } if ( !Q_stricmp( subcmd, "done" ) ) { - *cl->downloadName = 0; + cl->downloadName.clear(); cl->bWWWing = false; return; } else if ( !Q_stricmp( subcmd, "fail" ) ) { - *cl->downloadName = 0; + cl->downloadName.clear(); cl->bWWWing = false; cl->bFallback = true; // send a reconnect @@ -632,7 +629,7 @@ void SV_WWWDownload_f( client_t *cl, const Cmd::Args& args ) { Log::Warn("client '%s^*' reports that the redirect download for '%s^*' had wrong checksum.\n\tYou should check your download redirect configuration.", cl->name, cl->downloadName ); - *cl->downloadName = 0; + cl->downloadName.clear(); cl->bWWWing = false; cl->bFallback = true; // send a reconnect @@ -640,8 +637,8 @@ void SV_WWWDownload_f( client_t *cl, const Cmd::Args& args ) return; } - Log::Notice("SV_WWWDownload: unknown wwwdl subcommand '%s^*' for client '%s^*'", subcmd, cl->name ); - SV_DropClient( cl, va( "SV_WWWDownload: unknown wwwdl subcommand '%s^*'", subcmd ) ); + Log::Notice( "SV_WWWDownload: unknown wwwdl subcommand '%s^*' for client '%s^*'", subcmd, cl->name ); + SV_DropClient( cl, Str::Format( "SV_WWWDownload: unknown wwwdl subcommand '%s^*'", subcmd ).c_str() ); } // abort an attempted download @@ -651,7 +648,7 @@ void SV_BadDownload( client_t *cl, msg_t *msg ) MSG_WriteShort( msg, 0 ); // client is expecting block zero MSG_WriteLong( msg, -1 ); // illegal file size - *cl->downloadName = 0; + cl->downloadName.clear(); } /* @@ -676,7 +673,7 @@ static bool SV_CheckFallbackURL( client_t *cl, const char* pakName, int download MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, -1 ); // block -1 means ftp/http download - MSG_WriteString( msg, va( "%s/%s", sv_wwwFallbackURL.Get().c_str(), pakName ) ); + MSG_WriteString( msg, Str::Format( "%s/%s", sv_wwwFallbackURL.Get(), pakName ) ); MSG_WriteLong( msg, downloadSize ); MSG_WriteLong( msg, sv_wwwFallbackURL.Get().size() + 1 ); @@ -696,13 +693,12 @@ void SV_WriteDownloadToClient( client_t *cl, msg_t *msg ) int curindex; int rate; int blockspersnap; - char errorMessage[ 1024 ]; const FS::PakInfo* pak; bool success; bool bTellRate = false; // verbosity - if ( !*cl->downloadName ) + if ( cl->downloadName.empty() ) { return; // Nothing being downloaded } @@ -727,10 +723,10 @@ void SV_WriteDownloadToClient( client_t *cl, msg_t *msg ) { Log::Notice( "clientDownload: %d : \"%s\" download disabled", ( int )( cl - svs.clients ), cl->downloadName ); - Com_sprintf( errorMessage, sizeof( errorMessage ), - "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" - "You will need to get this file elsewhere before you can connect to this server.\n", - cl->downloadName ); + const std::string errorMessage = Str::Format( + "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" + "You will need to get this file elsewhere before you can connect to this server.\n", + cl->downloadName ); SV_BadDownload( cl, msg ); MSG_WriteString( msg, errorMessage ); // (could SV_DropClient instead?) @@ -748,7 +744,8 @@ void SV_WriteDownloadToClient( client_t *cl, msg_t *msg ) Util::optional checksum; int downloadSize = 0; - success = FS::ParsePakName(cl->downloadName, cl->downloadName + strlen(cl->downloadName), name, version, checksum); + success = FS::ParsePakName(cl->downloadName.c_str(), cl->downloadName.c_str() + cl->downloadName.size(), + name, version, checksum); if (success) { // legacy pk3s have empty version but no checksum @@ -827,7 +824,8 @@ void SV_WriteDownloadToClient( client_t *cl, msg_t *msg ) std::string name, version; Util::optional checksum; - success = FS::ParsePakName(cl->downloadName, cl->downloadName + strlen(cl->downloadName), name, version, checksum); + success = FS::ParsePakName(cl->downloadName.c_str(), cl->downloadName.c_str() + cl->downloadName.size(), + name, version, checksum); if (success) { // legacy paks have empty version but no checksum @@ -859,8 +857,8 @@ void SV_WriteDownloadToClient( client_t *cl, msg_t *msg ) if ( !success ) { Log::Notice( "clientDownload: %d : \"%s\" file not found on server", ( int )( cl - svs.clients ), cl->downloadName ); - Com_sprintf( errorMessage, sizeof( errorMessage ), "File \"%s\" not found on server for autodownloading.\n", - cl->downloadName ); + const std::string errorMessage = Str::Format( "File \"%s\" not found on server for autodownloading.\n", + cl->downloadName ); SV_BadDownload( cl, msg ); MSG_WriteString( msg, errorMessage ); // (could SV_DropClient instead?) return; @@ -1170,8 +1168,8 @@ SV_ClientCommand */ static bool SV_ClientCommand( client_t *cl, msg_t *msg, bool premaprestart ) { - auto seq = MSG_ReadLong( msg ); - auto s = MSG_ReadString( msg ); + uint32_t seq = MSG_ReadLong( msg ); + std::string command = MSG_ReadString( msg ); // see if we have already executed it if ( cl->lastClientCommand >= seq ) @@ -1179,20 +1177,12 @@ static bool SV_ClientCommand( client_t *cl, msg_t *msg, bool premaprestart ) return true; } - Log::Debug( "clientCommand: %s^* : %i : %s", cl->name, seq, s ); - - // drop the connection if we have somehow lost commands - if ( seq > cl->lastClientCommand + 1 ) - { - Log::Notice( "Client %s lost %i clientCommands", cl->name, seq - cl->lastClientCommand + 1 ); - SV_DropClient( cl, "Lost reliable commands" ); - return false; - } + Log::Debug( "clientCommand: %s^* : %i : %s", cl->name, seq, command ); - SV_ExecuteClientCommand( cl, s, premaprestart ); + SV_ExecuteClientCommand( cl, command.c_str(), premaprestart ); cl->lastClientCommand = seq; - Com_sprintf( cl->lastClientCommandString, sizeof( cl->lastClientCommandString ), "%s", s ); + Com_sprintf( cl->lastClientCommandString, sizeof( cl->lastClientCommandString ), "%s", command.c_str() ); return true; // continue processing } @@ -1349,7 +1339,7 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) // NOTE: when the client message is fux0red the acknowledgement numbers // can be out of range, this could cause the server to send thousands of server // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient - if ( cl->reliableAcknowledge < 0 || cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS || cl->reliableAcknowledge > cl->reliableSequence ) + if ( cl->reliableAcknowledge < 0 || cl->reliableAcknowledge > cl->reliableSequence ) { // usually only hackers create messages like this // it is more annoying for them to let them hanging @@ -1360,6 +1350,18 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) return; } + if ( cl->reliableAcknowledge != cl->previousAcknowledge ) { + std::vector::iterator start = cl->reliableCommands.begin() + ( cl->reliableSequence - cl->reliableAcknowledge ); + std::vector::iterator end = cl->reliableCommands.end(); + + std::move( start, end, cl->reliableCommands.begin() ); + cl->reliableCommands.erase( start, end ); + + cl->previousAcknowledge = cl->reliableAcknowledge; + } + + cl->reliableSequence = std::max( cl->reliableSequence, cl->reliableAcknowledge ); + // if this is a usercmd from a previous gamestate, // ignore it or retransmit the current gamestate // @@ -1372,7 +1374,7 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) // don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to "" // but we still need to read the next message to move to next download or send gamestate // I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else - if ( serverId != sv.serverId && !*cl->downloadName && !strstr( cl->lastClientCommandString, "nextdl" ) ) + if ( serverId != sv.serverId && cl->downloadName.empty() && !strstr(cl->lastClientCommandString, "nextdl") ) { if ( serverId >= sv.restartedServerId && serverId < sv.serverId ) { diff --git a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp index 293acb8c8f..e69a074733 100644 --- a/src/engine/server/sv_main.cpp +++ b/src/engine/server/sv_main.cpp @@ -163,30 +163,9 @@ not have future snapshot_t executed before it is executed */ void SV_AddServerCommand( client_t *client, const char *cmd ) { - int index, i; + client->reliableCommands.push_back( cmd ); client->reliableSequence++; - - // if we would be losing an old command that hasn't been acknowledged, - // we must drop the connection - // we check == instead of >= so a broadcast print added by SV_DropClient() - // doesn't cause a recursive drop client - if ( client->reliableSequence - client->reliableAcknowledge == MAX_RELIABLE_COMMANDS + 1 ) - { - Log::Debug("===== pending server commands ====="); - - for ( i = client->reliableAcknowledge + 1; i <= client->reliableSequence; i++ ) - { - Log::Debug( "cmd %5d: %s", i, client->reliableCommands[ i & ( MAX_RELIABLE_COMMANDS - 1 ) ] ); - } - - Log::Debug( "cmd %5d: %s", i, cmd ); - SV_DropClient( client, "Server command overflow" ); - return; - } - - index = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 ); - Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) ); } /* @@ -994,12 +973,12 @@ static void SV_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) MSG_BeginReadingOOB( msg ); MSG_ReadLong( msg ); // skip the -1 marker - if ( !Q_strncmp( "connect", ( char * ) &msg->data[ 4 ], 7 ) ) + if ( !Q_strncmp( "connect", ( char * ) &msg->data[ 8 ], 7 ) ) { - Huff_Decompress( msg, 12 ); + Huff_Decompress( msg, 16 ); } - Cmd::Args args(MSG_ReadStringLine( msg )); + Cmd::Args args( MSG_ReadString( msg, false ) ); if ( args.Argc() <= 0 ) { diff --git a/src/engine/server/sv_snapshot.cpp b/src/engine/server/sv_snapshot.cpp index a68baad5e1..7a6b1216c8 100644 --- a/src/engine/server/sv_snapshot.cpp +++ b/src/engine/server/sv_snapshot.cpp @@ -155,14 +155,11 @@ SV_WriteSnapshotToClient */ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) { - clientSnapshot_t *frame, *oldframe; - int lastframe; - int i; - int snapFlags; - // this is the snapshot we are creating - frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ]; + clientSnapshot_t* frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ]; + clientSnapshot_t* oldframe; + int lastframe; // try to use a previous frame as the source for delta compressing the snapshot if ( client->deltaMessage <= 0 || client->state != clientState_t::CS_ACTIVE ) { @@ -194,10 +191,6 @@ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) MSG_WriteByte( msg, svc_snapshot ); - // NOTE, MRE: now sent at the start of every message from server to client - // let the client know which reliable clientCommands we have received - //MSG_WriteLong( msg, client->lastClientCommand ); - // send over the current server time so the client can drift // its view of time to try to match MSG_WriteLong( msg, sv.time ); @@ -205,7 +198,7 @@ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) // what we are delta'ing from MSG_WriteByte( msg, lastframe ); - snapFlags = svs.snapFlagServerBit; + int snapFlags = svs.snapFlagServerBit; if ( client->rateDelayed ) { @@ -241,7 +234,7 @@ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) // padding for rate debugging if ( sv_padPackets.Get() ) { - for ( i = 0; i < sv_padPackets.Get(); i++ ) + for ( int i = 0; i < sv_padPackets.Get(); i++ ) { MSG_WriteByte( msg, svc_nop ); } @@ -257,17 +250,13 @@ SV_UpdateServerCommandsToClient */ void SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg ) { - int i; - // write any unacknowledged serverCommands - for ( i = client->reliableAcknowledge + 1; i <= client->reliableSequence; i++ ) + for ( uint32_t i = 0; i < client->reliableSequence - client->reliableAcknowledge; i++ ) { MSG_WriteByte( msg, svc_serverCommand ); - MSG_WriteLong( msg, i ); - MSG_WriteString( msg, client->reliableCommands[ i & ( MAX_RELIABLE_COMMANDS - 1 ) ] ); + MSG_WriteLong( msg, i + client->reliableAcknowledge ); + MSG_WriteString( msg, client->reliableCommands[i] ); } - - client->reliableSent = client->reliableSequence; } /* @@ -796,7 +785,7 @@ static int SV_RateMsec( client_t *client, int messageSize ) rate = client->rate; // work on the appropriate max rate (client or download) - if ( !*client->downloadName ) + if ( client->downloadName.empty() ) { maxRate = sv_maxRate.Get(); } @@ -851,7 +840,7 @@ void SV_SendMessageToClient( msg_t *msg, client_t *client ) // TTimo - during a download, ignore the snapshotMsec // the update server on steroids, with this disabled and sv_fps 60, the download can reach 30 kb/s // on a regular server, we will still top at 20 kb/s because of sv_fps 20 - if ( !*client->downloadName && rateMsec < client->snapshotMsec ) + if ( client->downloadName.empty() && rateMsec < client->snapshotMsec ) { // never send more packets than this, no matter what the rate is at rateMsec = client->snapshotMsec; @@ -870,7 +859,7 @@ void SV_SendMessageToClient( msg_t *msg, client_t *client ) // a gigantic connection message may have already put the nextSnapshotTime // more than a second away, so don't shorten it // do shorten if client is downloading - if ( !*client->downloadName && client->nextSnapshotTime < svs.time + 1000 ) + if ( client->downloadName.empty() && client->nextSnapshotTime < svs.time + 1000 ) { client->nextSnapshotTime = svs.time + 1000; } diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index 961583ab6a..9cd99e959e 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -647,12 +647,10 @@ void trap_LAN_ResetPings( int n ) VM::SendMsg(n); } -int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ) +bool trap_LAN_ServerStatus( const char *serverAddress, std::string& serverStatus ) { - std::string status; int res; - VM::SendMsg(serverAddress, maxLen, status, res); - Q_strncpyz(serverStatus, status.c_str(), maxLen); + VM::SendMsg(serverAddress, serverStatus, res); return res; } diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index 518a76d3ea..f25c8efdfb 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -129,7 +129,7 @@ void trap_LAN_MarkServerVisible( int source, int n, bool visible ); int trap_LAN_ServerIsVisible( int source, int n ); bool trap_LAN_UpdateVisiblePings( int source ); void trap_LAN_ResetPings( int n ); -int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ); +bool trap_LAN_ServerStatus( const char *serverAddress, std::string& serverStatus ); void trap_LAN_ResetServerStatus(); void trap_R_GetShaderNameFromHandle( const qhandle_t shader, char *out, int len ); void trap_PrepareKeyUp(); From d9fac623381e451f8d3363cb924d1b43657ac87e Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 00:43:00 +0300 Subject: [PATCH 02/17] userinfo: use std::string --- src/engine/server/server.h | 10 +++++----- src/engine/server/sg_msgdef.h | 2 +- src/engine/server/sv_client.cpp | 23 +++++++++++------------ src/engine/server/sv_init.cpp | 20 +++++--------------- src/engine/server/sv_sgame.cpp | 9 +++------ src/shared/server/sg_api.cpp | 10 +++++----- src/shared/server/sg_api.h | 4 ++-- 7 files changed, 32 insertions(+), 46 deletions(-) diff --git a/src/engine/server/server.h b/src/engine/server/server.h index f2185b2bc3..e2736b37e3 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -135,7 +135,7 @@ struct netchan_buffer_t struct client_t { clientState_t state; - char userinfo[ MAX_INFO_STRING ]; // name, etc + std::string userinfo; // name, etc std::vector reliableCommands; uint32_t reliableSequence; // last added reliable message, not necessarily sent or acknowledged yet @@ -150,7 +150,7 @@ struct client_t uint32_t lastClientCommand; // reliable client message sequence char lastClientCommandString[ MAX_STRING_CHARS ]; sharedEntity_t *gentity; // SV_GentityNum(clientnum) - char name[ MAX_NAME_LENGTH ]; // extracted from userinfo, high bits masked + std::string name; // extracted from userinfo, high bits masked // downloading std::string downloadName; // if not empty string, we are downloading @@ -191,7 +191,7 @@ struct client_t //% netchan_buffer_t **netchan_end_queue; netchan_buffer_t *netchan_end_queue; - char pubkey[ RSA_STRING_LENGTH ]; + char pubkey[ RSA_STRING_LENGTH ]; //bani int downloadnotify; @@ -339,8 +339,8 @@ void SV_UpdateConfigStrings(); void SV_GetConfigstring( int index, char *buffer, int bufferSize ); void SV_SetConfigstringRestrictions( int index, const clientList_t *clientList ); -void SV_SetUserinfo( int index, const char *val ); -void SV_GetUserinfo( int index, char *buffer, int bufferSize ); +void SV_SetUserinfo( int index, const std::string& userinfo ); +std::string SV_GetUserinfo( int index ); void SV_GetPlayerPubkey( int clientNum, char *pubkey, int size ); void SV_CreateBaseline(); diff --git a/src/engine/server/sg_msgdef.h b/src/engine/server/sg_msgdef.h index 6b3faa8624..3e3a680152 100644 --- a/src/engine/server/sg_msgdef.h +++ b/src/engine/server/sg_msgdef.h @@ -71,7 +71,7 @@ using GetConfigStringMsg = IPC::SyncMessage< using SetConfigStringRestrictionsMsg = IPC::Message>; using SetUserinfoMsg = IPC::Message, int, std::string>; using GetUserinfoMsg = IPC::SyncMessage< - IPC::Message, int, int>, + IPC::Message, int>, IPC::Reply >; using GetServerinfoMsg = IPC::SyncMessage< diff --git a/src/engine/server/sv_client.cpp b/src/engine/server/sv_client.cpp index a149017f7f..db6024a5ae 100644 --- a/src/engine/server/sv_client.cpp +++ b/src/engine/server/sv_client.cpp @@ -201,7 +201,7 @@ void SV_DirectConnect( const netadr_t& from, const Cmd::Args& args ) Q_strncpyz( new_client->pubkey, userinfo["pubkey"].c_str(), sizeof( new_client->pubkey ) ); userinfo.erase("pubkey"); // save the userinfo - Q_strncpyz( new_client->userinfo, InfoMapToString(userinfo).c_str(), sizeof( new_client->userinfo ) ); + new_client->userinfo = InfoMapToString( userinfo ); // get the game a chance to reject this connection or modify the userinfo char reason[ MAX_STRING_CHARS ]; @@ -287,7 +287,7 @@ void SV_DropClient( client_t *drop, const char *reason ) { // tell everyone why they got dropped // Gordon: we want this displayed elsewhere now - SV_SendServerCommand( nullptr, "print %s\"^* \"%s\"\n\"", Cmd_QuoteString( drop->name ), Cmd_QuoteString( reason ) ); + SV_SendServerCommand( nullptr, "print %s\"^* \"%s\"\n\"", Cmd_QuoteString( drop->name.c_str() ), Cmd_QuoteString( reason ) ); // add the disconnect command SV_SendServerCommand( drop, "disconnect %s\n", Cmd_QuoteString( reason ) ); @@ -1021,11 +1021,9 @@ into a more C friendly form. */ void SV_UserinfoChanged( client_t *cl ) { - const char *val; - int i; - // name for C code - Q_strncpyz( cl->name, Info_ValueForKey( cl->userinfo, "name" ), sizeof( cl->name ) ); + InfoMap userinfo = InfoStringToMap( cl->userinfo ); + cl->name = userinfo["name"]; // rate command @@ -1039,7 +1037,7 @@ void SV_UserinfoChanged( client_t *cl ) } else { - val = Info_ValueForKey( cl->userinfo, "rate" ); + const std::string val = userinfo["rate"]; int rate; if ( Str::ParseInt( rate, val ) ) @@ -1053,11 +1051,11 @@ void SV_UserinfoChanged( client_t *cl ) } // snaps command - val = Info_ValueForKey( cl->userinfo, "snaps" ); + const std::string val = userinfo["snaps"]; - if ( strlen( val ) ) + if ( val.size() ) { - i = atoi( val ); + int i = atoi( val.c_str() ); if ( i < 1 ) { @@ -1082,7 +1080,8 @@ void SV_UserinfoChanged( client_t *cl ) // zinx - modified to always keep this consistent, instead of only // when "ip" is 0-length, so users can't supply their own IP address //Log::Debug("Maintain IP address in userinfo for '%s'", cl->name); - Info_SetValueForKey( cl->userinfo, "ip", NET_AdrToString( cl->netchan.remoteAddress ), false ); + userinfo["ip"] = NET_AdrToString( cl->netchan.remoteAddress ); + cl->userinfo = InfoMapToString( userinfo ); } /* @@ -1096,7 +1095,7 @@ static void SV_UpdateUserinfo_f( client_t *cl, const Cmd::Args& args ) return; } - Q_strncpyz(cl->userinfo, args.Argv(1).c_str(), sizeof(cl->userinfo)); // FIXME QUOTING INFO + cl->userinfo = args.Argv( 1 ); // FIXME QUOTING INFO SV_UserinfoChanged( cl ); // call prog code to allow overrides diff --git a/src/engine/server/sv_init.cpp b/src/engine/server/sv_init.cpp index 14315f1ad1..77a8642ab6 100644 --- a/src/engine/server/sv_init.cpp +++ b/src/engine/server/sv_init.cpp @@ -197,20 +197,15 @@ SV_SetUserinfo =============== */ -void SV_SetUserinfo( int index, const char *val ) +void SV_SetUserinfo( int index, const std::string& userinfo ) { if ( index < 0 || index >= sv_maxClients.Get() ) { Sys::Drop( "SV_SetUserinfo: bad index %i", index ); } - if ( !val ) - { - val = ""; - } - - Q_strncpyz( svs.clients[ index ].userinfo, val, sizeof( svs.clients[ index ].userinfo ) ); - Q_strncpyz( svs.clients[ index ].name, Info_ValueForKey( val, "name" ), sizeof( svs.clients[ index ].name ) ); + svs.clients[index].userinfo = userinfo; + svs.clients[index].name = InfoStringToMap( userinfo )["name"]; } /* @@ -219,19 +214,14 @@ SV_GetUserinfo =============== */ -void SV_GetUserinfo( int index, char *buffer, int bufferSize ) +std::string SV_GetUserinfo( int index ) { - if ( bufferSize < 1 ) - { - Sys::Drop( "SV_GetUserinfo: bufferSize == %i", bufferSize ); - } - if ( index < 0 || index >= sv_maxClients.Get() ) { Sys::Drop( "SV_GetUserinfo: bad index %i", index ); } - Q_strncpyz( buffer, svs.clients[ index ].userinfo, bufferSize ); + return svs.clients[index].userinfo; } /* diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index be4eebf2be..da2ca5804b 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -487,16 +487,13 @@ void GameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& chan case G_SET_USERINFO: IPC::HandleMsg(channel, std::move(reader), [this](int index, std::string val) { - SV_SetUserinfo(index, val.c_str()); + SV_SetUserinfo(index, val); }); break; case G_GET_USERINFO: - IPC::HandleMsg(channel, std::move(reader), [this](int index, int len, std::string& res) { - std::unique_ptr buffer(new char[len]); - buffer[0] = '\0'; - SV_GetUserinfo(index, buffer.get(), len); - res.assign(buffer.get()); + IPC::HandleMsg(channel, std::move(reader), [this](int index, std::string& res) { + res = SV_GetUserinfo( index ); }); break; diff --git a/src/shared/server/sg_api.cpp b/src/shared/server/sg_api.cpp index 550b40ba80..90de7906fb 100644 --- a/src/shared/server/sg_api.cpp +++ b/src/shared/server/sg_api.cpp @@ -79,16 +79,16 @@ void trap_SetConfigstringRestrictions(int, const clientList_t*) VM::SendMsg(); // not implemented } -void trap_SetUserinfo(int num, const char *buffer) +void trap_SetUserinfo( int num, const std::string& userinfo ) { - VM::SendMsg(num, buffer); + VM::SendMsg( num, userinfo ); } -void trap_GetUserinfo(int num, char *buffer, int bufferSize) +std::string trap_GetUserinfo( int num ) { std::string res; - VM::SendMsg(num, bufferSize, res); - Q_strncpyz(buffer, res.c_str(), bufferSize); + VM::SendMsg( num, res ); + return res; } void trap_GetServerinfo(char *buffer, int bufferSize) diff --git a/src/shared/server/sg_api.h b/src/shared/server/sg_api.h index 80ef7cc46e..c6fdae8d72 100644 --- a/src/shared/server/sg_api.h +++ b/src/shared/server/sg_api.h @@ -41,8 +41,8 @@ void trap_SendServerCommand( int clientNum, const char *text ); void trap_SetConfigstring( int num, const char *string ); void trap_SetConfigstringRestrictions( int num, const clientList_t *clientList ); void trap_GetConfigstring( int num, char *buffer, int bufferSize ); -void trap_SetUserinfo( int num, const char *buffer ); -void trap_GetUserinfo( int num, char *buffer, int bufferSize ); +void trap_SetUserinfo( int num, const std::string& userinfo ); +std::string trap_GetUserinfo( int num ); void trap_GetServerinfo( char *buffer, int bufferSize ); int trap_BotAllocateClient(); void trap_BotFreeClient( int clientNum ); From 56451823072dfa25c5e875f88c843b1a89f0c142 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 00:45:03 +0300 Subject: [PATCH 03/17] NUKE unused Com_ParseInfos() and Parse*Matrix() --- src/engine/qcommon/q_shared.cpp | 69 --------------------------------- src/engine/qcommon/q_shared.h | 6 --- 2 files changed, 75 deletions(-) diff --git a/src/engine/qcommon/q_shared.cpp b/src/engine/qcommon/q_shared.cpp index be226777a5..30e4346364 100644 --- a/src/engine/qcommon/q_shared.cpp +++ b/src/engine/qcommon/q_shared.cpp @@ -978,75 +978,6 @@ void SkipRestOfLine( const char **data ) *data = p; } -/* -=============== -Com_ParseInfos -=============== -*/ -int Com_ParseInfos( const char *buf, int max, char infos[][ MAX_INFO_STRING ] ) -{ - const char *token; - int count; - char key[ MAX_TOKEN_CHARS ]; - - count = 0; - - while (true) - { - token = COM_Parse( &buf ); - - if ( !token[ 0 ] ) - { - break; - } - - if ( strcmp( token, "{" ) ) - { - Log::Notice( "Missing { in info file" ); - break; - } - - if ( count == max ) - { - Log::Notice( "Max infos exceeded" ); - break; - } - - infos[ count ][ 0 ] = 0; - - while (true) - { - token = COM_Parse( &buf ); - - if ( !token[ 0 ] ) - { - Log::Notice( "Unexpected end of info file" ); - break; - } - - if ( !strcmp( token, "}" ) ) - { - break; - } - - Q_strncpyz( key, token, sizeof( key ) ); - - token = COM_ParseExt( &buf, false ); - - if ( !token[ 0 ] ) - { - token = ""; - } - - Info_SetValueForKey( infos[ count ], key, token, false ); - } - - count++; - } - - return count; -} - /* =================== Com_HexStrToInt diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index 7b33e27f36..16467be06a 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -1510,18 +1510,12 @@ inline vec_t VectorNormalize2( const vec3_t v, vec3_t out ) void COM_ParseError( const char *format, ... ) PRINTF_LIKE(1); void COM_ParseWarning( const char *format, ... ) PRINTF_LIKE(1); - int Com_ParseInfos( const char *buf, int max, char infos[][ MAX_INFO_STRING ] ); - int Com_HashKey( char *string, int maxlen ); bool SkipBracedSection( const char **program ); bool SkipBracedSection_Depth( const char **program, int depth ); // start at given depth if already void SkipRestOfLine( const char **data ); - void Parse1DMatrix( const char **buf_p, int x, float *m ); - void Parse2DMatrix( const char **buf_p, int y, int x, float *m ); - void Parse3DMatrix( const char **buf_p, int z, int y, int x, float *m ); - int Com_sprintf( char *dest, int size, const char *fmt, ... ) PRINTF_LIKE(3); // mode parm for FS_FOpenFile From 13c67bc61321b15626b2dc13d3224be28757b081 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 01:07:24 +0300 Subject: [PATCH 04/17] ping_t::info: use std::string --- src/engine/client/cl_serverlist.cpp | 46 +++++++++++++---------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/engine/client/cl_serverlist.cpp b/src/engine/client/cl_serverlist.cpp index cb339c5892..4ea65ef85d 100644 --- a/src/engine/client/cl_serverlist.cpp +++ b/src/engine/client/cl_serverlist.cpp @@ -68,7 +68,7 @@ struct ping_t int time; char challenge[ 9 ]; // 8-character challenge string serverResponseProtocol_t responseProto; - char info[ MAX_INFO_STRING ]; + std::string info; }; ping_t cl_pinglist[ MAX_PINGREQUESTS ]; @@ -480,10 +480,10 @@ void CL_ServersResponsePacket( const netadr_t *from, msg_t *msg, bool extended ) } static void CL_SetServerInfo( - serverInfo_t *server, const char *info, + serverInfo_t *server, const std::string& info, serverResponseProtocol_t proto, pingStatus_t pingStatus, int ping ) { - if ( info ) + if ( info.size() ) { server->infoString = info; } @@ -494,12 +494,10 @@ static void CL_SetServerInfo( } static void CL_SetServerInfoByAddress( - const netadr_t& from, const char *info, + const netadr_t& from, const std::string& info, serverResponseProtocol_t proto, pingStatus_t pingStatus, int ping ) { - int i; - - for ( i = 0; i < MAX_OTHER_SERVERS; i++ ) + for ( int i = 0; i < MAX_OTHER_SERVERS; i++ ) { if ( NET_CompareAdr( from, cls.localServers[ i ].adr ) ) { @@ -507,7 +505,7 @@ static void CL_SetServerInfoByAddress( } } - for ( i = 0; i < MAX_GLOBAL_SERVERS; i++ ) + for ( int i = 0; i < MAX_GLOBAL_SERVERS; i++ ) { if ( NET_CompareAdr( from, cls.globalServers[ i ].adr ) ) { @@ -523,27 +521,24 @@ CL_ServerInfoPacket */ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) { - char info[ MAX_INFO_STRING ]; - int prot; - const char *gameName; - - std::string infoString = MSG_ReadString( msg ); + std::string infoStr = MSG_ReadString( msg ); + InfoMap infoString = InfoStringToMap( infoStr ); // if this isn't the correct protocol version, ignore it - prot = atoi( Info_ValueForKey( infoString.c_str(), "protocol" ) ); + int prot = atoi( infoString["protocol"].c_str() ); if ( prot != PROTOCOL_VERSION ) { - serverInfoLog.Verbose( "Different protocol info packet: %s", infoString ); + serverInfoLog.Verbose( "Different protocol info packet: %i", prot ); return; } // Arnout: if this isn't the correct game, ignore it - gameName = Info_ValueForKey( infoString.c_str(), "gamename" ); + const std::string& gameName = infoString["gamename"]; - if ( !gameName[ 0 ] || Q_stricmp( gameName, GAMENAME_STRING ) ) + if ( !gameName[ 0 ] || gameName != GAMENAME_STRING ) { - serverInfoLog.Verbose( "Different game info packet: %s", infoString ); + serverInfoLog.Verbose( "Different game info packet: %s", gameName ); return; } @@ -552,7 +547,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) { if ( cl_pinglist[ i ].adr.port && cl_pinglist[ i ].time == -1 && NET_CompareAdr( from, cl_pinglist[i].adr ) ) { - if ( strcmp( cl_pinglist[ i ].challenge, Info_ValueForKey( infoString.c_str(), "challenge" ) ) ) + if ( cl_pinglist[ i ].challenge != infoString["challenge"] ) { serverInfoLog.Verbose( "wrong challenge for ping response from %s", NET_AdrToString( from ) ); return; @@ -564,7 +559,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) serverInfoLog.Debug( "ping time %dms from %s", cl_pinglist[ i ].time, NET_AdrToString( from ) ); // save of info - Q_strncpyz( cl_pinglist[ i ].info, infoString.c_str(), sizeof( cl_pinglist[ i ].info ) ); + cl_pinglist[i].info = infoStr; // tack on the net type switch ( from.type ) @@ -583,7 +578,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) break; } - CL_SetServerInfoByAddress( from, infoString.c_str(), cl_pinglist[ i ].responseProto, + CL_SetServerInfoByAddress( from, infoStr, cl_pinglist[ i ].responseProto, pingStatus_t::COMPLETE, cl_pinglist[ i ].time ); return; @@ -627,15 +622,14 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) cls.localServers[ i ].responseProto = serverResponseProtocol_t::UNKNOWN; cls.localServers[ i ].infoString.clear(); - Q_strncpyz( info, MSG_ReadString( msg ).c_str(), MAX_INFO_STRING ); + std::string info = MSG_ReadString( msg ); // TODO when does this happen? if ( info[ 0 ] ) { - char *last = info + strlen( info ) - 1; - if ( *last == '\n' ) + if ( info.back() == '\n' ) { - *last = '\0'; + info = info.substr( 0, info.size() - 1 ); } Log::Notice( "%s: %s", Net::AddressToString( from, true ), info ); @@ -979,7 +973,7 @@ void CL_Ping_f() pingptr->time = -1; GeneratePingChallenge( *pingptr ); - CL_SetServerInfoByAddress( pingptr->adr, nullptr, serverResponseProtocol_t::UNKNOWN, + CL_SetServerInfoByAddress( pingptr->adr, "", serverResponseProtocol_t::UNKNOWN, pingStatus_t::WAITING, 0 ); Net::OutOfBandPrint( netsrc_t::NS_CLIENT, to, "getinfo %s", pingptr->challenge ); From c5772de91773006f233f0b6260c924249a0ac45e Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 01:34:01 +0300 Subject: [PATCH 05/17] Use more std::string instead of fixed-size strings --- src/engine/client/cg_api.h | 6 +++--- src/engine/client/cg_msgdef.h | 23 +++++++++++++++++++++++ src/engine/client/cl_cgame.cpp | 8 ++++---- src/engine/client/cl_main.cpp | 16 ++++++++-------- src/engine/client/client.h | 4 ++-- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/engine/client/cg_api.h b/src/engine/client/cg_api.h index 023dc7a9c0..4da145e447 100644 --- a/src/engine/client/cg_api.h +++ b/src/engine/client/cg_api.h @@ -70,9 +70,9 @@ struct cgClientState_t connstate_t connState; int connectPacketCount; int clientNum; - char servername[ MAX_STRING_CHARS ]; - char updateInfoString[ MAX_STRING_CHARS ]; - char messageString[ MAX_STRING_CHARS ]; + std::string servername; + std::string updateInfoString; + std::string messageString; }; enum class MouseMode diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index de294a472a..f0fcb27019 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -120,6 +120,29 @@ namespace Util { return value; } }; + + template<> + struct SerializeTraits { + static void Write( Writer& stream, const cgClientState_t& clientState ) { + stream.Write( ( int ) clientState.connState ); + stream.Write( clientState.connectPacketCount ); + stream.Write( clientState.clientNum ); + stream.Write( clientState.servername ); + stream.Write( clientState.updateInfoString ); + stream.Write( clientState.messageString ); + } + static cgClientState_t Read( Reader& stream ) { + cgClientState_t clientState; + clientState.connState = ( connstate_t ) stream.Read(); + clientState.connectPacketCount = stream.Read(); + clientState.clientNum = stream.Read(); + clientState.servername = stream.Read(); + clientState.updateInfoString = stream.Read(); + clientState.messageString = stream.Read(); + + return clientState; + } + }; } enum cgameImport_t diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index f2fef4c1d0..ee6aae5043 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -831,7 +831,7 @@ void CL_SetCGameTime() if ( cl.snap.serverTime < cl.oldFrameServerTime ) { // Ridah, if this is a localhost, then we are probably loading a savegame - if ( !Q_stricmp( cls.servername, "loopback" ) ) + if ( cls.servername == "loopback" ) { // do nothing? CL_FirstSnapshot(); @@ -1028,9 +1028,9 @@ void CGameVM::CGameRocketFrame() cgClientState_t state; state.connectPacketCount = clc.connectPacketCount; state.connState = cls.state; - Q_strncpyz( state.servername, cls.servername, sizeof( state.servername ) ); - Q_strncpyz( state.updateInfoString, cls.updateInfoString, sizeof( state.updateInfoString ) ); - Q_strncpyz( state.messageString, clc.serverMessage.c_str(), sizeof(state.messageString)); + state.servername = cls.servername; + state.updateInfoString = cls.updateInfoString; + state.messageString = clc.serverMessage; state.clientNum = cl.snap.ps.clientNum; this->SendMsg(state); } diff --git a/src/engine/client/cl_main.cpp b/src/engine/client/cl_main.cpp index 738f747b13..88b2df735a 100644 --- a/src/engine/client/cl_main.cpp +++ b/src/engine/client/cl_main.cpp @@ -707,10 +707,10 @@ void CL_MapLoading() cls.keyCatchers = 0; // if we are already connected to the local host, stay connected - if ( cls.state >= connstate_t::CA_CONNECTED && !Q_stricmp( cls.servername, "loopback" ) ) + if ( cls.state >= connstate_t::CA_CONNECTED && cls.servername == "loopback" ) { cls.state = connstate_t::CA_CONNECTED; // so the connect screen is drawn - memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) ); + cls.updateInfoString.clear(); clc.serverMessage.clear(); cl.gameState.fill(""); clc.lastPacketSentTime = -9999; @@ -723,13 +723,13 @@ void CL_MapLoading() } catch (Sys::DropErr& err) { Sys::Error( "CL_Disconnect error during map load: %s", err.what() ); } - Q_strncpyz( cls.servername, "loopback", sizeof( cls.servername ) ); + cls.servername = "loopback"; *cls.reconnectCmd = 0; // can't reconnect to this! cls.state = connstate_t::CA_CHALLENGING; // so the connect screen is drawn cls.keyCatchers = 0; SCR_UpdateScreen(); clc.connectTime = -RETRANSMIT_TIMEOUT; - NET_StringToAdr( cls.servername, &clc.serverAddress, netadrtype_t::NA_UNSPEC ); + NET_StringToAdr( cls.servername.c_str(), &clc.serverAddress, netadrtype_t::NA_UNSPEC); // we don't need a challenge on the localhost CL_CheckForResend(); @@ -919,9 +919,9 @@ CL_Reconnect_f */ void CL_Reconnect_f() { - if ( !*cls.servername ) + if ( cls.servername.empty() ) { - Log::Notice("Can't reconnect to nothing." ); + Log::Notice( "Can't reconnect to nothing." ); } else if ( !*cls.reconnectCmd ) { @@ -996,7 +996,7 @@ void CL_Connect_f() } //Copy the arguments before they can be overwritten, after that server is invalid - Q_strncpyz( cls.servername, server, sizeof( cls.servername ) ); + cls.servername = server; Q_strncpyz( cls.reconnectCmd, Cmd::GetCurrentArgs().EscapedArgs(0).c_str(), sizeof( cls.reconnectCmd ) ); Audio::StopAllSounds(); // NERVE - SMF @@ -1021,7 +1021,7 @@ void CL_Connect_f() } Con_Close(); - if ( !NET_StringToAdr( cls.servername, &clc.serverAddress, family ) ) + if ( !NET_StringToAdr( cls.servername.c_str(), &clc.serverAddress, family ) ) { Log::Notice("Bad server address" ); cls.state = connstate_t::CA_DISCONNECTED; diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 604e29b6ba..9694cd0ee3 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -270,7 +270,7 @@ struct clientStatic_t connstate_t state; // connection status int keyCatchers; // bit flags - char servername[ MAX_OSPATH ]; // name of server from original connect + std::string servername; // name of server from original connect char reconnectCmd[ MAX_STRING_CHARS ]; // command to be used on reconnection // when the server clears the hunk, all of these must be restarted @@ -301,7 +301,7 @@ struct clientStatic_t int masterNum; // update server info - char updateInfoString[ MAX_INFO_STRING ]; + std::string updateInfoString; // rendering info WindowConfig windowConfig; From 032d31112341a5711651fca8dd91b500c07daed0 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 01:35:24 +0300 Subject: [PATCH 06/17] Clean-up --- src/engine/client/cl_download.cpp | 2 +- src/engine/qcommon/files.cpp | 2 +- src/engine/qcommon/qcommon.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/client/cl_download.cpp b/src/engine/client/cl_download.cpp index 63e05f8546..a9820b77b4 100644 --- a/src/engine/client/cl_download.cpp +++ b/src/engine/client/cl_download.cpp @@ -213,7 +213,7 @@ void CL_InitDownloads() // reset the redirect checksum tracking clc.redirectedList.clear(); - if ( cl_allowDownload->integer && FS_ComparePaks( clc.downloadList, clc.downloadList.size() ) ) + if ( cl_allowDownload->integer && FS_ComparePaks( clc.downloadList ) ) { downloadLogger.Debug( "Need paks: '%s'", clc.downloadList ); diff --git a/src/engine/qcommon/files.cpp b/src/engine/qcommon/files.cpp index fe22bc2d73..371dd20aec 100644 --- a/src/engine/qcommon/files.cpp +++ b/src/engine/qcommon/files.cpp @@ -747,7 +747,7 @@ void FS_DeletePaksWithBadChecksum() { } } -bool FS_ComparePaks( std::string& neededpaks, int len ) +bool FS_ComparePaks( std::string& neededpaks ) { for (const missingPak_t& x: fs_missingPaks) { neededpaks += "@"; diff --git a/src/engine/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index 342e00d384..a2724f4956 100644 --- a/src/engine/qcommon/qcommon.h +++ b/src/engine/qcommon/qcommon.h @@ -433,7 +433,7 @@ bool FS_LoadServerPaks( const char* paks, bool isDemo ); // shutdown and restart the filesystem so changes to fs_gamedir can take effect void FS_DeletePaksWithBadChecksum(); -bool FS_ComparePaks( std::string& neededpaks, int len ); +bool FS_ComparePaks( std::string& neededpaks ); /* ============================================================== From 683a39e8cd54f535c419947e893a0d31d1bc7eb5 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 01:40:17 +0300 Subject: [PATCH 07/17] CL_CheckForResend(): use InfoMap --- src/engine/client/cl_main.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/engine/client/cl_main.cpp b/src/engine/client/cl_main.cpp index 88b2df735a..786365f149 100644 --- a/src/engine/client/cl_main.cpp +++ b/src/engine/client/cl_main.cpp @@ -1594,9 +1594,6 @@ Resend a connect message if the last one has timed out */ void CL_CheckForResend() { - int port; - char info[ MAX_INFO_STRING ]; - // don't send anything if playing back a demo if ( clc.demoplaying ) { @@ -1629,15 +1626,17 @@ void CL_CheckForResend() mpz_get_str( key, 16, public_key.n); // sending back the challenge - port = Cvar_VariableValue( "net_qport" ); + int port = Cvar_VariableValue( "net_qport" ); - Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO, false ), sizeof( info ) ); - Info_SetValueForKey( info, "protocol", Str::Format( "%i", PROTOCOL_VERSION ).c_str(), false); - Info_SetValueForKey( info, "qport", Str::Format( "%i", port ).c_str(), false); - Info_SetValueForKey( info, "challenge", clc.challenge.c_str(), false ); - Info_SetValueForKey( info, "pubkey", key, false ); + InfoMap info; + Cvar::PopulateInfoMap( CVAR_USERINFO, info ); + + info["protocol"] = Str::Format( "%i", PROTOCOL_VERSION ); + info["qport"] = Str::Format( "%i", port ); + info["challenge"] = clc.challenge; + info["pubkey"] = key; - std::string data = Str::Format( "connect %s", Cmd_QuoteString( info ) ); + std::string data = Str::Format( "connect %s", Cmd_QuoteString( InfoMapToString( info ).c_str() ) ); // This will be read by MSG_ReadString, which expects the string length data.resize( data.size() + 4 ); std::move( data.data(), data.data() + data.size() - 4, data.data() + 4 ); From b33151f815866d3e212deff57be91c8092f2cbc5 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 12:45:39 +0300 Subject: [PATCH 08/17] Implement MSG_ReadStringLines(), some fixes Correctly parse multiline strings in network messages. --- src/engine/client/cl_main.cpp | 45 ++++++++++----------- src/engine/client/cl_serverlist.cpp | 31 +++++++-------- src/engine/client/cl_serverstatus.cpp | 56 +++++++++++++-------------- src/engine/client/client.h | 4 +- src/engine/qcommon/msg.cpp | 41 ++++++++++++++------ src/engine/qcommon/qcommon.h | 3 +- src/engine/server/sv_main.cpp | 3 +- 7 files changed, 100 insertions(+), 83 deletions(-) diff --git a/src/engine/client/cl_main.cpp b/src/engine/client/cl_main.cpp index 786365f149..f860166e3f 100644 --- a/src/engine/client/cl_main.cpp +++ b/src/engine/client/cl_main.cpp @@ -1295,9 +1295,9 @@ class RconDiscoverCmd: public Cmd::StaticCmd static RconDiscoverCmd RconDiscoverCmdRegistration; -static void CL_ServerRconInfoPacket( netadr_t, msg_t *msg ) +static void CL_ServerRconInfoPacket( netadr_t, const std::string& message ) { - InfoMap info = InfoStringToMap( MSG_ReadString( msg ) ); + InfoMap info = InfoStringToMap( message ); int value; if ( Str::ParseInt( value, info["secure"] ) ) { @@ -1709,11 +1709,11 @@ print OOB are the only messages we handle markups in to 256 chars. =================== */ -void CL_PrintPacket( msg_t *msg ) +static void CL_PrintPacket( const std::string& message ) { - clc.serverMessage = MSG_ReadString( msg ); + clc.serverMessage = message; - if ( clc.serverMessage.substr( 12 ) == "[err_dialog]" ) + if ( clc.serverMessage.substr( 0, 12 ) == "[err_dialog]" ) { Sys::Drop( "^3Server disconnected:\n^7%s", clc.serverMessage.substr( 12, clc.serverMessage.size() ) ); } @@ -1733,7 +1733,8 @@ static void CL_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) MSG_BeginReadingOOB( msg ); MSG_ReadLong( msg ); // skip the -1 - Cmd::Args args( MSG_ReadString( msg, false ) ); + std::vector lines = MSG_ReadStringLines( msg ); + Cmd::Args args( lines[0] ); if ( args.Argc() < 1 ) { @@ -1744,7 +1745,7 @@ static void CL_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) // challenge from the server we are connecting to - if ( args.Argv(0) == "challengeResponse" ) + if ( args.Argv( 0 ).starts_with( "challengeResponse" ) ) { if ( cls.state == connstate_t::CA_CONNECTING ) { @@ -1772,7 +1773,7 @@ static void CL_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) } // server connection - if ( args.Argv(0) == "connectResponse" ) + if ( args.Argv( 0 ).starts_with( "connectResponse" ) ) { if ( cls.state >= connstate_t::CA_CONNECTED ) { @@ -1801,73 +1802,73 @@ static void CL_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) } // server responding to an info broadcast - if ( args.Argv(0) == "infoResponse" ) + if ( args.Argv( 0 ).starts_with( "infoResponse" ) ) { - CL_ServerInfoPacket( from, msg ); + CL_ServerInfoPacket( from, lines[1] ); return; } // server responding to a get playerlist if ( args.Argv(0) == "statusResponse" ) { - CL_ServerStatusResponse( from, msg ); + CL_ServerStatusResponse( from, lines ); return; } // a disconnect message from the server, which will happen if the server // dropped the connection but it is still getting packets from us - if ( args.Argv(0) == "disconnect" ) + if ( args.Argv( 0 ).starts_with( "disconnect" ) ) { CL_DisconnectPacket( from ); return; } // echo request from server - if ( args.Argv(0) == "echo" && args.Argc() >= 2) + if ( args.Argv( 0 ).starts_with( "echo" ) && args.Argc() >= 2) { Net::OutOfBandPrint( netsrc_t::NS_CLIENT, from, "%s", args.Argv(1) ); return; } // echo request from server - if ( args.Argv(0) == "print" ) + if ( args.Argv( 0 ).starts_with( "print" ) ) { - CL_PrintPacket( msg ); + CL_PrintPacket( lines[1] ); return; } // echo request from server - if ( args.Argv(0) == "getserversResponse" ) + if ( args.Argv( 0 ).starts_with( "getserversResponse" ) ) { CL_ServersResponsePacket( &from, msg, false ); return; } // list of servers with both IPv4 and IPv6 addresses; sent back by a master server (extended) - if ( args.Argv(0) == "getserversExtResponseLinks" ) + if ( args.Argv( 0 ).starts_with( "getserversExtResponseLinks" ) ) { CL_ServerLinksResponsePacket( msg ); return; } // list of servers sent back by a master server (extended) - if ( args.Argv(0) == "getserversExtResponse" ) + if ( args.Argv( 0 ).starts_with( "getserversExtResponse" ) ) { CL_ServersResponsePacket( &from, msg, true ); return; } // prints a n error message returned by the server - if ( args.Argv(0) == "error" ) + if ( args.Argv( 0 ).starts_with( "error" ) ) { - Log::Warn( MSG_ReadString( msg, false ) ); + Log::Warn( lines[1] ); return; } // prints a n error message returned by the server - if ( args.Argv(0) == "rconInfoResponse" ) + if ( args.Argv( 0 ).starts_with( "rconInfoResponse" ) ) { - CL_ServerRconInfoPacket( from, msg ); + CL_ServerRconInfoPacket( from, lines[1] ); return; } diff --git a/src/engine/client/cl_serverlist.cpp b/src/engine/client/cl_serverlist.cpp index 4ea65ef85d..2f1674318c 100644 --- a/src/engine/client/cl_serverlist.cpp +++ b/src/engine/client/cl_serverlist.cpp @@ -519,9 +519,8 @@ static void CL_SetServerInfoByAddress( CL_ServerInfoPacket =================== */ -void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) +void CL_ServerInfoPacket( const netadr_t& from, const std::string& infoStr ) { - std::string infoStr = MSG_ReadString( msg ); InfoMap infoString = InfoStringToMap( infoStr ); // if this isn't the correct protocol version, ignore it @@ -547,7 +546,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) { if ( cl_pinglist[ i ].adr.port && cl_pinglist[ i ].time == -1 && NET_CompareAdr( from, cl_pinglist[i].adr ) ) { - if ( cl_pinglist[ i ].challenge != infoString["challenge"] ) + if ( Q_strncmp( cl_pinglist[ i ].challenge, infoString["challenge"].c_str(), 7 ) ) { serverInfoLog.Verbose( "wrong challenge for ping response from %s", NET_AdrToString( from ) ); return; @@ -622,10 +621,10 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) cls.localServers[ i ].responseProto = serverResponseProtocol_t::UNKNOWN; cls.localServers[ i ].infoString.clear(); - std::string info = MSG_ReadString( msg ); + // std::string info = MSG_ReadString( msg ); // TODO when does this happen? - if ( info[ 0 ] ) + /* if ( info[ 0 ] ) { if ( info.back() == '\n' ) { @@ -633,7 +632,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) } Log::Notice( "%s: %s", Net::AddressToString( from, true ), info ); - } + } */ } /* @@ -643,16 +642,13 @@ CL_LocalServers_f */ void CL_LocalServers_f() { - const char *message; - int i, j; - serverInfoLog.Verbose( "Scanning for servers on the local network…" ); // reset the list, waiting for response cls.numlocalservers = 0; cls.pingUpdateSource = AS_LOCAL; - for ( i = 0; i < MAX_OTHER_SERVERS; i++ ) + for ( int i = 0; i < MAX_OTHER_SERVERS; i++ ) { bool b = cls.localServers[ i ].visible; cls.localServers[ i ] = {}; @@ -664,24 +660,27 @@ void CL_LocalServers_f() // The 'xxx' in the message is a challenge that will be echoed back // by the server. We don't care about that here, but master servers // can use that to prevent spoofed server responses from invalid IP addresses - message = "\377\377\377\377getinfo xxx"; - int messageLen = strlen(message); + std::string message = "\377\377\377\377xxxxgetinfo xxx"; + + // This will be read by MSG_ReadString, which expects the string length + uint32_t* sizeEncode = ( uint32_t* ) ( message.data() + 4 ); + *sizeEncode = message.size() - 4; // send each message twice in case one is dropped - for ( i = 0; i < 2; i++ ) + for ( int i = 0; i < 2; i++ ) { // send a broadcast packet on each server port // we support multiple server ports so a single machine // can nicely run multiple servers - for ( j = 0; j < NUM_SERVER_PORTS; j++ ) + for ( int j = 0; j < NUM_SERVER_PORTS; j++ ) { to.port = UBigShort( ( uint16_t )( PORT_SERVER + j ) ); to.type = netadrtype_t::NA_BROADCAST; - NET_SendPacket( netsrc_t::NS_CLIENT, messageLen, message, to ); + NET_SendPacket( netsrc_t::NS_CLIENT, message.size(), message.c_str(), to ); to.type = netadrtype_t::NA_MULTICAST6; - NET_SendPacket( netsrc_t::NS_CLIENT, messageLen, message, to ); + NET_SendPacket( netsrc_t::NS_CLIENT, message.size(), message.c_str(), to ); } } } diff --git a/src/engine/client/cl_serverstatus.cpp b/src/engine/client/cl_serverstatus.cpp index c6a1d75125..941b4cb738 100644 --- a/src/engine/client/cl_serverstatus.cpp +++ b/src/engine/client/cl_serverstatus.cpp @@ -186,7 +186,7 @@ void CL_ServerStatusReset() { CL_ServerStatusResponse =================== */ -void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ) +void CL_ServerStatusResponse( const netadr_t& from, const std::vector& lines ) { serverStatus_t *serverStatus = nullptr; @@ -205,7 +205,7 @@ void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ) return; } - serverStatus->string = MSG_ReadString( msg, false ); + serverStatus->string = lines[1]; if ( serverStatus->print ) { @@ -224,41 +224,37 @@ void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ) Log::CommandInteractionMessage( "num: score: ping: name:" ); } - uint32_t i = 0; - while ( true ) - { - const std::string string = MSG_ReadString( msg, false ); + if ( lines.size() > 2 ) { + uint32_t i = 0; + while ( true ) { + const std::string string = lines[2]; - if ( string.empty() ) { - break; - } + if ( string.empty() ) { + break; + } - serverStatus->string += "\\" + string; + serverStatus->string += "\\" + string; - if ( serverStatus->print ) - { - int ping = 0; - int score = 0; - const char* s = string.c_str(); + if ( serverStatus->print ) { + int ping = 0; + int score = 0; + const char* s = string.c_str(); - sscanf( s, "%d %d", &score, &ping ); - s = strchr( s, ' ' ); + sscanf( s, "%d %d", &score, &ping ); + s = strchr( s, ' ' ); - if ( s ) - { - s = strchr( s + 1, ' ' ); - } + if ( s ) { + s = strchr( s + 1, ' ' ); + } - if ( s ) - { - s++; - } - else - { - s = "unknown"; - } + if ( s ) { + s++; + } else { + s = "unknown"; + } - Log::CommandInteractionMessage(Str::Format("%-2d %-3d %-3d %s", i, score, ping, s)); + Log::CommandInteractionMessage( Str::Format( "%-2d %-3d %-3d %s", i, score, ping, s ) ); + } } } diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 9694cd0ee3..995e94e3e3 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -462,7 +462,7 @@ void CL_Record(std::string demo_name); bool CL_ServerStatus( const std::string& serverAddress, std::string& serverStatusString ); void CL_ServerStatusReset(); void CL_ServerStatus_f(); -void CL_ServerStatusResponse( const netadr_t& from, msg_t *msg ); +void CL_ServerStatusResponse( const netadr_t& from, const std::vector& lines ); // // cl_keys (for input usage) @@ -537,7 +537,7 @@ void CL_ParseServerMessage( msg_t *msg ); // // cl_serverlist.cpp // -void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ); +void CL_ServerInfoPacket( const netadr_t& from, const std::string& infoStr ); void CL_ServerLinksResponsePacket( msg_t *msg ); void CL_ServersResponsePacket( const netadr_t *from, msg_t *msg, bool extended ); void CL_LocalServers_f(); diff --git a/src/engine/qcommon/msg.cpp b/src/engine/qcommon/msg.cpp index b020b5d55e..5b55870d86 100644 --- a/src/engine/qcommon/msg.cpp +++ b/src/engine/qcommon/msg.cpp @@ -429,28 +429,47 @@ float MSG_ReadFloat( msg_t *msg ) return dat.f; } -std::string MSG_ReadString( msg_t *msg, const bool allowNewLines ) +std::string MSG_ReadString( msg_t *msg ) { std::string string; uint32_t size = MSG_ReadLong( msg ); string.resize( size ); - if ( allowNewLines ) { - MSG_ReadData( msg, string.data(), size ); - } else { - for ( char* write = string.data(); write < string.data() + size; write++ ) { - const int c = MSG_ReadByte( msg ); + MSG_ReadData( msg, string.data(), size ); - if ( c == '\n' ) { - break; - } + return string; +} + +std::vector MSG_ReadStringLines( msg_t* msg ) { + std::string string; + uint32_t size = MSG_ReadLong( msg ); + + string.reserve( size ); + + std::vector out; - *write = c; + for ( uint32_t i = 0; i < size; i++ ) { + const int c = MSG_ReadByte( msg ); + + if ( c == '\n' ) { + string.shrink_to_fit(); + out.push_back( string ); + + string.clear(); + string.reserve( size - out.back().size() ); + continue; } + + string.push_back( c ); } - return string; + if ( string.size() ) { + string.shrink_to_fit(); + out.push_back( string ); + } + + return out; } void MSG_ReadData( msg_t *msg, void *data, int len ) diff --git a/src/engine/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index a2724f4956..34ce844e2f 100644 --- a/src/engine/qcommon/qcommon.h +++ b/src/engine/qcommon/qcommon.h @@ -83,7 +83,8 @@ int MSG_ReadByte( msg_t *sb ); int MSG_ReadShort( msg_t *sb ); int MSG_ReadLong( msg_t *sb ); float MSG_ReadFloat( msg_t *sb ); -std::string MSG_ReadString( msg_t *sb, const bool allowNewLines = true ); +std::string MSG_ReadString( msg_t *sb ); +std::vector MSG_ReadStringLines( msg_t* sb ); void MSG_ReadData( msg_t *sb, void *buffer, int size ); void MSG_WriteDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ); diff --git a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp index e69a074733..b707d40488 100644 --- a/src/engine/server/sv_main.cpp +++ b/src/engine/server/sv_main.cpp @@ -978,7 +978,8 @@ static void SV_ConnectionlessPacket( const netadr_t& from, msg_t *msg ) Huff_Decompress( msg, 16 ); } - Cmd::Args args( MSG_ReadString( msg, false ) ); + std::vector lines = MSG_ReadStringLines( msg ); + Cmd::Args args( lines[0] ); if ( args.Argc() <= 0 ) { From 87df3f969bda16d05845a0a0539d0be1a9751241 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 15 Sep 2025 13:11:45 +0300 Subject: [PATCH 09/17] NUKE Info_SetValueForKeyRocket() --- src/engine/qcommon/q_shared.cpp | 35 --------------------------------- src/engine/qcommon/q_shared.h | 2 -- 2 files changed, 37 deletions(-) diff --git a/src/engine/qcommon/q_shared.cpp b/src/engine/qcommon/q_shared.cpp index 30e4346364..6813d387c3 100644 --- a/src/engine/qcommon/q_shared.cpp +++ b/src/engine/qcommon/q_shared.cpp @@ -1984,41 +1984,6 @@ void Info_SetValueForKey( char *s, const char *key, const char *value, bool big strcat( s, newi ); } -void Info_SetValueForKeyRocket( char *s, const char *key, const char *value, bool big ) -{ - int maxlen = big ? BIG_INFO_STRING : MAX_INFO_STRING; - int slen = strlen( s ); - static char newi[ BIG_INFO_STRING ]; - - if ( slen >= maxlen ) - { - Sys::Drop( "Info_SetValueForKey: oversize infostring [%s] [%s] [%s]", s, key, value ); - } - - if ( strchr( key, '\\' ) || ( value && strchr( value, '\\' ) ) ) - { - Log::Notice( "Can't use keys or values with a \\" ); - return; - } - - Info_RemoveKey( s, key, true ); - - if ( !value || !strlen( value ) ) - { - return; - } - - Com_sprintf( newi, maxlen, "\\%s\\%s", key, value ); - - if ( strlen( newi ) + slen >= (unsigned) maxlen ) - { - Log::Notice( "Info string length exceeded" ); - return; - } - - strcat( s, newi ); -} - /* ============ Com_ClientListContains diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index 16467be06a..e0b7afed98 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -1605,8 +1605,6 @@ inline vec_t VectorNormalize2( const vec3_t v, vec3_t out ) // DEPRECATED: Use InfoMap void Info_SetValueForKey( char *s, const char *key, const char *value , bool big ); // DEPRECATED: Use InfoMap - void Info_SetValueForKeyRocket( char *s, const char *key, const char *value, bool big ); - // DEPRECATED: Use InfoMap bool Info_Validate( const char *s ); // DEPRECATED: Use InfoMap void Info_NextPair( const char **s, char *key, char *value ); From e4f2314d33487c15d51d21ad66419d08de68d873 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:09:31 +0300 Subject: [PATCH 10/17] FS_LoadedPaks(): use std::string --- src/engine/qcommon/files.cpp | 14 +++++++------- src/engine/qcommon/qcommon.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/qcommon/files.cpp b/src/engine/qcommon/files.cpp index 371dd20aec..5a575ea4f8 100644 --- a/src/engine/qcommon/files.cpp +++ b/src/engine/qcommon/files.cpp @@ -621,18 +621,18 @@ int FS_GetFileListRecursive(const char* path, const char* extension, char* listB return numFiles; } -const char* FS_LoadedPaks() +std::string FS_LoadedPaks() { - static char info[BIG_INFO_STRING]; - info[0] = '\0'; + std::string out; for (const FS::LoadedPakInfo& x: FS::PakPath::GetLoadedPaks()) { if (!x.pathPrefix.empty()) continue; - if (info[0]) - Q_strcat(info, sizeof(info), " "); - Q_strcat(info, sizeof(info), FS::MakePakName(x.name, x.version, x.realChecksum).c_str()); + if ( out.size() ) { + out += " "; + } + out += FS::MakePakName(x.name, x.version, x.realChecksum); } - return info; + return out; } bool FS_LoadPak(const Str::StringRef name) diff --git a/src/engine/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index 34ce844e2f..4114c6de49 100644 --- a/src/engine/qcommon/qcommon.h +++ b/src/engine/qcommon/qcommon.h @@ -423,7 +423,7 @@ int FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin ); // seek on a file (doesn't work for zip files!!!!!!!!) -const char* FS_LoadedPaks(); +std::string FS_LoadedPaks(); // Returns a space separated string containing all loaded dpk/pk3 files. From 2e5e399129a4d00c7fb9a653a63ed3acbc613dea Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:10:07 +0300 Subject: [PATCH 11/17] CVar::InfoString(): use std::string --- src/engine/client/cl_main.cpp | 4 ++-- src/engine/framework/CvarSystem.cpp | 9 ++++----- src/engine/framework/CvarSystem.h | 2 +- src/engine/qcommon/cvar.cpp | 4 ++-- src/engine/qcommon/cvar.h | 2 +- src/engine/server/sv_ccmds.cpp | 4 ++-- src/engine/server/sv_init.cpp | 4 ++-- src/engine/server/sv_main.cpp | 4 ++-- src/engine/server/sv_sgame.cpp | 2 +- 9 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/engine/client/cl_main.cpp b/src/engine/client/cl_main.cpp index f860166e3f..e327a62e79 100644 --- a/src/engine/client/cl_main.cpp +++ b/src/engine/client/cl_main.cpp @@ -1507,7 +1507,7 @@ void CL_Clientinfo_f() Log::Notice( "state: %s", Util::enum_str(cls.state)); Log::Notice( "Server: %s", cls.servername ); Log::Notice("User info settings:" ); - Info_Print( Cvar_InfoString( CVAR_USERINFO, false ) ); + Info_Print( Cvar_InfoString( CVAR_USERINFO ).c_str() ); Log::Notice("--------------------------------------" ); } @@ -1989,7 +1989,7 @@ void CL_CheckUserinfo() if ( cvar_modifiedFlags & CVAR_USERINFO ) { cvar_modifiedFlags &= ~CVAR_USERINFO; - CL_AddReliableCommand( va( "userinfo %s", Cmd_QuoteString( Cvar_InfoString( CVAR_USERINFO, false ) ) ) ); + CL_AddReliableCommand( va( "userinfo %s", Cmd_QuoteString( Cvar_InfoString( CVAR_USERINFO ).c_str() ) ) ); } } diff --git a/src/engine/framework/CvarSystem.cpp b/src/engine/framework/CvarSystem.cpp index e9b2acb717..f4e6a953e1 100644 --- a/src/engine/framework/CvarSystem.cpp +++ b/src/engine/framework/CvarSystem.cpp @@ -547,9 +547,8 @@ namespace Cvar { return result.str(); } - char* InfoString(int flag, bool big) { - static char info[BIG_INFO_STRING]; - info[0] = 0; + std::string InfoString(int flag) { + std::string out; CvarMap& cvars = GetCvarMap(); @@ -557,11 +556,11 @@ namespace Cvar { cvarRecord_t* cvar = entry.second; if (cvar->flags & flag) { - Info_SetValueForKey(info, entry.first.c_str(), cvar->value.c_str(), big); + out += entry.first + "\\" + cvar->value; } } - return info; + return out; } void PopulateInfoMap(int flag, InfoMap& map) { diff --git a/src/engine/framework/CvarSystem.h b/src/engine/framework/CvarSystem.h index 92952154e2..d09d773d9a 100644 --- a/src/engine/framework/CvarSystem.h +++ b/src/engine/framework/CvarSystem.h @@ -87,7 +87,7 @@ namespace Cvar { cvar_t* FindCCvar(const std::string& cvarName); std::string GetCvarConfigText(); // DEPRECATED: Use PopulateInfoMap - char* InfoString(int flag, bool big); + std::string InfoString(int flag); void PopulateInfoMap(int flag, InfoMap& map); void SetValueCProxy(const std::string& cvarName, const std::string& value); diff --git a/src/engine/qcommon/cvar.cpp b/src/engine/qcommon/cvar.cpp index 55026c0352..088c765bf1 100644 --- a/src/engine/qcommon/cvar.cpp +++ b/src/engine/qcommon/cvar.cpp @@ -164,6 +164,6 @@ void Cvar_WriteVariables( fileHandle_t f ) Cvar_InfoString ===================== */ -char* Cvar_InfoString(int flag, bool big) { - return Cvar::InfoString(flag, big); +std::string Cvar_InfoString(int flag) { + return Cvar::InfoString(flag); } diff --git a/src/engine/qcommon/cvar.h b/src/engine/qcommon/cvar.h index 8dcfea07b3..f7e5557fe2 100644 --- a/src/engine/qcommon/cvar.h +++ b/src/engine/qcommon/cvar.h @@ -97,7 +97,7 @@ void Cvar_WriteVariables(fileHandle_t f); * returns an info string containing all the cvars that have the given bit set * in their flags ( CVAR_USERINFO, CVAR_SERVERINFO, CVAR_SYSTEMINFO, etc ) */ -char *Cvar_InfoString(int bit, bool big); +std::string Cvar_InfoString(int bit); /** * whenever a cvar is modified, its flags will be OR'd into this, so diff --git a/src/engine/server/sv_ccmds.cpp b/src/engine/server/sv_ccmds.cpp index 5f066e1fd1..538389c138 100644 --- a/src/engine/server/sv_ccmds.cpp +++ b/src/engine/server/sv_ccmds.cpp @@ -365,7 +365,7 @@ static void SV_Serverinfo_f() } Log::Notice( "Server info settings:" ); - Info_Print( Cvar_InfoString( CVAR_SERVERINFO, false ) ); + Info_Print( Cvar_InfoString( CVAR_SERVERINFO ).c_str() ); } /* @@ -385,7 +385,7 @@ static void SV_Systeminfo_f() } Log::Notice( "System info settings:" ); - Info_Print( Cvar_InfoString( CVAR_SYSTEMINFO, false ) ); + Info_Print( Cvar_InfoString( CVAR_SYSTEMINFO ).c_str() ); } class ListMapsCmd: public Cmd::StaticCmd diff --git a/src/engine/server/sv_init.cpp b/src/engine/server/sv_init.cpp index 77a8642ab6..a5a24f9204 100644 --- a/src/engine/server/sv_init.cpp +++ b/src/engine/server/sv_init.cpp @@ -563,9 +563,9 @@ void SV_SpawnServer(std::string pakname, std::string mapname) // save systeminfo and serverinfo strings cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; - SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO, true ) ); + SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ).c_str() ); - SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO, false ) ); + SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ).c_str() ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning diff --git a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp index b707d40488..0bb2ef492b 100644 --- a/src/engine/server/sv_main.cpp +++ b/src/engine/server/sv_main.cpp @@ -1360,13 +1360,13 @@ void SV_Frame( int msec ) // update infostrings if anything has been changed if ( cvar_modifiedFlags & CVAR_SERVERINFO ) { - SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO, false ) ); + SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ).c_str() ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; } if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) { - SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO, true ) ); + SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ).c_str() ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; } diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index da2ca5804b..d4f474b7dd 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -174,7 +174,7 @@ void SV_GetServerinfo( char *buffer, int bufferSize ) Sys::Drop( "SV_GetServerinfo: bufferSize == %i", bufferSize ); } - Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO, false ), bufferSize ); + Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ).c_str(), bufferSize ); } /* From 4b93c4e21e3501e649306090b5e1912ffd891bda Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:15:31 +0300 Subject: [PATCH 12/17] SV_GetServerinfo(): use std::string --- src/engine/server/sg_msgdef.h | 2 +- src/engine/server/sv_sgame.cpp | 16 ++++------------ src/shared/server/sg_api.cpp | 6 +++--- src/shared/server/sg_api.h | 2 +- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/engine/server/sg_msgdef.h b/src/engine/server/sg_msgdef.h index 3e3a680152..36220d9f5b 100644 --- a/src/engine/server/sg_msgdef.h +++ b/src/engine/server/sg_msgdef.h @@ -75,7 +75,7 @@ using GetUserinfoMsg = IPC::SyncMessage< IPC::Reply >; using GetServerinfoMsg = IPC::SyncMessage< - IPC::Message, int>, + IPC::Message>, IPC::Reply >; using GetUsercmdMsg = IPC::SyncMessage< diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index d4f474b7dd..0f23695e8a 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -167,14 +167,9 @@ SV_GetServerinfo =============== */ -void SV_GetServerinfo( char *buffer, int bufferSize ) +std::string SV_GetServerinfo() { - if ( bufferSize < 1 ) - { - Sys::Drop( "SV_GetServerinfo: bufferSize == %i", bufferSize ); - } - - Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ).c_str(), bufferSize ); + return Cvar_InfoString( CVAR_SERVERINFO ); } /* @@ -498,11 +493,8 @@ void GameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& chan break; case G_GET_SERVERINFO: - IPC::HandleMsg(channel, std::move(reader), [this](int len, std::string& res) { - std::unique_ptr buffer(new char[len]); - buffer[0] = '\0'; - SV_GetServerinfo(buffer.get(), len); - res.assign(buffer.get()); + IPC::HandleMsg(channel, std::move(reader), [this](std::string& res) { + res = SV_GetServerinfo(); }); break; diff --git a/src/shared/server/sg_api.cpp b/src/shared/server/sg_api.cpp index 90de7906fb..0d50e7e48e 100644 --- a/src/shared/server/sg_api.cpp +++ b/src/shared/server/sg_api.cpp @@ -91,11 +91,11 @@ std::string trap_GetUserinfo( int num ) return res; } -void trap_GetServerinfo(char *buffer, int bufferSize) +std::string trap_GetServerinfo() { std::string res; - VM::SendMsg(bufferSize, res); - Q_strncpyz(buffer, res.c_str(), bufferSize); + VM::SendMsg(res); + return res; } void trap_GetUsercmd(int clientNum, usercmd_t *cmd) diff --git a/src/shared/server/sg_api.h b/src/shared/server/sg_api.h index c6fdae8d72..7973f42a30 100644 --- a/src/shared/server/sg_api.h +++ b/src/shared/server/sg_api.h @@ -43,7 +43,7 @@ void trap_SetConfigstringRestrictions( int num, const clientList_t * void trap_GetConfigstring( int num, char *buffer, int bufferSize ); void trap_SetUserinfo( int num, const std::string& userinfo ); std::string trap_GetUserinfo( int num ); -void trap_GetServerinfo( char *buffer, int bufferSize ); +std::string trap_GetServerinfo(); int trap_BotAllocateClient(); void trap_BotFreeClient( int clientNum ); void trap_GetUsercmd( int clientNum, usercmd_t *cmd ); From 468d5133a65956dfa6605cfb2f06a437f05dcd92 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:20:10 +0300 Subject: [PATCH 13/17] trap_EscapedArgs()/trap_LiteralArgs(): use std::string --- src/shared/CommonProxies.cpp | 12 ++++-------- src/shared/CommonProxies.h | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/shared/CommonProxies.cpp b/src/shared/CommonProxies.cpp index 24be8c403b..7dc91d6093 100644 --- a/src/shared/CommonProxies.cpp +++ b/src/shared/CommonProxies.cpp @@ -242,16 +242,12 @@ const Cmd::Args& trap_Args() { return *argStack.back(); } -void trap_EscapedArgs( char *buffer, int bufferLength ) { - const Cmd::Args* args = argStack.back(); - std::string res = args->EscapedArgs(0); - Q_strncpyz( buffer, res.c_str(), bufferLength ); +std::string trap_EscapedArgs() { + return argStack.back()->EscapedArgs(0); } -void trap_LiteralArgs( char *buffer, int bufferLength ) { - const Cmd::Args* args = argStack.back(); - std::string res = args->ConcatArgs(0); - Q_strncpyz( buffer, res.c_str(), bufferLength ); +std::string trap_LiteralArgs() { + return argStack.back()->ConcatArgs(0); } namespace Cmd { diff --git a/src/shared/CommonProxies.h b/src/shared/CommonProxies.h index 7f96275033..f549c25682 100644 --- a/src/shared/CommonProxies.h +++ b/src/shared/CommonProxies.h @@ -55,8 +55,8 @@ void trap_CompleteCallback(const char* complete); int trap_Argc(); void trap_Argv(int n, char* buffer, int bufferLength); const Cmd::Args& trap_Args(); -void trap_EscapedArgs(char* buffer, int bufferLength); -void trap_LiteralArgs(char* buffer, int bufferLength); +std::string trap_EscapedArgs(); +std::string trap_LiteralArgs(); void trap_Cvar_Set(const char* varName, const char* value); int trap_Cvar_VariableIntegerValue(const char* varName); float trap_Cvar_VariableValue(const char* varName); From 2b74c56f0e3f74180dc97a5ed469c4e277fcecd2 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:28:58 +0300 Subject: [PATCH 14/17] NUKE unused MAX_INFO_KEY and MAX_INFO_VALUE --- src/engine/qcommon/q_shared.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index e0b7afed98..910c59ab53 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -182,8 +182,6 @@ using clipHandle_t = int; #define MAX_ADDR_CHARS sizeof("[1111:2222:3333:4444:5555:6666:7777:8888]:99999") #define MAX_INFO_STRING 1024 -#define MAX_INFO_KEY 1024 -#define MAX_INFO_VALUE 1024 #define BIG_INFO_STRING 8192 // used for system info key only #define BIG_INFO_KEY 8192 From 51c1dfdaa1ff10bb409a0c3514ebe5a86a0b8193 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:46:48 +0300 Subject: [PATCH 15/17] Shut CI up --- src/engine/qcommon/msg.cpp | 3 ++- src/engine/server/sv_client.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/qcommon/msg.cpp b/src/engine/qcommon/msg.cpp index 5b55870d86..41ab6e2f3f 100644 --- a/src/engine/qcommon/msg.cpp +++ b/src/engine/qcommon/msg.cpp @@ -436,7 +436,8 @@ std::string MSG_ReadString( msg_t *msg ) string.resize( size ); - MSG_ReadData( msg, string.data(), size ); + void* fuckOffGCC = string.data(); + MSG_ReadData( msg, fuckOffGCC, size ); return string; } diff --git a/src/engine/server/sv_client.cpp b/src/engine/server/sv_client.cpp index db6024a5ae..4c534d6e76 100644 --- a/src/engine/server/sv_client.cpp +++ b/src/engine/server/sv_client.cpp @@ -1338,7 +1338,7 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) // NOTE: when the client message is fux0red the acknowledgement numbers // can be out of range, this could cause the server to send thousands of server // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient - if ( cl->reliableAcknowledge < 0 || cl->reliableAcknowledge > cl->reliableSequence ) + if ( cl->reliableAcknowledge > cl->reliableSequence ) { // usually only hackers create messages like this // it is more annoying for them to let them hanging From ef7e82e090c93ba22d5366086423866ce8d939ac Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:55:38 +0300 Subject: [PATCH 16/17] . --- src/engine/qcommon/msg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/qcommon/msg.cpp b/src/engine/qcommon/msg.cpp index 41ab6e2f3f..8065fc6e75 100644 --- a/src/engine/qcommon/msg.cpp +++ b/src/engine/qcommon/msg.cpp @@ -436,7 +436,7 @@ std::string MSG_ReadString( msg_t *msg ) string.resize( size ); - void* fuckOffGCC = string.data(); + void* fuckOffGCC = const_cast( string.data() ); MSG_ReadData( msg, fuckOffGCC, size ); return string; From 3f26fccfff0fd4ac5eb860a2c10407c373ba2148 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 16 Mar 2026 11:59:49 +0300 Subject: [PATCH 17/17] . --- src/engine/qcommon/msg.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/engine/qcommon/msg.cpp b/src/engine/qcommon/msg.cpp index 8065fc6e75..daa6f7ac7b 100644 --- a/src/engine/qcommon/msg.cpp +++ b/src/engine/qcommon/msg.cpp @@ -431,15 +431,14 @@ float MSG_ReadFloat( msg_t *msg ) std::string MSG_ReadString( msg_t *msg ) { - std::string string; uint32_t size = MSG_ReadLong( msg ); - string.resize( size ); + std::vector data; + data.resize( size ); - void* fuckOffGCC = const_cast( string.data() ); - MSG_ReadData( msg, fuckOffGCC, size ); + MSG_ReadData( msg, data.data(), size ); - return string; + return std::string( data.begin(), data.end() ); } std::vector MSG_ReadStringLines( msg_t* msg ) {