diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index f956e8bf..515c0960 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -669,9 +669,9 @@ FRAME PARSING ========================================================================= */ -static qboolean CL_ParseEntityNumFromPacket( sizebuf_t *msg, int *newnum ) +static qboolean CL_ParseEntityNumFromPacket( sizebuf_t *msg, int *newnum, connprotocol_t proto ) { - if( cls.legacymode ) + if( proto == PROTO_LEGACY ) { *newnum = MSG_ReadWord( msg ); if( *newnum == 0 ) @@ -694,7 +694,7 @@ CL_FlushEntityPacket Read and ignore whole entity packet. ================= */ -static void CL_FlushEntityPacket( sizebuf_t *msg ) +static void CL_FlushEntityPacket( sizebuf_t *msg, connprotocol_t proto ) { int newnum; entity_state_t from, to; @@ -707,7 +707,7 @@ static void CL_FlushEntityPacket( sizebuf_t *msg ) // read it all, but ignore it while( 1 ) { - if( !CL_ParseEntityNumFromPacket( msg, &newnum )) + if( !CL_ParseEntityNumFromPacket( msg, &newnum, proto )) break; // done if( MSG_CheckOverflow( msg )) @@ -717,6 +717,47 @@ static void CL_FlushEntityPacket( sizebuf_t *msg ) } } +qboolean CL_ValidateDeltaPacket( uint oldpacket, frame_t *oldframe ) +{ + int subtracted = ( cls.netchan.incoming_sequence - oldpacket ) & 0xFF; + + if( subtracted == 0 ) + { + Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" ); + return false; + } + + if( subtracted >= CL_UPDATE_MASK ) + { + // we can't use this, it is too old + Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); + return false; + } + + if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - NUM_PACKET_ENTITIES )) + { + Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); + return false; + } + + return true; +} + +int CL_UpdateOldEntNum( int oldindex, frame_t *oldframe, entity_state_t **oldent ) +{ + if( !oldframe ) + { + *oldent = NULL; + return MAX_ENTNUMBER; + } + + if( oldindex >= oldframe->num_entities ) + return MAX_ENTNUMBER; + + *oldent = &cls.packet_entities[(oldframe->first_entity + oldindex) % cls.num_client_entities]; + return (*oldent)->number; +} + /* ================= CL_DeltaEntity @@ -787,7 +828,7 @@ An svc_packetentities has just been parsed, deal with the rest of the data stream. ================== */ -int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) +int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto ) { frame_t *newframe, *oldframe; int oldindex, newnum, oldnum; @@ -803,7 +844,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) CL_WriteDemoJumpTime(); // sentinel count. save it for debug checking - if( cls.legacymode ) + if( proto == PROTO_LEGACY ) count = MSG_ReadWord( msg ); else count = MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS ) + 1; @@ -817,32 +858,12 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) if( delta ) { - int subtracted; - - oldpacket = MSG_ReadByte( msg ); - subtracted = ( cls.netchan.incoming_sequence - oldpacket ) & 0xFF; - - if( subtracted == 0 ) - { - Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" ); - CL_FlushEntityPacket( msg ); - return playerbytes; - } - - if( subtracted >= CL_UPDATE_MASK ) - { - // we can't use this, it is too old - Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); - CL_FlushEntityPacket( msg ); - return playerbytes; - } - + uint oldpacket = MSG_ReadByte( msg ); oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK]; - if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - NUM_PACKET_ENTITIES )) + if( !CL_ValidateDeltaPacket( oldpacket, oldframe )) { - Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); - CL_FlushEntityPacket( msg ); + CL_FlushEntityPacket( msg, proto ); return playerbytes; } } @@ -860,27 +881,11 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) oldent = NULL; oldindex = 0; - - if( !oldframe ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } - } + oldnum = CL_UpdateOldEntNum( oldindex, oldframe, &oldent ); while( 1 ) { - if( !CL_ParseEntityNumFromPacket( msg, &newnum )) + if( !CL_ParseEntityNumFromPacket( msg, &newnum, proto )) break; // done if( MSG_CheckOverflow( msg )) @@ -892,17 +897,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) { // one or more entities from the old packet are unchanged CL_DeltaEntity( msg, newframe, oldnum, oldent, false ); - oldindex++; - - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); } if( oldnum == newnum ) @@ -911,17 +906,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) bufStart = MSG_GetNumBytesRead( msg ); CL_DeltaEntity( msg, newframe, newnum, oldent, true ); if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufStart; - oldindex++; - - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); continue; } @@ -940,17 +925,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) { // one or more entities from the old packet are unchanged CL_DeltaEntity( msg, newframe, oldnum, oldent, false ); - oldindex++; - - if( oldindex >= oldframe->num_entities ) - { - oldnum = MAX_ENTNUMBER; - } - else - { - oldent = &cls.packet_entities[(oldframe->first_entity+oldindex) % cls.num_client_entities]; - oldnum = oldent->number; - } + oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); } if( newframe->num_entities != count && newframe->num_entities != 0 ) @@ -972,7 +947,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) cls.signon = SIGNONS; // Clear loading plaque. - CL_SignonReply (); + CL_SignonReply( proto ); } return playerbytes; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index f250bfb5..f88ce4af 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -223,7 +223,7 @@ CL_SignonReply An svc_signonnum has been received, perform a client side setup ===================== */ -void CL_SignonReply( void ) +void CL_SignonReply( connprotocol_t proto ) { // g-cont. my favorite message :-) Con_Reportf( "%s: %i\n", __func__, cls.signon ); @@ -231,7 +231,7 @@ void CL_SignonReply( void ) switch( cls.signon ) { case 1: - CL_ServerCommand( true, "begin" ); + CL_ServerCommand( true, proto == PROTO_GOLDSRC ? "sendents" : "begin" ); if( host_developer.value >= DEV_EXTENDED ) Mem_PrintStats(); break; @@ -699,7 +699,13 @@ void CL_WriteUsercmd( sizebuf_t *msg, int from, int to ) t = &cl.commands[to].cmd; // write it into the buffer - MSG_WriteDeltaUsercmd( msg, f, t ); + if( cls.legacymode == PROTO_GOLDSRC ) + { + MSG_StartBitWriting( msg ); + Delta_WriteGSFields( msg, DT_USERCMD_T, f, t, 0.0f ); + MSG_EndBitWriting( msg ); + } + else MSG_WriteDeltaUsercmd( msg, f, t ); } /* @@ -798,6 +804,9 @@ static void CL_WritePacket( void ) // begin a client move command MSG_BeginClientCmd( &buf, clc_move ); + if( cls.legacymode == PROTO_GOLDSRC ) + MSG_WriteByte( &buf, 0 ); + // save the position for a checksum byte key = MSG_GetRealBytesWritten( &buf ); MSG_WriteByte( &buf, 0 ); @@ -835,8 +844,16 @@ static void CL_WritePacket( void ) // calculate a checksum over the move commands size = MSG_GetRealBytesWritten( &buf ) - key - 1; + if( cls.legacymode == PROTO_GOLDSRC ) + { + size = Q_min( size, 255 ); + buf.pData[key - 1] = size; + } buf.pData[key] = CRC32_BlockSequence( buf.pData + key + 1, size, cls.netchan.outgoing_sequence ); + if( cls.legacymode == PROTO_GOLDSRC ) + COM_Munge( buf.pData + key + 1, size, cls.netchan.outgoing_sequence ); + // message we are constructing. i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK; @@ -1054,7 +1071,31 @@ static void CL_SendConnectPacket( void ) Info_SetValueForKey( protinfo, "a", Q_buildarch(), sizeof( protinfo ) ); } - if( cls.legacymode ) + if( cls.legacymode == PROTO_GOLDSRC ) + { + byte send_buf[MAX_PRINT_MSG]; + byte steam_cert[512]; + sizebuf_t send; + + protinfo[0] = 0; + + memset( steam_cert, 0, sizeof( steam_cert )); + + Info_SetValueForKey( protinfo, "prot", "3", sizeof( protinfo )); // steam auth type + Info_SetValueForKey( protinfo, "raw", "steam", sizeof( protinfo )); + Info_SetValueForKey( protinfo, "cdkey", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", sizeof( protinfo )); + + Info_SetValueForStarKey( cls.userinfo, "*hltv", "0", sizeof( cls.userinfo )); + + MSG_Init( &send, "GoldSrcConnect", send_buf, sizeof( send_buf )); + MSG_WriteLong( &send, NET_HEADER_OUTOFBANDPACKET ); + MSG_WriteStringf( &send, "connect %i %i \"%s\" \"%s\"\n", + PROTOCOL_GOLDSRC_VERSION, cls.challenge, protinfo, cls.userinfo ); + MSG_WriteBytes( &send, steam_cert, sizeof( steam_cert )); + + NET_SendPacket( NS_CLIENT, MSG_GetNumBytesWritten( &send ), MSG_GetData( &send ), adr ); + } + else if( cls.legacymode == PROTO_LEGACY ) { // set related userinfo keys if( cl_dlmax.value >= 40000 || cl_dlmax.value < 100 ) @@ -1280,15 +1321,16 @@ static void CL_Connect_f( void ) { const char *s = Cmd_Argv( 2 ); - if( !Q_strcmp( s, "current" ) || !Q_strcmp( s, "49" )) + if( !Q_stricmp( s, "current" ) || !Q_strcmp( s, "49" )) proto = PROTO_CURRENT; - else if( !Q_strcmp( s, "legacy" ) || !Q_strcmp( s, "48" )) + else if( !Q_stricmp( s, "legacy" ) || !Q_strcmp( s, "48" )) proto = PROTO_LEGACY; + else if( !Q_stricmp( s, "goldsrc" ) || !Q_strcmp( s, "gs" )) + proto = PROTO_GOLDSRC; else { // quake protocol only used for demos - // goldsrc protocol is not supported yet - Con_Printf( "Unknown protocol. Supported are: current, legacy\n" ); + Con_Printf( "Unknown protocol. Supported are: 49 (current), 48 (legacy), gs (goldsrc)\n" ); return; } } @@ -2055,7 +2097,7 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) Con_Reportf( "%s: %s : %s\n", __func__, NET_AdrToString( from ), c ); // server connection - if( !Q_strcmp( c, "client_connect" )) + if( !Q_strcmp( c, "client_connect" ) || !Q_strcmp( c, S2C_CONNECTION )) { if( !CL_IsFromConnectingServer( from )) return; @@ -2177,7 +2219,7 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) // ping from somewhere Netchan_OutOfBandPrint( NS_CLIENT, from, "ack" ); } - else if( !Q_strcmp( c, "challenge" )) + else if( !Q_strcmp( c, "challenge" ) || !Q_strcmp( c, S2C_CHALLENGE )) { // this message only used during connection // it doesn't make sense after client_connect @@ -2214,7 +2256,7 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) // dropped the connection but it is still getting packets from us CL_Disconnect_f(); } - else if( !Q_strcmp( c, "errormsg" )) + else if( !Q_strcmp( c, "errormsg" ) || c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD ) { char formatted_msg[MAX_VA_STRING]; @@ -2222,6 +2264,8 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) return; args = MSG_ReadString( msg ); + if( c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD ) + args++; // skip one byte Q_snprintf( formatted_msg, sizeof( formatted_msg ), "^3Server message^7\n%s", args ); @@ -2386,6 +2430,8 @@ static void CL_ReadNetMessage( void ) parsefn = CL_ParseQuakeMessage; break; case PROTO_GOLDSRC: + parsefn = CL_ParseGoldSrcServerMessage; + break; default: ASSERT( 0 ); return; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 563becfa..c513801c 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -216,7 +216,7 @@ CL_ParseSignon ================== */ -void CL_ParseSignon( sizebuf_t *msg ) +void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto ) { int i = MSG_ReadByte( msg ); @@ -228,7 +228,7 @@ void CL_ParseSignon( sizebuf_t *msg ) } cls.signon = i; - CL_SignonReply(); + CL_SignonReply( proto ); } /* @@ -2480,7 +2480,7 @@ void CL_ParseServerMessage( sizebuf_t *msg ) cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); break; case svc_signonnum: - CL_ParseSignon( msg ); + CL_ParseSignon( msg, PROTO_CURRENT ); break; case svc_centerprint: CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); @@ -2523,12 +2523,12 @@ void CL_ParseServerMessage( sizebuf_t *msg ) CL_RegisterUserMessage( msg ); break; case svc_packetentities: - playerbytes = CL_ParsePacketEntities( msg, false ); + playerbytes = CL_ParsePacketEntities( msg, false, PROTO_CURRENT ); cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; break; case svc_deltapacketentities: - playerbytes = CL_ParsePacketEntities( msg, true ); + playerbytes = CL_ParsePacketEntities( msg, true, PROTO_CURRENT ); cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; break; diff --git a/engine/client/cl_parse_48.c b/engine/client/cl_parse_48.c index f0815328..05055a7b 100644 --- a/engine/client/cl_parse_48.c +++ b/engine/client/cl_parse_48.c @@ -492,7 +492,7 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg ) cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); break; case svc_signonnum: - CL_ParseSignon( msg ); + CL_ParseSignon( msg, PROTO_LEGACY ); break; case svc_centerprint: CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); @@ -538,12 +538,12 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg ) CL_RegisterUserMessage( msg ); break; case svc_packetentities: - playerbytes = CL_ParsePacketEntities( msg, false ); + playerbytes = CL_ParsePacketEntities( msg, false, PROTO_LEGACY ); cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; break; case svc_deltapacketentities: - playerbytes = CL_ParsePacketEntities( msg, true ); + playerbytes = CL_ParsePacketEntities( msg, true, PROTO_LEGACY ); cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; break; diff --git a/engine/client/cl_parse_gs.c b/engine/client/cl_parse_gs.c index 5581f862..675f7101 100644 --- a/engine/client/cl_parse_gs.c +++ b/engine/client/cl_parse_gs.c @@ -382,7 +382,7 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta ) cls.signon = SIGNONS; // Clear loading plaque. - CL_SignonReply (); + CL_SignonReply( PROTO_GOLDSRC ); } return playerbytes; @@ -516,29 +516,12 @@ CL_ParseGoldSrcServerMessage dispatch messages ===================== */ -void CL_ParseGoldSrcServerMessage( sizebuf_t *msg, qboolean normal_message ) +void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) { size_t bufStart, playerbytes; int cmd, param1, param2; const char *s; - cls.starting_count = MSG_GetNumBytesRead( msg ); // updates each frame - CL_Parse_Debug( true ); // begin parsing - - if( normal_message ) - { - // assume no entity/player update this packet - if( cls.state == ca_active ) - { - cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].valid = false; - cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = false; - } - else - { - CL_ResetFrame( &cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK] ); - } - } - // parse the message while( 1 ) { @@ -658,7 +641,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg, qboolean normal_message ) cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); break; case svc_signonnum: - CL_ParseSignon( msg ); + CL_ParseSignon( msg, PROTO_GOLDSRC ); break; case svc_centerprint: CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); @@ -771,21 +754,4 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg, qboolean normal_message ) break; } } - - cl.frames[cl.parsecountmod].graphdata.msgbytes += MSG_GetNumBytesRead( msg ) - cls.starting_count; - CL_Parse_Debug( false ); // done - - // we don't know if it is ok to save a demo message until - // after we have parsed the frame - if( !cls.demoplayback ) - { - if( cls.demorecording && !cls.demowaiting ) - { - CL_WriteDemoMessage( false, cls.starting_count, msg ); - } - else if( cls.state != ca_active ) - { - CL_WriteDemoMessage( true, cls.starting_count, msg ); - } - } } diff --git a/engine/client/cl_qparse.c b/engine/client/cl_qparse.c index f4682ec7..9e52c068 100644 --- a/engine/client/cl_qparse.c +++ b/engine/client/cl_qparse.c @@ -431,7 +431,7 @@ static void CL_ParseQuakeEntityData( sizebuf_t *msg, int bits ) cls.signon = SIGNONS; // Clear loading plaque. - CL_SignonReply (); + CL_SignonReply( PROTO_QUAKE ); } // alloc next slot to store update diff --git a/engine/client/client.h b/engine/client/client.h index 0ce21b95..5db23343 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -754,7 +754,7 @@ qboolean CL_PrecacheResources( void ); void CL_SetupOverviewParams( void ); void CL_UpdateFrameLerp( void ); int CL_IsDevOverviewMode( void ); -void CL_SignonReply( void ); +void CL_SignonReply( connprotocol_t proto ); void CL_ClearState( void ); // @@ -871,7 +871,7 @@ void CL_UpdateUserPings( sizebuf_t *msg ); void CL_ParseParticles( sizebuf_t *msg ); void CL_ParseRestoreSoundPacket( sizebuf_t *msg ); void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto ); -void CL_ParseSignon( sizebuf_t *msg ); +void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseRestore( sizebuf_t *msg ); void CL_ParseStaticDecal( sizebuf_t *msg ); void CL_ParseAddAngle( sizebuf_t *msg ); @@ -912,7 +912,7 @@ void CL_LegacyPrecache_f( void ); // // cl_parse_gs.c // -void CL_ParseGoldSrcServerMessage( sizebuf_t *msg, qboolean normal_message ); +void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ); // // cl_scrn.c @@ -980,7 +980,7 @@ struct channel_s; struct rawchan_s; qboolean CL_ValidateDeltaPacket( uint oldpacket, frame_t *oldframe ); int CL_UpdateOldEntNum( int oldindex, frame_t *oldframe, entity_state_t **oldent ); -int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ); +int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto ); qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ); void CL_ResetLatchedVars( cl_entity_t *ent, qboolean full_reset ); qboolean CL_GetEntitySpatialization( struct channel_s *ch );