📄 cl_parse.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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 2 of the License,
or (at your option) any later version.
Quake III Arena source code 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.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cl_parse.c -- parse a message received from the server
#include "client.h"
char *svc_strings[256] = {
"svc_bad",
"svc_nop",
"svc_gamestate",
"svc_configstring",
"svc_baseline",
"svc_serverCommand",
"svc_download",
"svc_snapshot"
};
void SHOWNET( msg_t *msg, char *s) {
if ( cl_shownet->integer >= 2) {
Com_Printf ("%3i:%s\n", msg->readcount-1, s);
}
}
/*
=========================================================================
MESSAGE PARSING
=========================================================================
*/
/*
==================
CL_DeltaEntity
Parses deltas from the given base and adds the resulting entity
to the current frame
==================
*/
void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old,
qboolean unchanged) {
entityState_t *state;
// save the parsed entity state into the big circular buffer so
// it can be used as the source for a later delta
state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];
if ( unchanged ) {
*state = *old;
} else {
MSG_ReadDeltaEntity( msg, old, state, newnum );
}
if ( state->number == (MAX_GENTITIES-1) ) {
return; // entity was delta removed
}
cl.parseEntitiesNum++;
frame->numEntities++;
}
/*
==================
CL_ParsePacketEntities
==================
*/
void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) {
int newnum;
entityState_t *oldstate;
int oldindex, oldnum;
newframe->parseEntitiesNum = cl.parseEntitiesNum;
newframe->numEntities = 0;
// delta from the entities present in oldframe
oldindex = 0;
oldstate = NULL;
if (!oldframe) {
oldnum = 99999;
} else {
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
}
while ( 1 ) {
// read the entity index number
newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
if ( newnum == (MAX_GENTITIES-1) ) {
break;
}
if ( msg->readcount > msg->cursize ) {
Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
}
while ( oldnum < newnum ) {
// one or more entities from the old packet are unchanged
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
}
CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
oldindex++;
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
}
if (oldnum == newnum) {
// delta from previous state
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum);
}
CL_DeltaEntity( msg, newframe, newnum, oldstate, qfalse );
oldindex++;
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
continue;
}
if ( oldnum > newnum ) {
// delta from baseline
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum);
}
CL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], qfalse );
continue;
}
}
// any remaining entities in the old frame are copied over
while ( oldnum != 99999 ) {
// one or more entities from the old packet are unchanged
if ( cl_shownet->integer == 3 ) {
Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
}
CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
oldindex++;
if ( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &cl.parseEntities[
(oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
oldnum = oldstate->number;
}
}
}
/*
================
CL_ParseSnapshot
If the snapshot is parsed properly, it will be copied to
cl.snap and saved in cl.snapshots[]. If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg ) {
int len;
clSnapshot_t *old;
clSnapshot_t newSnap;
int deltaNum;
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
Com_Memset (&newSnap, 0, sizeof(newSnap));
// we will have read any new server commands in this
// message before we got to svc_snapshot
newSnap.serverCommandNum = clc.serverCommandSequence;
newSnap.serverTime = MSG_ReadLong( msg );
newSnap.messageNum = clc.serverMessageSequence;
deltaNum = MSG_ReadByte( msg );
if ( !deltaNum ) {
newSnap.deltaNum = -1;
} else {
newSnap.deltaNum = newSnap.messageNum - deltaNum;
}
newSnap.snapFlags = MSG_ReadByte( msg );
// If the frame is delta compressed from data that we
// no longer have available, we must suck up the rest of
// the frame, but not use it, then ask for a non-compressed
// message
if ( newSnap.deltaNum <= 0 ) {
newSnap.valid = qtrue; // uncompressed frame
old = NULL;
clc.demowaiting = qfalse; // we can start recording now
} else {
old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
if ( !old->valid ) {
// should never happen
Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
} else if ( old->messageNum != newSnap.deltaNum ) {
// The frame that the server did the delta from
// is too old, so we can't reconstruct it properly.
Com_Printf ("Delta frame too old.\n");
} else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
Com_Printf ("Delta parseEntitiesNum too old.\n");
} else {
newSnap.valid = qtrue; // valid delta parse
}
}
// read areamask
len = MSG_ReadByte( msg );
MSG_ReadData( msg, &newSnap.areamask, len);
// read playerinfo
SHOWNET( msg, "playerstate" );
if ( old ) {
MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
} else {
MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
}
// read packet entities
SHOWNET( msg, "packet entities" );
CL_ParsePacketEntities( msg, old, &newSnap );
// if not valid, dump the entire thing now that it has
// been properly read
if ( !newSnap.valid ) {
return;
}
// clear the valid flags of any snapshots between the last
// received and this one, so if there was a dropped packet
// it won't look like something valid to delta from next
// time we wrap around in the buffer
oldMessageNum = cl.snap.messageNum + 1;
if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
}
for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
}
// copy to the current good spot
cl.snap = newSnap;
cl.snap.ping = 999;
// calculate ping time
for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
break;
}
}
// save the frame off in the backup array for later delta comparisons
cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;
if (cl_shownet->integer == 3) {
Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum,
cl.snap.deltaNum, cl.snap.ping );
}
cl.newSnapshots = qtrue;
}
//=====================================================================
int cl_connectedToPureServer;
/*
==================
CL_SystemInfoChanged
The systeminfo configstring has been changed, so parse
new information out of it. This will happen at every
gamestate, and possibly during gameplay.
==================
*/
void CL_SystemInfoChanged( void ) {
char *systemInfo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -