From 547a8620244c9bc107c49d50288c288c33e4088c Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Thu, 29 Jun 2023 04:06:42 +0300 Subject: [PATCH] engine: client: split protocol 48 support to separate file --- engine/client/cl_parse.c | 665 +--------------------------------- engine/client/cl_parse_48.c | 687 ++++++++++++++++++++++++++++++++++++ engine/client/client.h | 34 +- 3 files changed, 719 insertions(+), 667 deletions(-) create mode 100644 engine/client/cl_parse_48.c diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 60ab2d85..b1b304a6 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1240,7 +1240,7 @@ CL_ParseSetAngle set the view angle to this absolute value ================ */ -static void CL_ParseSetAngle( sizebuf_t *msg ) +void CL_ParseSetAngle( sizebuf_t *msg ) { MSG_ReadVec3Angles( msg, cl.viewangles ); } @@ -2491,666 +2491,3 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message ) } } } - -/* -================== -CL_ParseStaticEntity - -static client entity -================== -*/ -void CL_LegacyParseStaticEntity( sizebuf_t *msg ) -{ - int i; - entity_state_t state; - cl_entity_t *ent; - - memset( &state, 0, sizeof( state )); - state.modelindex = MSG_ReadShort( msg ); - state.sequence = MSG_ReadByte( msg ); - state.frame = MSG_ReadByte( msg ); - state.colormap = MSG_ReadWord( msg ); - state.skin = MSG_ReadByte( msg ); - - for( i = 0; i < 3; i++ ) - { - state.origin[i] = MSG_ReadCoord( msg ); - state.angles[i] = MSG_ReadBitAngle( msg, 16 ); - } - - state.rendermode = MSG_ReadByte( msg ); - - if( state.rendermode != kRenderNormal ) - { - state.renderamt = MSG_ReadByte( msg ); - state.rendercolor.r = MSG_ReadByte( msg ); - state.rendercolor.g = MSG_ReadByte( msg ); - state.rendercolor.b = MSG_ReadByte( msg ); - state.renderfx = MSG_ReadByte( msg ); - } - - i = clgame.numStatics; - if( i >= MAX_STATIC_ENTITIES ) - { - Con_Printf( S_ERROR "MAX_STATIC_ENTITIES limit exceeded!\n" ); - return; - } - - ent = &clgame.static_entities[i]; - clgame.numStatics++; - - // all states are same - ent->baseline = ent->curstate = ent->prevstate = state; - ent->index = 0; // static entities doesn't has the numbers - - // statics may be respawned in game e.g. for demo recording - if( cls.state == ca_connected || cls.state == ca_validate ) - ent->trivial_accept = INVALID_HANDLE; - - // setup the new static entity - VectorCopy( ent->curstate.origin, ent->origin ); - VectorCopy( ent->curstate.angles, ent->angles ); - ent->model = CL_ModelHandle( state.modelindex ); - ent->curstate.framerate = 1.0f; - CL_ResetLatchedVars( ent, true ); - - if( ent->curstate.rendermode == kRenderNormal && ent->model != NULL ) - { - // auto 'solid' faces - if( FBitSet( ent->model->flags, MODEL_TRANSPARENT ) && Host_IsQuakeCompatible( )) - { - ent->curstate.rendermode = kRenderTransAlpha; - ent->curstate.renderamt = 255; - } - } - - R_AddEfrags( ent ); // add link -} - -void CL_LegacyParseSoundPacket( sizebuf_t *msg, qboolean is_ambient ) -{ - vec3_t pos; - int chan, sound; - float volume, attn; - int flags, pitch, entnum; - sound_t handle = 0; - - flags = MSG_ReadWord( msg ); - if( flags & SND_LEGACY_LARGE_INDEX ) - { - sound = MSG_ReadWord( msg ); - flags &= ~SND_LEGACY_LARGE_INDEX; - } - else - sound = MSG_ReadByte( msg ); - chan = MSG_ReadByte( msg ); - - if( FBitSet( flags, SND_VOLUME )) - volume = (float)MSG_ReadByte( msg ) / 255.0f; - else volume = VOL_NORM; - - if( FBitSet( flags, SND_ATTENUATION )) - attn = (float)MSG_ReadByte( msg ) / 64.0f; - else attn = ATTN_NONE; - - if( FBitSet( flags, SND_PITCH )) - pitch = MSG_ReadByte( msg ); - else pitch = PITCH_NORM; - - // entity reletive - entnum = MSG_ReadWord( msg ); - - // positioned in space - MSG_ReadVec3Coord( msg, pos ); - - if( FBitSet( flags, SND_SENTENCE )) - { - char sentenceName[32]; - - //if( FBitSet( flags, SND_SEQUENCE )) - //Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound + MAX_SOUNDS ); - //else - Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound ); - - handle = S_RegisterSound( sentenceName ); - } - else handle = cl.sound_index[sound]; // see precached sound - - if( !cl.audio_prepped ) - return; // too early - - // g-cont. sound and ambient sound have only difference with channel - if( is_ambient ) - { - S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags ); - } - else - { - S_StartSound( pos, entnum, chan, handle, volume, attn, pitch, flags ); - } -} -/* -================ -CL_PrecacheSound - -prceache sound from server -================ -*/ -void CL_LegacyPrecacheSound( sizebuf_t *msg ) -{ - int soundIndex; - - soundIndex = MSG_ReadUBitLong( msg, MAX_SOUND_BITS ); - - if( soundIndex < 0 || soundIndex >= MAX_SOUNDS ) - Host_Error( "CL_PrecacheSound: bad soundindex %i\n", soundIndex ); - - Q_strncpy( cl.sound_precache[soundIndex], MSG_ReadString( msg ), sizeof( cl.sound_precache[0] )); - - // when we loading map all resources is precached sequentially - //if( !cl.audio_prepped ) return; - - cl.sound_index[soundIndex] = S_RegisterSound( cl.sound_precache[soundIndex] ); -} - -void CL_LegacyPrecacheModel( sizebuf_t *msg ) -{ - int modelIndex; - string model; - - modelIndex = MSG_ReadUBitLong( msg, MAX_LEGACY_MODEL_BITS ); - - if( modelIndex < 0 || modelIndex >= MAX_MODELS ) - Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex ); - - Q_strncpy( model, MSG_ReadString( msg ), MAX_STRING ); - //Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] )); - - // when we loading map all resources is precached sequentially - //if( !cl.video_prepped ) return; - if( modelIndex == 1 && !cl.worldmodel ) - { - CL_ClearWorld (); - - cl.models[modelIndex] = cl.worldmodel = Mod_LoadWorld( model, true ); - return; - - } - - //Mod_RegisterModel( cl.model_precache[modelIndex], modelIndex ); - - cl.models[modelIndex] = Mod_ForName( model, false, false ); - cl.nummodels = Q_max( cl.nummodels, modelIndex ); -} - -void CL_LegacyPrecacheEvent( sizebuf_t *msg ) -{ - int eventIndex; - - eventIndex = MSG_ReadUBitLong( msg, MAX_EVENT_BITS ); - - if( eventIndex < 0 || eventIndex >= MAX_EVENTS ) - Host_Error( "CL_PrecacheEvent: bad eventindex %i\n", eventIndex ); - - Q_strncpy( cl.event_precache[eventIndex], MSG_ReadString( msg ), sizeof( cl.event_precache[0] )); - - // can be set now - CL_SetEventIndex( cl.event_precache[eventIndex], eventIndex ); -} - -#if XASH_LOW_MEMORY == 0 -#define MAX_LEGACY_RESOURCES 2048 -#elif XASH_LOW_MEMORY == 2 -#define MAX_LEGACY_RESOURCES 1 -#elif XASH_LOW_MEMORY == 1 -#define MAX_LEGACY_RESOURCES 512 -#endif -/* -============== -CL_ParseResourceList - -============== -*/ -void CL_LegacyParseResourceList( sizebuf_t *msg ) -{ - int i = 0; - static struct - { - int rescount; - int restype[MAX_LEGACY_RESOURCES]; - char resnames[MAX_LEGACY_RESOURCES][MAX_QPATH]; - } reslist; - - memset( &reslist, 0, sizeof( reslist )); - reslist.rescount = MSG_ReadWord( msg ) - 1; - - if( reslist.rescount > MAX_LEGACY_RESOURCES ) - Host_Error("MAX_RESOURCES reached\n"); - - for( i = 0; i < reslist.rescount; i++ ) - { - reslist.restype[i] = MSG_ReadWord( msg ); - Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), MAX_QPATH ); - } - - if( CL_IsPlaybackDemo() ) - { - return; - } - - HTTP_ResetProcessState(); - - host.downloadcount = 0; - - for( i = 0; i < reslist.rescount; i++ ) - { - char soundpath[MAX_VA_STRING]; - const char *path; - - if( reslist.restype[i] == t_sound ) - { - Q_snprintf( soundpath, sizeof( soundpath ), DEFAULT_SOUNDPATH "%s", reslist.resnames[i] ); - - path = soundpath; - } - else path = reslist.resnames[i]; - - if( FS_FileExists( path, false )) - continue; // already exists - - host.downloadcount++; - HTTP_AddDownload( path, -1, true ); - } - - if( !host.downloadcount ) - { - MSG_WriteByte( &cls.netchan.message, clc_stringcmd ); - MSG_WriteString( &cls.netchan.message, "continueloading" ); - } -} - -/* -===================== -CL_ParseLegacyServerMessage - -dispatch messages -===================== -*/ -void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message ) -{ - size_t bufStart, playerbytes; - int cmd, param1, param2; - int old_background; - 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 ) - { - if( MSG_CheckOverflow( msg )) - { - Host_Error( "CL_ParseServerMessage: overflow!\n" ); - return; - } - - // mark start position - bufStart = MSG_GetNumBytesRead( msg ); - - // end of message (align bits) - if( MSG_GetNumBitsLeft( msg ) < 8 ) - break; - - cmd = MSG_ReadServerCmd( msg ); - - // record command for debugging spew on parse problem - CL_Parse_RecordCommand( cmd, bufStart ); - - // other commands - switch( cmd ) - { - case svc_bad: - Host_Error( "svc_bad\n" ); - break; - case svc_nop: - // this does nothing - break; - case svc_disconnect: - CL_Drop (); - Host_AbortCurrentFrame (); - break; - case svc_legacy_event: - CL_ParseEvent( msg ); - cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_legacy_changing: - old_background = cl.background; - if( MSG_ReadOneBit( msg )) - { - cls.changelevel = true; - S_StopAllSounds( true ); - - Con_Printf( "Server changing, reconnecting\n" ); - - if( cls.demoplayback ) - { - SCR_BeginLoadingPlaque( cl.background ); - cls.changedemo = true; - } - - CL_ClearState (); - CL_InitEdicts (); // re-arrange edicts - } - else Con_Printf( "Server disconnected, reconnecting\n" ); - - if( cls.demoplayback ) - { - cl.background = (cls.demonum != -1) ? true : false; - cls.state = ca_connected; - } - else - { - // g-cont. local client skip the challenge - if( SV_Active( )) - cls.state = ca_disconnected; - else cls.state = ca_connecting; - cl.background = old_background; - cls.connect_time = MAX_HEARTBEAT; - cls.connect_retry = 0; - } - break; - case svc_setview: - CL_ParseViewEntity( msg ); - break; - case svc_sound: - CL_LegacyParseSoundPacket( msg, false ); - cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_legacy_ambientsound: - CL_LegacyParseSoundPacket( msg, true ); - cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; - - break; - case svc_time: - CL_ParseServerTime( msg ); - break; - case svc_print: - Con_Printf( "%s", MSG_ReadString( msg )); - break; - case svc_stufftext: - s = MSG_ReadString( msg ); -#ifdef HACKS_RELATED_HLMODS - // disable Cry Of Fear antisave protection - if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) - break; // too early -#endif - - Con_Reportf( "Stufftext: %s", s ); - Cbuf_AddFilteredText( s ); - break; - case svc_setangle: - CL_ParseSetAngle( msg ); - break; - case svc_serverdata: - Cbuf_Execute(); // make sure any stuffed commands are done - CL_ParseServerData( msg, true ); - break; - case svc_lightstyle: - CL_ParseLightStyle( msg ); - break; - case svc_updateuserinfo: - CL_UpdateUserinfo( msg, true ); - break; - case svc_deltatable: - Delta_ParseTableField( msg ); - break; - case svc_clientdata: - CL_ParseClientData( msg ); - cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_resource: - CL_ParseResource( msg ); - break; - case svc_pings: - CL_UpdateUserPings( msg ); - break; - case svc_particle: - CL_ParseParticles( msg ); - break; - case svc_restoresound: - CL_ParseRestoreSoundPacket( msg ); - cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_spawnstatic: - CL_LegacyParseStaticEntity( msg ); - break; - case svc_event_reliable: - CL_ParseReliableEvent( msg ); - cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_spawnbaseline: - CL_ParseBaseline( msg, true ); - break; - case svc_temp_entity: - CL_ParseTempEntity( msg ); - cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_setpause: - cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); - break; - case svc_signonnum: - CL_ParseSignon( msg ); - break; - case svc_centerprint: - CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); - break; - case svc_intermission: - cl.intermission = 1; - break; - case svc_legacy_modelindex: - CL_LegacyPrecacheModel( msg ); - break; - case svc_legacy_soundindex: - CL_LegacyPrecacheSound( msg ); - break; - case svc_cdtrack: - param1 = MSG_ReadByte( msg ); - param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum - param2 = MSG_ReadByte( msg ); - param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum - S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0, false ); - break; - case svc_restore: - CL_ParseRestore( msg ); - break; - case svc_legacy_eventindex: - CL_LegacyPrecacheEvent(msg); - break; - case svc_weaponanim: - param1 = MSG_ReadByte( msg ); // iAnim - param2 = MSG_ReadByte( msg ); // body - CL_WeaponAnim( param1, param2 ); - break; - case svc_bspdecal: - CL_ParseStaticDecal( msg ); - break; - case svc_roomtype: - param1 = MSG_ReadShort( msg ); - Cvar_SetValue( "room_type", param1 ); - break; - case svc_addangle: - CL_ParseAddAngle( msg ); - break; - case svc_usermessage: - CL_RegisterUserMessage( msg ); - break; - case svc_packetentities: - playerbytes = CL_ParsePacketEntities( msg, false ); - 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 ); - cl.frames[cl.parsecountmod].graphdata.players += playerbytes; - cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; - break; - case svc_legacy_chokecount: - { - int i, j; - i = MSG_ReadByte( msg ); - j = cls.netchan.incoming_acknowledged - 1; - for( ; i > 0 && j > cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP; j-- ) - { - if( cl.frames[j & CL_UPDATE_MASK].receivedtime != -3.0 ) - { - cl.frames[j & CL_UPDATE_MASK].choked = true; - cl.frames[j & CL_UPDATE_MASK].receivedtime = -2.0; - i--; - } - } - break; - } - //cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true; - //cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0; - break; - case svc_resourcelist: - CL_LegacyParseResourceList( msg ); - break; - case svc_deltamovevars: - CL_ParseMovevars( msg ); - break; - case svc_resourcerequest: - CL_ParseResourceRequest( msg ); - break; - case svc_customization: - CL_ParseCustomization( msg ); - break; - case svc_crosshairangle: - CL_ParseCrosshairAngle( msg ); - break; - case svc_soundfade: - CL_ParseSoundFade( msg ); - break; - case svc_filetxferfailed: - CL_ParseFileTransferFailed( msg ); - break; - case svc_hltv: - CL_ParseHLTV( msg ); - break; - case svc_director: - CL_ParseDirector( msg ); - break; - case svc_resourcelocation: - CL_ParseResLocation( msg ); - break; - case svc_querycvarvalue: - CL_ParseCvarValue( msg, false ); - break; - case svc_querycvarvalue2: - CL_ParseCvarValue( msg, true ); - break; - default: - CL_ParseUserMessage( msg, cmd ); - cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart; - 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 ); - } - } -} - -void CL_LegacyPrecache_f( void ) -{ - int spawncount, i; - model_t *mod; - - if( !cls.legacymode ) - return; - - spawncount = Q_atoi( Cmd_Argv( 1 )); - - Con_Printf( "Setting up renderer...\n" ); - - // load tempent sprites (glowshell, muzzleflashes etc) - CL_LoadClientSprites (); - - // invalidate all decal indexes - memset( cl.decal_index, 0, sizeof( cl.decal_index )); - cl.video_prepped = true; - cl.audio_prepped = true; - if( clgame.entities ) - clgame.entities->model = cl.worldmodel; - - // update the ref state. - R_UpdateRefState (); - - // tell rendering system we have a new set of models. - ref.dllFuncs.R_NewMap (); - - CL_SetupOverviewParams(); - - // release unused SpriteTextures - for( i = 1, mod = clgame.sprites; i < MAX_CLIENT_SPRITES; i++, mod++ ) - { - if( mod->needload == NL_UNREFERENCED && COM_CheckString( mod->name )) - Mod_FreeModel( mod ); - } - -// Mod_FreeUnused (); - - if( host_developer.value <= DEV_NONE ) - Con_ClearNotify(); // clear any lines of console text - - // done with all resources, issue prespawn command. - // Include server count in case server disconnects and changes level during d/l - MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd ); - MSG_WriteStringf( &cls.netchan.message, "begin %i", spawncount ); - cls.signon = SIGNONS; -} - -void CL_LegacyUpdateInfo( void ) -{ - if( !cls.legacymode ) - return; - - if( cls.state != ca_active ) - return; - - MSG_BeginClientCmd( &cls.netchan.message, clc_legacy_userinfo ); - MSG_WriteString( &cls.netchan.message, cls.userinfo ); -} - -qboolean CL_LegacyMode( void ) -{ - return cls.legacymode; -} diff --git a/engine/client/cl_parse_48.c b/engine/client/cl_parse_48.c new file mode 100644 index 00000000..8994312d --- /dev/null +++ b/engine/client/cl_parse_48.c @@ -0,0 +1,687 @@ +/* +cl_parse.c - parse a message received from the server +Copyright (C) 2008 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "common.h" +#include "client.h" +#include "net_encode.h" +#include "particledef.h" +#include "cl_tent.h" +#include "shake.h" +#include "hltv.h" +#include "input.h" + + +/* +================== +CL_ParseStaticEntity + +static client entity +================== +*/ +void CL_LegacyParseStaticEntity( sizebuf_t *msg ) +{ + int i; + entity_state_t state; + cl_entity_t *ent; + + memset( &state, 0, sizeof( state )); + state.modelindex = MSG_ReadShort( msg ); + state.sequence = MSG_ReadByte( msg ); + state.frame = MSG_ReadByte( msg ); + state.colormap = MSG_ReadWord( msg ); + state.skin = MSG_ReadByte( msg ); + + for( i = 0; i < 3; i++ ) + { + state.origin[i] = MSG_ReadCoord( msg ); + state.angles[i] = MSG_ReadBitAngle( msg, 16 ); + } + + state.rendermode = MSG_ReadByte( msg ); + + if( state.rendermode != kRenderNormal ) + { + state.renderamt = MSG_ReadByte( msg ); + state.rendercolor.r = MSG_ReadByte( msg ); + state.rendercolor.g = MSG_ReadByte( msg ); + state.rendercolor.b = MSG_ReadByte( msg ); + state.renderfx = MSG_ReadByte( msg ); + } + + i = clgame.numStatics; + if( i >= MAX_STATIC_ENTITIES ) + { + Con_Printf( S_ERROR "MAX_STATIC_ENTITIES limit exceeded!\n" ); + return; + } + + ent = &clgame.static_entities[i]; + clgame.numStatics++; + + // all states are same + ent->baseline = ent->curstate = ent->prevstate = state; + ent->index = 0; // static entities doesn't has the numbers + + // statics may be respawned in game e.g. for demo recording + if( cls.state == ca_connected || cls.state == ca_validate ) + ent->trivial_accept = INVALID_HANDLE; + + // setup the new static entity + VectorCopy( ent->curstate.origin, ent->origin ); + VectorCopy( ent->curstate.angles, ent->angles ); + ent->model = CL_ModelHandle( state.modelindex ); + ent->curstate.framerate = 1.0f; + CL_ResetLatchedVars( ent, true ); + + if( ent->curstate.rendermode == kRenderNormal && ent->model != NULL ) + { + // auto 'solid' faces + if( FBitSet( ent->model->flags, MODEL_TRANSPARENT ) && Host_IsQuakeCompatible( )) + { + ent->curstate.rendermode = kRenderTransAlpha; + ent->curstate.renderamt = 255; + } + } + + R_AddEfrags( ent ); // add link +} + +void CL_LegacyParseSoundPacket( sizebuf_t *msg, qboolean is_ambient ) +{ + vec3_t pos; + int chan, sound; + float volume, attn; + int flags, pitch, entnum; + sound_t handle = 0; + + flags = MSG_ReadWord( msg ); + if( flags & SND_LEGACY_LARGE_INDEX ) + { + sound = MSG_ReadWord( msg ); + flags &= ~SND_LEGACY_LARGE_INDEX; + } + else + sound = MSG_ReadByte( msg ); + chan = MSG_ReadByte( msg ); + + if( FBitSet( flags, SND_VOLUME )) + volume = (float)MSG_ReadByte( msg ) / 255.0f; + else volume = VOL_NORM; + + if( FBitSet( flags, SND_ATTENUATION )) + attn = (float)MSG_ReadByte( msg ) / 64.0f; + else attn = ATTN_NONE; + + if( FBitSet( flags, SND_PITCH )) + pitch = MSG_ReadByte( msg ); + else pitch = PITCH_NORM; + + // entity reletive + entnum = MSG_ReadWord( msg ); + + // positioned in space + MSG_ReadVec3Coord( msg, pos ); + + if( FBitSet( flags, SND_SENTENCE )) + { + char sentenceName[32]; + + //if( FBitSet( flags, SND_SEQUENCE )) + //Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound + MAX_SOUNDS ); + //else + Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound ); + + handle = S_RegisterSound( sentenceName ); + } + else handle = cl.sound_index[sound]; // see precached sound + + if( !cl.audio_prepped ) + return; // too early + + // g-cont. sound and ambient sound have only difference with channel + if( is_ambient ) + { + S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags ); + } + else + { + S_StartSound( pos, entnum, chan, handle, volume, attn, pitch, flags ); + } +} +/* +================ +CL_PrecacheSound + +prceache sound from server +================ +*/ +void CL_LegacyPrecacheSound( sizebuf_t *msg ) +{ + int soundIndex; + + soundIndex = MSG_ReadUBitLong( msg, MAX_SOUND_BITS ); + + if( soundIndex < 0 || soundIndex >= MAX_SOUNDS ) + Host_Error( "CL_PrecacheSound: bad soundindex %i\n", soundIndex ); + + Q_strncpy( cl.sound_precache[soundIndex], MSG_ReadString( msg ), sizeof( cl.sound_precache[0] )); + + // when we loading map all resources is precached sequentially + //if( !cl.audio_prepped ) return; + + cl.sound_index[soundIndex] = S_RegisterSound( cl.sound_precache[soundIndex] ); +} + +void CL_LegacyPrecacheModel( sizebuf_t *msg ) +{ + int modelIndex; + string model; + + modelIndex = MSG_ReadUBitLong( msg, MAX_LEGACY_MODEL_BITS ); + + if( modelIndex < 0 || modelIndex >= MAX_MODELS ) + Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex ); + + Q_strncpy( model, MSG_ReadString( msg ), MAX_STRING ); + //Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] )); + + // when we loading map all resources is precached sequentially + //if( !cl.video_prepped ) return; + if( modelIndex == 1 && !cl.worldmodel ) + { + CL_ClearWorld (); + + cl.models[modelIndex] = cl.worldmodel = Mod_LoadWorld( model, true ); + return; + + } + + //Mod_RegisterModel( cl.model_precache[modelIndex], modelIndex ); + + cl.models[modelIndex] = Mod_ForName( model, false, false ); + cl.nummodels = Q_max( cl.nummodels, modelIndex ); +} + +void CL_LegacyPrecacheEvent( sizebuf_t *msg ) +{ + int eventIndex; + + eventIndex = MSG_ReadUBitLong( msg, MAX_EVENT_BITS ); + + if( eventIndex < 0 || eventIndex >= MAX_EVENTS ) + Host_Error( "CL_PrecacheEvent: bad eventindex %i\n", eventIndex ); + + Q_strncpy( cl.event_precache[eventIndex], MSG_ReadString( msg ), sizeof( cl.event_precache[0] )); + + // can be set now + CL_SetEventIndex( cl.event_precache[eventIndex], eventIndex ); +} + +#if XASH_LOW_MEMORY == 0 +#define MAX_LEGACY_RESOURCES 2048 +#elif XASH_LOW_MEMORY == 2 +#define MAX_LEGACY_RESOURCES 1 +#elif XASH_LOW_MEMORY == 1 +#define MAX_LEGACY_RESOURCES 512 +#endif +/* +============== +CL_ParseResourceList + +============== +*/ +void CL_LegacyParseResourceList( sizebuf_t *msg ) +{ + int i = 0; + static struct + { + int rescount; + int restype[MAX_LEGACY_RESOURCES]; + char resnames[MAX_LEGACY_RESOURCES][MAX_QPATH]; + } reslist; + + memset( &reslist, 0, sizeof( reslist )); + reslist.rescount = MSG_ReadWord( msg ) - 1; + + if( reslist.rescount > MAX_LEGACY_RESOURCES ) + Host_Error("MAX_RESOURCES reached\n"); + + for( i = 0; i < reslist.rescount; i++ ) + { + reslist.restype[i] = MSG_ReadWord( msg ); + Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), MAX_QPATH ); + } + + if( CL_IsPlaybackDemo() ) + { + return; + } + + HTTP_ResetProcessState(); + + host.downloadcount = 0; + + for( i = 0; i < reslist.rescount; i++ ) + { + char soundpath[MAX_VA_STRING]; + const char *path; + + if( reslist.restype[i] == t_sound ) + { + Q_snprintf( soundpath, sizeof( soundpath ), DEFAULT_SOUNDPATH "%s", reslist.resnames[i] ); + + path = soundpath; + } + else path = reslist.resnames[i]; + + if( FS_FileExists( path, false )) + continue; // already exists + + host.downloadcount++; + HTTP_AddDownload( path, -1, true ); + } + + if( !host.downloadcount ) + { + MSG_WriteByte( &cls.netchan.message, clc_stringcmd ); + MSG_WriteString( &cls.netchan.message, "continueloading" ); + } +} + +/* +===================== +CL_ParseLegacyServerMessage + +dispatch messages +===================== +*/ +void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message ) +{ + size_t bufStart, playerbytes; + int cmd, param1, param2; + int old_background; + 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 ) + { + if( MSG_CheckOverflow( msg )) + { + Host_Error( "CL_ParseServerMessage: overflow!\n" ); + return; + } + + // mark start position + bufStart = MSG_GetNumBytesRead( msg ); + + // end of message (align bits) + if( MSG_GetNumBitsLeft( msg ) < 8 ) + break; + + cmd = MSG_ReadServerCmd( msg ); + + // record command for debugging spew on parse problem + CL_Parse_RecordCommand( cmd, bufStart ); + + // other commands + switch( cmd ) + { + case svc_bad: + Host_Error( "svc_bad\n" ); + break; + case svc_nop: + // this does nothing + break; + case svc_disconnect: + CL_Drop (); + Host_AbortCurrentFrame (); + break; + case svc_legacy_event: + CL_ParseEvent( msg ); + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_legacy_changing: + old_background = cl.background; + if( MSG_ReadOneBit( msg )) + { + cls.changelevel = true; + S_StopAllSounds( true ); + + Con_Printf( "Server changing, reconnecting\n" ); + + if( cls.demoplayback ) + { + SCR_BeginLoadingPlaque( cl.background ); + cls.changedemo = true; + } + + CL_ClearState (); + CL_InitEdicts (); // re-arrange edicts + } + else Con_Printf( "Server disconnected, reconnecting\n" ); + + if( cls.demoplayback ) + { + cl.background = (cls.demonum != -1) ? true : false; + cls.state = ca_connected; + } + else + { + // g-cont. local client skip the challenge + if( SV_Active( )) + cls.state = ca_disconnected; + else cls.state = ca_connecting; + cl.background = old_background; + cls.connect_time = MAX_HEARTBEAT; + cls.connect_retry = 0; + } + break; + case svc_setview: + CL_ParseViewEntity( msg ); + break; + case svc_sound: + CL_LegacyParseSoundPacket( msg, false ); + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_legacy_ambientsound: + CL_LegacyParseSoundPacket( msg, true ); + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; + + break; + case svc_time: + CL_ParseServerTime( msg ); + break; + case svc_print: + Con_Printf( "%s", MSG_ReadString( msg )); + break; + case svc_stufftext: + s = MSG_ReadString( msg ); +#ifdef HACKS_RELATED_HLMODS + // disable Cry Of Fear antisave protection + if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) + break; // too early +#endif + + Con_Reportf( "Stufftext: %s", s ); + Cbuf_AddFilteredText( s ); + break; + case svc_setangle: + CL_ParseSetAngle( msg ); + break; + case svc_serverdata: + Cbuf_Execute(); // make sure any stuffed commands are done + CL_ParseServerData( msg, true ); + break; + case svc_lightstyle: + CL_ParseLightStyle( msg ); + break; + case svc_updateuserinfo: + CL_UpdateUserinfo( msg, true ); + break; + case svc_deltatable: + Delta_ParseTableField( msg ); + break; + case svc_clientdata: + CL_ParseClientData( msg ); + cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_resource: + CL_ParseResource( msg ); + break; + case svc_pings: + CL_UpdateUserPings( msg ); + break; + case svc_particle: + CL_ParseParticles( msg ); + break; + case svc_restoresound: + CL_ParseRestoreSoundPacket( msg ); + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_spawnstatic: + CL_LegacyParseStaticEntity( msg ); + break; + case svc_event_reliable: + CL_ParseReliableEvent( msg ); + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_spawnbaseline: + CL_ParseBaseline( msg, true ); + break; + case svc_temp_entity: + CL_ParseTempEntity( msg ); + cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart; + break; + case svc_setpause: + cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); + break; + case svc_signonnum: + CL_ParseSignon( msg ); + break; + case svc_centerprint: + CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); + break; + case svc_intermission: + cl.intermission = 1; + break; + case svc_legacy_modelindex: + CL_LegacyPrecacheModel( msg ); + break; + case svc_legacy_soundindex: + CL_LegacyPrecacheSound( msg ); + break; + case svc_cdtrack: + param1 = MSG_ReadByte( msg ); + param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum + param2 = MSG_ReadByte( msg ); + param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum + S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0, false ); + break; + case svc_restore: + CL_ParseRestore( msg ); + break; + case svc_legacy_eventindex: + CL_LegacyPrecacheEvent(msg); + break; + case svc_weaponanim: + param1 = MSG_ReadByte( msg ); // iAnim + param2 = MSG_ReadByte( msg ); // body + CL_WeaponAnim( param1, param2 ); + break; + case svc_bspdecal: + CL_ParseStaticDecal( msg ); + break; + case svc_roomtype: + param1 = MSG_ReadShort( msg ); + Cvar_SetValue( "room_type", param1 ); + break; + case svc_addangle: + CL_ParseAddAngle( msg ); + break; + case svc_usermessage: + CL_RegisterUserMessage( msg ); + break; + case svc_packetentities: + playerbytes = CL_ParsePacketEntities( msg, false ); + 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 ); + cl.frames[cl.parsecountmod].graphdata.players += playerbytes; + cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; + break; + case svc_legacy_chokecount: + { + int i, j; + i = MSG_ReadByte( msg ); + j = cls.netchan.incoming_acknowledged - 1; + for( ; i > 0 && j > cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP; j-- ) + { + if( cl.frames[j & CL_UPDATE_MASK].receivedtime != -3.0 ) + { + cl.frames[j & CL_UPDATE_MASK].choked = true; + cl.frames[j & CL_UPDATE_MASK].receivedtime = -2.0; + i--; + } + } + break; + } + //cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true; + //cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0; + break; + case svc_resourcelist: + CL_LegacyParseResourceList( msg ); + break; + case svc_deltamovevars: + CL_ParseMovevars( msg ); + break; + case svc_resourcerequest: + CL_ParseResourceRequest( msg ); + break; + case svc_customization: + CL_ParseCustomization( msg ); + break; + case svc_crosshairangle: + CL_ParseCrosshairAngle( msg ); + break; + case svc_soundfade: + CL_ParseSoundFade( msg ); + break; + case svc_filetxferfailed: + CL_ParseFileTransferFailed( msg ); + break; + case svc_hltv: + CL_ParseHLTV( msg ); + break; + case svc_director: + CL_ParseDirector( msg ); + break; + case svc_resourcelocation: + CL_ParseResLocation( msg ); + break; + case svc_querycvarvalue: + CL_ParseCvarValue( msg, false ); + break; + case svc_querycvarvalue2: + CL_ParseCvarValue( msg, true ); + break; + default: + CL_ParseUserMessage( msg, cmd ); + cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart; + 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 ); + } + } +} + +void CL_LegacyPrecache_f( void ) +{ + int spawncount, i; + model_t *mod; + + if( !cls.legacymode ) + return; + + spawncount = Q_atoi( Cmd_Argv( 1 )); + + Con_Printf( "Setting up renderer...\n" ); + + // load tempent sprites (glowshell, muzzleflashes etc) + CL_LoadClientSprites (); + + // invalidate all decal indexes + memset( cl.decal_index, 0, sizeof( cl.decal_index )); + cl.video_prepped = true; + cl.audio_prepped = true; + if( clgame.entities ) + clgame.entities->model = cl.worldmodel; + + // update the ref state. + R_UpdateRefState (); + + // tell rendering system we have a new set of models. + ref.dllFuncs.R_NewMap (); + + CL_SetupOverviewParams(); + + // release unused SpriteTextures + for( i = 1, mod = clgame.sprites; i < MAX_CLIENT_SPRITES; i++, mod++ ) + { + if( mod->needload == NL_UNREFERENCED && COM_CheckString( mod->name )) + Mod_FreeModel( mod ); + } + +// Mod_FreeUnused (); + + if( host_developer.value <= DEV_NONE ) + Con_ClearNotify(); // clear any lines of console text + + // done with all resources, issue prespawn command. + // Include server count in case server disconnects and changes level during d/l + MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd ); + MSG_WriteStringf( &cls.netchan.message, "begin %i", spawncount ); + cls.signon = SIGNONS; +} + +void CL_LegacyUpdateInfo( void ) +{ + if( !cls.legacymode ) + return; + + if( cls.state != ca_active ) + return; + + MSG_BeginClientCmd( &cls.netchan.message, clc_legacy_userinfo ); + MSG_WriteString( &cls.netchan.message, cls.userinfo ); +} + +qboolean CL_LegacyMode( void ) +{ + return cls.legacymode; +} diff --git a/engine/client/client.h b/engine/client/client.h index c55cbff4..4ed56871 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -878,10 +878,32 @@ _inline cl_entity_t *CL_EDICT_NUM( int n ) // // cl_parse.c // +void CL_ParseSetAngle( sizebuf_t *msg ); +void CL_ParseServerData( sizebuf_t *msg, qboolean legacy ); +void CL_ParseLightStyle( sizebuf_t *msg ); +void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy ); +void CL_ParseResource( sizebuf_t *msg ); +void CL_ParseClientData( sizebuf_t *msg ); +void CL_UpdateUserPings( sizebuf_t *msg ); +void CL_ParseParticles( sizebuf_t *msg ); +void CL_ParseRestoreSoundPacket( sizebuf_t *msg ); +void CL_ParseBaseline( sizebuf_t *msg, qboolean legacy ); +void CL_ParseSignon( sizebuf_t *msg ); +void CL_ParseRestore( sizebuf_t *msg ); +void CL_ParseStaticDecal( sizebuf_t *msg ); +void CL_ParseAddAngle( sizebuf_t *msg ); +void CL_RegisterUserMessage( sizebuf_t *msg ); +void CL_ParseMovevars( sizebuf_t *msg ); +void CL_ParseResourceRequest( sizebuf_t *msg ); +void CL_ParseCustomization( sizebuf_t *msg ); +void CL_ParseCrosshairAngle( sizebuf_t *msg ); +void CL_ParseSoundFade( sizebuf_t *msg ); +void CL_ParseFileTransferFailed( sizebuf_t *msg ); +void CL_ParseHLTV( sizebuf_t *msg ); +void CL_ParseDirector( sizebuf_t *msg ); +void CL_ParseResLocation( sizebuf_t *msg ); +void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext ); void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message ); -void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message ); -void CL_LegacyPrecache_f( void ); - void CL_ParseTempEntity( sizebuf_t *msg ); qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf ); qboolean CL_RequestMissingResources( void ); @@ -889,6 +911,12 @@ void CL_RegisterResources ( sizebuf_t *msg ); void CL_ParseViewEntity( sizebuf_t *msg ); void CL_ParseServerTime( sizebuf_t *msg ); +// +// cl_parse_48.c +// +void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message ); +void CL_LegacyPrecache_f( void ); + // // cl_scrn.c //