/* ================== CL_ParseParticles ================== */ void CL_ParseParticles( sizebuf_t *msg ) { vec3_t org, dir; int i, count, color; float life; BF_ReadVec3Coord( msg, org ); for( i = 0; i < 3; i++ ) dir[i] = BF_ReadChar( msg ) * (1.0f / 16); count = BF_ReadByte( msg ); color = BF_ReadByte( msg ); if( count == 255 ) count = 1024; life = BF_ReadByte( msg ) * 0.125f; if( life != 0.0f && count == 1 ) { particle_t *p; p = CL_AllocParticle( NULL ); if( !p ) return; p->die += life; p->color = color; p->type = pt_static; VectorCopy( org, p->org ); VectorCopy( dir, p->vel ); } else CL_RunParticleEffect( org, dir, color, count ); }
/* ================== CL_ParseSoundPacket ================== */ void CL_ParseSoundPacket( sizebuf_t *msg, qboolean is_ambient ) { vec3_t pos; int chan, sound; float volume, attn; int flags, pitch, entnum; sound_t handle = 0; flags = BF_ReadWord( msg ); if( flags & SND_LARGE_INDEX ) sound = BF_ReadWord( msg ); else sound = BF_ReadByte( msg ); chan = BF_ReadByte( msg ); if( flags & SND_VOLUME ) volume = (float)BF_ReadByte( msg ) / 255.0f; else volume = VOL_NORM; if( flags & SND_ATTENUATION ) attn = (float)BF_ReadByte( msg ) / 64.0f; else attn = ATTN_NONE; if( flags & SND_PITCH ) pitch = BF_ReadByte( msg ); else pitch = PITCH_NORM; // entity reletive entnum = BF_ReadWord( msg ); // positioned in space BF_ReadVec3Coord( msg, pos ); if( flags & SND_SENTENCE ) { char sentenceName[32]; 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 if( is_ambient ) { S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags ); } else { S_StartSound( pos, entnum, chan, handle, volume, attn, pitch, flags ); } }
/* ================== CL_ParseSoundFade ================== */ void CL_ParseSoundFade( sizebuf_t *msg ) { float fadePercent, fadeOutSeconds; float holdTime, fadeInSeconds; fadePercent = (float)BF_ReadByte( msg ); holdTime = (float)BF_ReadByte( msg ); fadeOutSeconds = (float)BF_ReadByte( msg ); fadeInSeconds = (float)BF_ReadByte( msg ); S_FadeClientVolume( fadePercent, fadeOutSeconds, holdTime, fadeInSeconds ); }
/* ================ CL_RegisterUserMessage register new user message or update existing ================ */ void CL_RegisterUserMessage( sizebuf_t *msg ) { char *pszName; int svc_num, size; svc_num = BF_ReadByte( msg ); size = BF_ReadByte( msg ); pszName = BF_ReadString( msg ); // important stuff if( size == 0xFF ) size = -1; svc_num = bound( 0, svc_num, 255 ); CL_LinkUserMessage( pszName, svc_num, size ); }
/* ============== CL_ParseDirector spectator message (hltv) ============== */ void CL_ParseDirector( sizebuf_t *msg ) { byte pbuf[256]; int iSize = BF_ReadByte( msg ); // parse user message into buffer BF_ReadBytes( msg, pbuf, iSize ); clgame.dllFuncs.pfnDirectorMessage( iSize, pbuf ); }
/* ================ CL_ParseLightStyle ================ */ void CL_ParseLightStyle( sizebuf_t *msg ) { int style; const char *s; style = BF_ReadByte( msg ); s = BF_ReadString( msg ); CL_SetLightstyle( style, s ); }
/* ============== CL_ParseScreenFade Set screen fade ============== */ void CL_ParseScreenFade( sizebuf_t *msg ) { float duration, holdTime; screenfade_t *sf = &clgame.fade; duration = (float)(word)BF_ReadShort( msg ) * (1.0f / (float)(1U << 12)); holdTime = (float)(word)BF_ReadShort( msg ) * (1.0f / (float)(1U << 12)); sf->fadeFlags = BF_ReadShort( msg ); sf->fader = BF_ReadByte( msg ); sf->fadeg = BF_ReadByte( msg ); sf->fadeb = BF_ReadByte( msg ); sf->fadealpha = BF_ReadByte( msg ); sf->fadeSpeed = 0.0f; sf->fadeEnd = duration; sf->fadeReset = holdTime; // calc fade speed if( duration > 0 ) { if( sf->fadeFlags & FFADE_OUT ) { if( sf->fadeEnd ) { sf->fadeSpeed = -(float)sf->fadealpha / sf->fadeEnd; } sf->fadeEnd += cl.time; sf->fadeReset += sf->fadeEnd; } else { if( sf->fadeEnd ) { sf->fadeSpeed = (float)sf->fadealpha / sf->fadeEnd; } sf->fadeReset += cl.time; sf->fadeEnd += sf->fadeReset; } } }
/* ================== CL_ParseStaticDecal ================== */ void CL_ParseStaticDecal( sizebuf_t *msg ) { vec3_t origin; int decalIndex, entityIndex, modelIndex; int flags; BF_ReadBitVec3Coord( msg, origin ); decalIndex = BF_ReadWord( msg ); entityIndex = BF_ReadShort( msg ); if( entityIndex > 0 ) modelIndex = BF_ReadWord( msg ); else modelIndex = 0; flags = BF_ReadByte( msg ); CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags ); }
/* ============== CL_ParseStudioDecal Studio Decal message. Used by engine in case we need save\restore decals ============== */ void CL_ParseStudioDecal( sizebuf_t *msg ) { modelstate_t state; vec3_t start, pos; int decalIndex, entityIndex; int modelIndex = 0; int flags; BF_ReadVec3Coord( msg, pos ); BF_ReadVec3Coord( msg, start ); decalIndex = BF_ReadWord( msg ); entityIndex = BF_ReadWord( msg ); flags = BF_ReadByte( msg ); state.sequence = BF_ReadShort( msg ); state.frame = BF_ReadShort( msg ); state.blending[0] = BF_ReadByte( msg ); state.blending[1] = BF_ReadByte( msg ); state.controller[0] = BF_ReadByte( msg ); state.controller[1] = BF_ReadByte( msg ); state.controller[2] = BF_ReadByte( msg ); state.controller[3] = BF_ReadByte( msg ); modelIndex = BF_ReadWord( msg ); state.body = BF_ReadByte( msg ); state.skin = BF_ReadByte( msg ); if( clgame.drawFuncs.R_StudioDecalShoot != NULL ) { int decalTexture = CL_DecalIndex( decalIndex ); cl_entity_t *ent = CL_GetEntityByIndex( entityIndex ); if( ent && !ent->model && modelIndex != 0 ) ent->model = Mod_Handle( modelIndex ); clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state ); } }
/* ============== CL_ParseStudioDecal Studio Decal message. Used by engine in case we need save\restore decals ============== */ void CL_ParseStudioDecal( sizebuf_t *msg ) { modelstate_t state; vec3_t start, pos; int decalIndex, entityIndex; int modelIndex = 0; int flags; pos[0] = BF_ReadCoord( msg ); pos[1] = BF_ReadCoord( msg ); pos[2] = BF_ReadCoord( msg ); start[0] = BF_ReadCoord( msg ); start[1] = BF_ReadCoord( msg ); start[2] = BF_ReadCoord( msg ); decalIndex = BF_ReadShort( msg ); entityIndex = BF_ReadShort( msg ); flags = BF_ReadByte( msg ); state.sequence = BF_ReadShort( msg ); state.frame = BF_ReadShort( msg ); state.blending[0] = BF_ReadByte( msg ); state.blending[1] = BF_ReadByte( msg ); state.controller[0] = BF_ReadByte( msg ); state.controller[1] = BF_ReadByte( msg ); state.controller[2] = BF_ReadByte( msg ); state.controller[3] = BF_ReadByte( msg ); if( cls.state == ca_connected ) { // this message came on restore. // read modelindex in case client models are not linked with entities // because first client frame has not yet received modelIndex = BF_ReadShort( msg ); } if( clgame.drawFuncs.R_StudioDecalShoot ) { int decalTexture = CL_DecalIndex( decalIndex ); cl_entity_t *ent = CL_GetEntityByIndex( entityIndex ); if( ent && !ent->model && modelIndex != 0 ) ent->model = Mod_Handle( modelIndex ); clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state ); } }
/* ================== CL_ParseRestoreSoundPacket ================== */ void CL_ParseRestoreSoundPacket( sizebuf_t *msg ) { vec3_t pos; int chan, sound; float volume, attn; int flags, pitch, entnum; double samplePos, forcedEnd; int wordIndex; sound_t handle = 0; flags = BF_ReadWord( msg ); if( flags & SND_LARGE_INDEX ) sound = BF_ReadWord( msg ); else sound = BF_ReadByte( msg ); chan = BF_ReadByte( msg ); if( flags & SND_VOLUME ) volume = (float)BF_ReadByte( msg ) / 255.0f; else volume = VOL_NORM; if( flags & SND_ATTENUATION ) attn = (float)BF_ReadByte( msg ) / 64.0f; else attn = ATTN_NONE; if( flags & SND_PITCH ) pitch = BF_ReadByte( msg ); else pitch = PITCH_NORM; if( flags & SND_SENTENCE ) { char sentenceName[32]; Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound ); handle = S_RegisterSound( sentenceName ); } else handle = cl.sound_index[sound]; // see precached sound // entity reletive entnum = BF_ReadWord( msg ); // positioned in space BF_ReadVec3Coord( msg, pos ); wordIndex = BF_ReadByte( msg ); // 16 bytes here BF_ReadBytes( msg, &samplePos, sizeof( samplePos )); BF_ReadBytes( msg, &forcedEnd, sizeof( forcedEnd )); S_RestoreSound( pos, entnum, chan, handle, volume, attn, pitch, flags, samplePos, forcedEnd, wordIndex ); }
/* ================== CL_ParseStaticDecal ================== */ void CL_ParseStaticDecal( sizebuf_t *msg ) { vec3_t origin; int decalIndex, entityIndex, modelIndex; cl_entity_t *ent = NULL; float scale; int flags; BF_ReadVec3Coord( msg, origin ); decalIndex = BF_ReadWord( msg ); entityIndex = BF_ReadShort( msg ); if( entityIndex > 0 ) modelIndex = BF_ReadWord( msg ); else modelIndex = 0; flags = BF_ReadByte( msg ); scale = (float)BF_ReadWord( msg ) / 4096.0f; CL_FireCustomDecal( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags, scale ); }
/* ================== CL_ParsePacketEntities An svc_packetentities has just been parsed, deal with the rest of the data stream. ================== */ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ) { frame_t *newframe, *oldframe; int oldindex, newnum, oldnum; int oldpacket, newpacket; cl_entity_t *player; entity_state_t *oldent; int i, count; // save first uncompressed packet as timestamp if( cls.changelevel && !delta && cls.demorecording ) CL_WriteDemoJumpTime(); // first, allocate packet for new frame count = BF_ReadWord( msg ); newpacket = cl.parsecountmod; newframe = &cl.frames[newpacket]; // allocate parse entities newframe->first_entity = cls.next_client_entities; newframe->num_entities = 0; newframe->valid = true; // assume valid if( delta ) { int subtracted; oldpacket = BF_ReadByte( msg ); subtracted = ((( cls.netchan.incoming_sequence & 0xFF ) - oldpacket ) & 0xFF ); if( subtracted == 0 ) { Host_Error( "CL_DeltaPacketEntities: update too old, connection dropped.\n" ); return; } 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; } oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK]; if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - 128 )) { Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" ); CL_FlushEntityPacket( msg ); return; } } else { // this is a full update that we can start delta compressing from now oldframe = NULL; oldpacket = -1; // delta too old or is initial message cl.force_send_usercmd = true; // send reply cls.demowaiting = false; // we can start recording now } // mark current delta state cl.validsequence = cls.netchan.incoming_sequence; 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; } } while( 1 ) { newnum = BF_ReadWord( msg ); if( !newnum ) break; // end of packet entities if( BF_CheckOverflow( msg )) Host_Error( "CL_ParsePacketEntities: read overflow\n" ); while( oldnum < newnum ) { // one or more entities from the old packet are unchanged CL_DeltaEntity( msg, newframe, oldnum, oldent, true ); 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; } } if( oldnum == newnum ) { // delta from previous state CL_DeltaEntity( msg, newframe, newnum, 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; } continue; } if( oldnum > newnum ) { // delta from baseline ? CL_DeltaEntity( msg, newframe, newnum, NULL, false ); continue; } } // any remaining entities in the old frame are copied over while( oldnum != MAX_ENTNUMBER ) { // one or more entities from the old packet are unchanged CL_DeltaEntity( msg, newframe, oldnum, oldent, true ); 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; } } cl.frame = *newframe; if( !cl.frame.valid ) return; player = CL_GetLocalPlayer(); if( cls.state != ca_active ) { // client entered the game cls.state = ca_active; cl.force_refdef = true; cls.changelevel = false; // changelevel is done cls.changedemo = false; // changedemo is done SCR_MakeLevelShot(); // make levelshot if needs Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar if(( cls.demoplayback || cls.disable_servercount != cl.servercount ) && cl.video_prepped ) SCR_EndLoadingPlaque(); // get rid of loading plaque } // update local player states clgame.dllFuncs.pfnTxferLocalOverrides( &player->curstate, &newframe->local.client ); // update state for all players for( i = 0; i < cl.maxclients; i++ ) { cl_entity_t *ent = CL_GetEntityByIndex( i + 1 ); if( !ent ) continue; clgame.dllFuncs.pfnProcessPlayerState( &newframe->playerstate[i], &ent->curstate ); newframe->playerstate[i].number = ent->index; } cl.frame = *newframe; }
/* ============== CL_ParseUserMessage handles all user messages ============== */ void CL_ParseUserMessage( sizebuf_t *msg, int svc_num ) { int i, iSize; byte pbuf[256]; // message can't be larger than 255 bytes // NOTE: any user message parse on engine, not in client.dll if( svc_num < svc_lastmsg || svc_num >= ( MAX_USER_MESSAGES + svc_lastmsg )) { // out or range MsgDev( D_ERROR, "CL_ParseUserMessage: illegible server message %d (out or range)\n", svc_num ); return; } for( i = 0; i < MAX_USER_MESSAGES; i++ ) { // search for user message if( clgame.msg[i].number == svc_num ) break; } if( i == MAX_USER_MESSAGES ) // probably unregistered { MsgDev( D_ERROR, "CL_ParseUserMessage: illegible server message %d (probably unregistered)\n", svc_num ); return; } // NOTE: some user messages handled into engine if( !Q_strcmp( clgame.msg[i].name, "ScreenShake" )) { CL_ParseScreenShake( msg ); return; } else if( !Q_strcmp( clgame.msg[i].name, "ScreenFade" )) { CL_ParseScreenFade( msg ); return; } iSize = clgame.msg[i].size; // message with variable sizes receive an actual size as first byte if( iSize == -1 ) iSize = BF_ReadByte( msg ); // parse user message into buffer BF_ReadBytes( msg, pbuf, iSize ); if( clgame.msg[i].func ) { clgame.msg[i].func( clgame.msg[i].name, iSize, pbuf ); // HACKHACK: run final credits for Half-Life // because hl1 doesn't have call END_SECTION if( !Q_stricmp( clgame.msg[i].name, "HudText" ) && !Q_stricmp( GI->gamefolder, "valve" )) { // it's a end, so we should run credits if( !Q_strcmp( (char *)pbuf, "END3" )) Host_Credits(); } } else { MsgDev( D_ERROR, "CL_ParseUserMessage: %s not hooked\n", clgame.msg[i].name ); clgame.msg[i].func = CL_UserMsgStub; // throw warning only once } }
/* =================== CL_ParseClientData =================== */ void CL_ParseClientData( sizebuf_t *msg ) { int i, j; clientdata_t *from_cd, *to_cd; weapon_data_t *from_wd, *to_wd; weapon_data_t nullwd[32]; clientdata_t nullcd; frame_t *frame; int idx; // this is the frame update that this message corresponds to i = cls.netchan.incoming_sequence; // did we drop some frames? if( i > cl.last_incoming_sequence + 1 ) { // mark as dropped for( j = cl.last_incoming_sequence + 1; j < i; j++ ) { if( cl.frames[j & CL_UPDATE_MASK].receivedtime >= 0.0 ) { cl.frames[j & CL_UPDATE_MASK].receivedtime = -1; cl.frames[j & CL_UPDATE_MASK].latency = 0; } } } cl.parsecount = i; // ack'd incoming messages. cl.parsecountmod = cl.parsecount & CL_UPDATE_MASK; // index into window. frame = &cl.frames[cl.parsecountmod]; // frame at index. frame->time = cl.mtime[0]; // mark network received time frame->receivedtime = host.realtime; // time now that we are parsing. if( cl.last_command_ack != -1 ) { int last_predicted; entity_state_t * ps; entity_state_t * pps; clientdata_t * pcd; clientdata_t * ppcd; weapon_data_t * wd; weapon_data_t * pwd; last_predicted = ( cl.last_incoming_sequence + ( cls.netchan.incoming_acknowledged - cl.last_command_ack)) & CL_UPDATE_MASK; pps = &cl.predict[last_predicted].playerstate; ppcd = &cl.predict[last_predicted].client; pwd = cl.predict[last_predicted].weapondata; ps = &frame->playerstate[cl.playernum]; pcd = &frame->local.client; wd = frame->local.weapondata; clgame.dllFuncs.pfnTxferPredictionData( ps, pps, pcd, ppcd, wd, pwd ); } // do this after all packets read for this frame? cl.last_command_ack = cls.netchan.incoming_acknowledged; cl.last_incoming_sequence = cls.netchan.incoming_sequence; if( hltv->integer ) return; // clientdata for spectators ends here to_cd = &frame->local.client; to_wd = frame->local.weapondata; // clear to old value before delta parsing if( !BF_ReadOneBit( msg )) { Q_memset( &nullcd, 0, sizeof( nullcd )); Q_memset( nullwd, 0, sizeof( nullwd )); from_cd = &nullcd; from_wd = nullwd; } else { int delta_sequence = BF_ReadByte( msg ); from_cd = &cl.frames[delta_sequence & CL_UPDATE_MASK].local.client; from_wd = cl.frames[delta_sequence & CL_UPDATE_MASK].local.weapondata; } MSG_ReadClientData( msg, from_cd, to_cd, cl.mtime[0] ); for( i = 0; i < MAX_WEAPONS; i++ ) { // check for end of weapondata (and clientdata_t message) if( !BF_ReadOneBit( msg )) break; // read the weapon idx idx = BF_ReadUBitLong( msg, MAX_WEAPON_BITS ); MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] ); } }
/* ================== CL_ParseServerData ================== */ void CL_ParseServerData( sizebuf_t *msg ) { string gamefolder; qboolean background; int i; MsgDev( D_NOTE, "Serverdata packet received.\n" ); cls.demowaiting = false; // server is changed clgame.load_sequence++; // now all hud sprites are invalid // wipe the client_t struct if( !cls.changelevel && !cls.changedemo ) CL_ClearState (); cls.state = ca_connected; // parse protocol version number i = BF_ReadLong( msg ); cls.serverProtocol = i; if( i != PROTOCOL_VERSION ) Host_Error( "Server uses invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION ); cl.servercount = BF_ReadLong( msg ); cl.checksum = BF_ReadLong( msg ); cl.playernum = BF_ReadByte( msg ); cl.maxclients = BF_ReadByte( msg ); clgame.maxEntities = BF_ReadWord( msg ); clgame.maxEntities = bound( 600, clgame.maxEntities, 4096 ); Q_strncpy( clgame.mapname, BF_ReadString( msg ), MAX_STRING ); Q_strncpy( clgame.maptitle, BF_ReadString( msg ), MAX_STRING ); background = BF_ReadOneBit( msg ); Q_strncpy( gamefolder, BF_ReadString( msg ), MAX_STRING ); host.features = (uint)BF_ReadLong( msg ); if( cl.maxclients > 1 && host.developer < 1 ) host.developer++; // set the background state if( cls.demoplayback && ( cls.demonum != -1 )) { // re-init mouse host.mouse_visible = false; cl.background = true; } else cl.background = background; if( cl.background ) // tell the game parts about background state Cvar_FullSet( "cl_background", "1", CVAR_READ_ONLY ); else Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY ); if( !cls.changelevel ) { // continue playing if we are changing level S_StopBackgroundTrack (); } #if 0 // NOTE: this is not tested as well. Use with precaution CL_ChangeGame( gamefolder, false ); #endif if( !cls.changedemo ) UI_SetActiveMenu( cl.background ); cl.refdef.viewentity = cl.playernum + 1; // always keep viewent an actual menu.globals->maxClients = cl.maxclients; Q_strncpy( menu.globals->maptitle, clgame.maptitle, sizeof( menu.globals->maptitle )); if( cl.maxclients > 1 && r_decals->value > mp_decals->value ) Cvar_SetFloat( "r_decals", mp_decals->value ); if( !cls.changelevel && !cls.changedemo ) CL_InitEdicts (); // re-arrange edicts // get splash name if( cls.demoplayback && ( cls.demonum != -1 )) Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", cls.demoname, glState.wideScreen ? "16x9" : "4x3" )); else Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", clgame.mapname, glState.wideScreen ? "16x9" : "4x3" )); Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar if(( cl_allow_levelshots->integer && !cls.changelevel ) || cl.background ) { if( !FS_FileExists( va( "%s.bmp", cl_levelshot_name->string ), true )) Cvar_Set( "cl_levelshot_name", "*black" ); // render a black screen cls.scrshot_request = scrshot_plaque; // request levelshot even if exist (check filetime) } if( scr_dark->integer ) { screenfade_t *sf = &clgame.fade; client_textmessage_t *title; title = CL_TextMessageGet( "GAMETITLE" ); if( title ) { // get settings from titles.txt sf->fadeEnd = title->holdtime + title->fadeout; sf->fadeReset = title->fadeout; } else sf->fadeEnd = sf->fadeReset = 4.0f; sf->fadeFlags = FFADE_IN; sf->fader = sf->fadeg = sf->fadeb = 0; sf->fadealpha = 255; sf->fadeSpeed = (float)sf->fadealpha / sf->fadeReset; sf->fadeReset += cl.time; sf->fadeEnd += sf->fadeReset; Cvar_SetFloat( "v_dark", 0.0f ); } // need to prep refresh at next oportunity cl.video_prepped = false; cl.audio_prepped = false; Q_memset( &clgame.movevars, 0, sizeof( clgame.movevars )); Q_memset( &clgame.oldmovevars, 0, sizeof( clgame.oldmovevars )); }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage( sizebuf_t *msg ) { char *s; int i, j, cmd; int param1, param2; int bufStart; cls_message_debug.parsing = true; // begin parsing starting_count = BF_GetNumBytesRead( msg ); // updates each frame // parse the message while( 1 ) { if( BF_CheckOverflow( msg )) { Host_Error( "CL_ParseServerMessage: overflow!\n" ); return; } // mark start position bufStart = BF_GetNumBytesRead( msg ); // end of message if( BF_GetNumBitsLeft( msg ) < 8 ) break; cmd = BF_ReadByte( 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: MsgDev( D_INFO, "Disconnected from server\n" ); CL_Drop (); Host_AbortCurrentFrame (); break; case svc_changing: if( BF_ReadOneBit( msg )) { cls.changelevel = true; S_StopAllSounds(); if( cls.demoplayback ) { SCR_BeginLoadingPlaque( cl.background ); cls.changedemo = true; } } else MsgDev( D_INFO, "Server disconnected, reconnecting\n" ); CL_ClearState (); CL_InitEdicts (); // re-arrange edicts if( cls.demoplayback ) { cl.background = (cls.demonum != -1) ? true : false; cls.state = ca_connected; } else cls.state = ca_connecting; cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately break; case svc_setview: cl.refdef.viewentity = BF_ReadWord( msg ); break; case svc_sound: CL_ParseSoundPacket( msg, false ); break; case svc_time: // shuffle timestamps cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = BF_ReadFloat( msg ); break; case svc_print: i = BF_ReadByte( msg ); MsgDev( D_INFO, "^6%s", BF_ReadString( msg )); if( i == PRINT_CHAT ) S_StartLocalSound( "common/menu2.wav", VOL_NORM, false ); break; case svc_stufftext: CL_ParseStuffText( msg ); break; case svc_lightstyle: CL_ParseLightStyle( msg ); break; case svc_setangle: CL_ParseSetAngle( msg ); break; case svc_serverdata: Cbuf_Execute(); // make sure any stuffed commands are done CL_ParseServerData( msg ); break; case svc_addangle: CL_ParseAddAngle( msg ); break; case svc_clientdata: CL_ParseClientData( msg ); break; case svc_packetentities: CL_ParsePacketEntities( msg, false ); break; case svc_deltapacketentities: CL_ParsePacketEntities( msg, true ); break; case svc_updatepings: CL_UpdateUserPings( msg ); break; case svc_usermessage: CL_RegisterUserMessage( msg ); break; case svc_particle: CL_ParseParticles( msg ); break; case svc_restoresound: CL_ParseRestoreSoundPacket( msg ); break; case svc_spawnstatic: CL_ParseStaticEntity( msg ); break; case svc_ambientsound: CL_ParseSoundPacket( msg, true ); break; case svc_crosshairangle: CL_ParseCrosshairAngle( msg ); break; case svc_spawnbaseline: CL_ParseBaseline( msg ); break; case svc_temp_entity: CL_ParseTempEntity( msg ); break; case svc_setpause: cl.refdef.paused = ( BF_ReadOneBit( msg ) != 0 ); break; case svc_deltamovevars: CL_ParseMovevars( msg ); break; case svc_customization: CL_ParseCustomization( msg ); break; case svc_centerprint: CL_CenterPrint( BF_ReadString( msg ), 0.25f ); break; case svc_event: CL_ParseEvent( msg ); break; case svc_event_reliable: CL_ParseReliableEvent( msg ); break; case svc_updateuserinfo: CL_UpdateUserinfo( msg ); break; case svc_intermission: cl.refdef.intermission = true; break; case svc_modelindex: CL_PrecacheModel( msg ); break; case svc_soundindex: CL_PrecacheSound( msg ); break; case svc_soundfade: CL_ParseSoundFade( msg ); break; case svc_cdtrack: param1 = BF_ReadByte( msg ); param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum param2 = BF_ReadByte( msg ); param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0 ); break; case svc_serverinfo: CL_ServerInfo( msg ); break; case svc_eventindex: CL_PrecacheEvent( msg ); break; case svc_deltatable: Delta_ParseTableField( msg ); break; case svc_weaponanim: param1 = BF_ReadByte( msg ); // iAnim param2 = BF_ReadByte( msg ); // body CL_WeaponAnim( param1, param2 ); break; case svc_bspdecal: CL_ParseStaticDecal( msg ); break; case svc_roomtype: param1 = BF_ReadShort( msg ); Cvar_SetFloat( "room_type", param1 ); break; case svc_chokecount: i = BF_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].receivedtime = -2.0; i--; } } break; case svc_resourcelist: CL_ParseResourceList( msg ); break; case svc_director: CL_ParseDirector( msg ); break; case svc_studiodecal: CL_ParseStudioDecal( msg ); break; case svc_querycvarvalue: CL_ParseCvarValue( msg ); break; case svc_querycvarvalue2: CL_ParseCvarValue2( msg ); break; default: CL_ParseUserMessage( msg, cmd ); break; } } cls_message_debug.parsing = 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, starting_count, msg ); } else if( cls.state != ca_active ) { CL_WriteDemoMessage( true, starting_count, msg ); } } }
/* ================== CL_ParseStaticEntity static client entity ================== */ void CL_ParseStaticEntity( sizebuf_t *msg ) { entity_state_t state; cl_entity_t *ent; int i; Q_memset( &state, 0, sizeof( state )); state.modelindex = BF_ReadShort( msg ); state.sequence = BF_ReadByte( msg ); state.frame = BF_ReadByte( msg ); state.colormap = BF_ReadWord( msg ); state.skin = BF_ReadByte( msg ); for( i = 0; i < 3; i++ ) { state.origin[i] = BF_ReadCoord( msg ); state.angles[i] = BF_ReadBitAngle( msg, 16 ); } state.rendermode = BF_ReadByte( msg ); if( state.rendermode != kRenderNormal ) { state.renderamt = BF_ReadByte( msg ); state.rendercolor.r = BF_ReadByte( msg ); state.rendercolor.g = BF_ReadByte( msg ); state.rendercolor.b = BF_ReadByte( msg ); state.renderfx = BF_ReadByte( msg ); } i = clgame.numStatics; if( i >= MAX_STATIC_ENTITIES ) { MsgDev( D_ERROR, "CL_ParseStaticEntity: static entities limit exceeded!\n" ); return; } ent = &clgame.static_entities[i]; clgame.numStatics++; ent->index = 0; // ??? ent->baseline = state; ent->curstate = state; ent->prevstate = state; // statics may be respawned in game e.g. for demo recording if( cls.state == ca_connected ) ent->trivial_accept = INVALID_HANDLE; // setup the new static entity CL_UpdateEntityFields( ent ); if( Mod_GetType( state.modelindex ) == mod_studio ) { CL_UpdateStudioVars( ent, &state, true ); // animate studio model ent->curstate.animtime = cl.time; ent->curstate.framerate = 1.0f; ent->latched.prevframe = 0.0f; } R_AddEfrags( ent ); // add link }