static int read_level_file(void)
{
char name[MAX_OSPATH];
size_t len, maxlen;
int index;
len = Q_snprintf(name, MAX_QPATH, "save/" SAVE_CURRENT "/%s.sv2", sv.name);
if (len >= MAX_QPATH)
return -1;
if (read_binary_file(name))
return -1;
if (MSG_ReadLong() != SAVE_MAGIC2)
return -1;
if (MSG_ReadLong() != SAVE_VERSION)
return -1;
// any error will drop from this point
// the rest can't underflow
msg_read.allowunderflow = qfalse;
// read all configstrings
while (1) {
index = MSG_ReadShort();
if (index == MAX_CONFIGSTRINGS)
break;
if (index < 0 || index > MAX_CONFIGSTRINGS)
Com_Error(ERR_DROP, "Bad savegame configstring index");
maxlen = CS_SIZE(index);
len = MSG_ReadString(sv.configstrings[index], maxlen);
if (len >= maxlen)
Com_Error(ERR_DROP, "Savegame configstring too long");
}
len = MSG_ReadByte();
if (len > MAX_MAP_PORTAL_BYTES)
Com_Error(ERR_DROP, "Savegame portalbits too long");
SV_ClearWorld();
CM_SetPortalStates(&sv.cm, MSG_ReadData(len), len);
// read game level
len = Q_snprintf(name, MAX_OSPATH, "%s/save/" SAVE_CURRENT "/%s.sav",
fs_gamedir, sv.name);
if (len >= MAX_OSPATH)
Com_Error(ERR_DROP, "Savegame path too long");
ge->ReadLevel(name);
return 0;
}
/*
================
CL_ParseSnapshot
If the snapshot is parsed properly, it will be copied to
cl.frame and saved in cl.frames[]. 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
clc.reliableAcknowledge = MSG_ReadLong( msg );
// read in the new snapshot to a temporary buffer
// we will only copy to cl.frame if it is valid
memset (&newSnap, 0, sizeof(newSnap));
newSnap.serverCommandNum = clc.serverCommandSequence;
newSnap.serverTime = MSG_ReadLong( msg );
newSnap.messageNum = MSG_ReadLong( msg );
deltaNum = MSG_ReadByte( msg );
if ( !deltaNum ) {
newSnap.deltaNum = -1;
} else {
newSnap.deltaNum = newSnap.messageNum - deltaNum;
}
newSnap.cmdNum = MSG_ReadLong( msg );
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;
} else {
old = &cl.frames[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 ) {
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
oldMessageNum = cl.frame.messageNum + 1;
if ( cl.frame.messageNum - oldMessageNum >= PACKET_BACKUP ) {
oldMessageNum = cl.frame.messageNum - ( PACKET_BACKUP - 1 );
}
for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
cl.frames[oldMessageNum & PACKET_MASK].valid = qfalse;
}
// copy to the current good spot
cl.frame = newSnap;
// calculate ping time
for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
if ( cl.frame.cmdNum == cl.packetCmdNumber[ packetNum ] ) {
cl.frame.ping = cls.realtime - cl.packetTime[ packetNum ];
//.........这里部分代码省略.........
static
void SV_UserVoip( client_t *cl, msg_t *msg ) {
const int sender = (int) (cl - svs.clients);
const int generation = MSG_ReadByte(msg);
const int sequence = MSG_ReadLong(msg);
const int frames = MSG_ReadByte(msg);
const int recip1 = MSG_ReadLong(msg);
const int recip2 = MSG_ReadLong(msg);
const int recip3 = MSG_ReadLong(msg);
const int packetsize = MSG_ReadShort(msg);
byte encoded[sizeof (cl->voipPacket[0].data)];
client_t *client = NULL;
voipServerPacket_t *packet = NULL;
int i;
if (generation < 0)
return; // short/invalid packet, bail.
else if (sequence < 0)
return; // short/invalid packet, bail.
else if (frames < 0)
return; // short/invalid packet, bail.
else if (recip1 < 0)
return; // short/invalid packet, bail.
else if (recip2 < 0)
return; // short/invalid packet, bail.
else if (recip3 < 0)
return; // short/invalid packet, bail.
else if (packetsize < 0)
return; // short/invalid packet, bail.
if (packetsize > sizeof (encoded)) { // overlarge packet?
int bytesleft = packetsize;
while (bytesleft) {
int br = bytesleft;
if (br > sizeof (encoded))
br = sizeof (encoded);
MSG_ReadData(msg, encoded, br);
bytesleft -= br;
}
return; // overlarge packet, bail.
}
MSG_ReadData(msg, encoded, packetsize);
if (SV_ShouldIgnoreVoipSender(cl))
return; // Blacklisted, disabled, etc.
// !!! FIXME: see if we read past end of msg...
// !!! FIXME: reject if not speex narrowband codec.
// !!! FIXME: decide if this is bogus data?
// (the three recip* values are 31 bits each (ignores sign bit so we can
// get a -1 error from MSG_ReadLong() ... ), allowing for 93 clients.)
assert( sv_maxclients->integer < 93 );
// decide who needs this VoIP packet sent to them...
for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
if (client->state != CS_ACTIVE)
continue; // not in the game yet, don't send to this guy.
else if (i == sender)
continue; // don't send voice packet back to original author.
else if (!client->hasVoip)
continue; // no VoIP support, or support disabled.
else if (client->muteAllVoip)
continue; // client is ignoring everyone.
else if (client->ignoreVoipFromClient[sender])
continue; // client is ignoring this talker.
else if (*cl->downloadName) // !!! FIXME: possible to DoS?
continue; // no VoIP allowed if downloading, to save bandwidth.
else if ( ((i >= 0) && (i < 31)) && ((recip1 & (1 << (i-0))) == 0) )
continue; // not addressed to this player.
else if ( ((i >= 31) && (i < 62)) && ((recip2 & (1 << (i-31))) == 0) )
continue; // not addressed to this player.
else if ( ((i >= 62) && (i < 93)) && ((recip3 & (1 << (i-62))) == 0) )
continue; // not addressed to this player.
// Transmit this packet to the client.
// !!! FIXME: I don't like this queueing system.
if (client->queuedVoipPackets >= (sizeof (client->voipPacket) / sizeof (client->voipPacket[0]))) {
Com_Printf("Too many VoIP packets queued for client #%d\n", i);
continue; // no room for another packet right now.
}
packet = &client->voipPacket[client->queuedVoipPackets];
packet->sender = sender;
packet->frames = frames;
packet->len = packetsize;
packet->generation = generation;
packet->sequence = sequence;
memcpy(packet->data, encoded, packetsize);
client->queuedVoipPackets++;
}
}
//.........这里部分代码省略.........
{
CL_AddReliableCommand( "wwwdl bbl8r" );
cls.bWWWDlDisconnected = qtrue;
}
return;
}
else
{
// server keeps sending that message till we ack it, eat and ignore
//MSG_ReadLong( msg );
MSG_ReadString( msg );
MSG_ReadLong( msg );
MSG_ReadLong( msg );
return;
}
}
if ( !block )
{
// block zero is special, contains file size
clc.downloadSize = MSG_ReadLong( msg );
Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
if ( clc.downloadSize < 0 )
{
Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) );
}
}
size = MSG_ReadShort( msg );
if ( size < 0 || size > sizeof( data ) )
{
Com_Error( ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size );
}
MSG_ReadData( msg, data, size );
if ( clc.downloadBlock != block )
{
Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block );
return;
}
// open the file if not opened yet
if ( !clc.download )
{
clc.download = FS_SV_FOpenFileWrite( cls.downloadTempName );
if ( !clc.download )
{
Com_Printf(_( "Could not create %s\n"), cls.downloadTempName );
CL_AddReliableCommand( "stopdl" );
CL_NextDownload();
return;
}
}
if ( size )
{
FS_Write( data, size, clc.download );
}
CL_AddReliableCommand( va( "nextdl %d", clc.downloadBlock ) );
clc.downloadBlock++;
clc.downloadCount += size;
// So UI gets access to it
Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
if ( !size )
{
// A zero length block means EOF
if ( clc.download )
{
FS_FCloseFile( clc.download );
clc.download = 0;
// rename the file
FS_SV_Rename( cls.downloadTempName, cls.downloadName );
}
*cls.downloadTempName = *cls.downloadName = 0;
Cvar_Set( "cl_downloadName", "" );
// send intentions now
// We need this because without it, we would hold the last nextdl and then start
// loading right away. If we take a while to load, the server is happily trying
// to send us that last block over and over.
// Write it twice to help make sure we acknowledge the download
CL_WritePacket();
CL_WritePacket();
// get another file if needed
CL_NextDownload();
}
}
void
CL_ParseFrame(void)
{
int cmd;
int len;
frame_t *old;
memset(&cl.frame, 0, sizeof(cl.frame));
cl.frame.serverframe = MSG_ReadLong(&net_message);
cl.frame.deltaframe = MSG_ReadLong(&net_message);
cl.frame.servertime = cl.frame.serverframe * 100;
/* BIG HACK to let old demos continue to work */
if (cls.serverProtocol != 26)
{
cl.surpressCount = MSG_ReadByte(&net_message);
}
if (cl_shownet->value == 3)
{
Com_Printf(" frame:%i delta:%i\n", cl.frame.serverframe,
cl.frame.deltaframe);
}
/* 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 (cl.frame.deltaframe <= 0)
{
cl.frame.valid = true; /* uncompressed frame */
old = NULL;
cls.demowaiting = false; /* we can start recording now */
}
else
{
old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
if (!old->valid)
{
/* should never happen */
Com_Printf("Delta from invalid frame (not supposed to happen!).\n");
}
if (old->serverframe != cl.frame.deltaframe)
{
/* 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.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES -
128)
{
Com_Printf("Delta parse_entities too old.\n");
}
else
{
cl.frame.valid = true; /* valid delta parse */
}
}
/* clamp time */
if (cl.time > cl.frame.servertime)
{
cl.time = cl.frame.servertime;
}
else if (cl.time < cl.frame.servertime - 100)
{
cl.time = cl.frame.servertime - 100;
}
/* read areabits */
len = MSG_ReadByte(&net_message);
MSG_ReadData(&net_message, &cl.frame.areabits, len);
/* read playerinfo */
cmd = MSG_ReadByte(&net_message);
SHOWNET(svc_strings[cmd]);
if (cmd != svc_playerinfo)
{
Com_Error(ERR_DROP, "CL_ParseFrame: 0x%X not playerinfo", cmd);
}
CL_ParsePlayerstate(old, &cl.frame);
/* read packet entities */
cmd = MSG_ReadByte(&net_message);
SHOWNET(svc_strings[cmd]);
if (cmd != svc_packetentities)
{
Com_Error(ERR_DROP, "CL_ParseFrame: 0x%X not packetentities", cmd);
}
CL_ParsePacketEntities(old, &cl.frame);
/* save the frame off in the backup array for later delta comparisons */
//.........这里部分代码省略.........
/*
=====================
CL_ParseDownload
A download message has been received from the server
=====================
*/
void CL_ParseDownload ( msg_t *msg ) {
int size;
unsigned char data[MAX_MSGLEN];
uint16_t block;
if (!*clc.downloadTempName) {
Com_Printf("Server sending download, but no download was requested\n");
CL_AddReliableCommand("stopdl", qfalse);
return;
}
// read the data
block = MSG_ReadShort ( msg );
if(!block && !clc.downloadBlock)
{
// block zero is special, contains file size
clc.downloadSize = MSG_ReadLong ( msg );
Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
if (clc.downloadSize < 0)
{
Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) );
return;
}
}
size = MSG_ReadShort ( msg );
if (size < 0 || size > sizeof(data))
{
Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk", size);
return;
}
MSG_ReadData(msg, data, size);
if((clc.downloadBlock & 0xFFFF) != block)
{
Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", (clc.downloadBlock & 0xFFFF), block);
return;
}
// open the file if not opened yet
if (!clc.download)
{
clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
if (!clc.download) {
Com_Printf( "Could not create %s\n", clc.downloadTempName );
CL_AddReliableCommand("stopdl", qfalse);
CL_NextDownload();
return;
}
}
if (size)
FS_Write( data, size, clc.download );
CL_AddReliableCommand(va("nextdl %d", clc.downloadBlock), qfalse);
clc.downloadBlock++;
clc.downloadCount += size;
// So UI gets access to it
Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
if (!size) { // A zero length block means EOF
if (clc.download) {
FS_FCloseFile( clc.download );
clc.download = 0;
// rename the file
FS_SV_Rename ( clc.downloadTempName, clc.downloadName, qfalse );
}
// send intentions now
// We need this because without it, we would hold the last nextdl and then start
// loading right away. If we take a while to load, the server is happily trying
// to send us that last block over and over.
// Write it twice to help make sure we acknowledge the download
CL_WritePacket();
CL_WritePacket();
// get another file if needed
CL_NextDownload ();
}
}
/*
================
CL_ParseFrame
================
*/
void CL_ParseFrame (void)
{
int cmd;
int len;
frame_t *old;
memset (&cl.frame, 0, sizeof(cl.frame));
cl.frame.serverframe = MSG_ReadLong(&net_message);
cl.frame.deltaframe = MSG_ReadLong(&net_message);
cl.frame.servertime = cl.frame.serverframe*100;
// BIG HACK to let old demos continue to work
if (cls.serverProtocol != 26)
cl.surpressCount = MSG_ReadByte(&net_message);
if (cl_shownet->value == 3)
Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe, cl.frame.deltaframe);
// 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 (cl.frame.deltaframe <= 0)
{
cl.frame.valid = true; // uncompressed frame
old = NULL;
cls.demowaiting = false; // we can start recording now
}
else
{
old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
if (!old->valid)
{ // should never happen
Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
}
if (old->serverframe != cl.frame.deltaframe)
{ // 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.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
{
Com_Printf ("Delta parse_entities too old.\n");
}
else
{
cl.frame.valid = true; // valid delta parse
}
}
// clamp time
if (cl.time > cl.frame.servertime)
cl.time = cl.frame.servertime;
else if (cl.time < cl.frame.servertime - 100)
cl.time = cl.frame.servertime - 100;
// read areabits
len = MSG_ReadByte(&net_message);
MSG_ReadData(&net_message, &cl.frame.areabits, len);
// read playerinfo
cmd = MSG_ReadByte(&net_message);
SHOWNET(svc_strings[cmd]);
if (cmd != svc_playerinfo)
Com_Error(ERR_DROP, "CL_ParseFrame: not playerinfo");
CL_ParsePlayerstate(old, &cl.frame);
// read packet entities
cmd = MSG_ReadByte(&net_message);
SHOWNET(svc_strings[cmd]);
if (cmd != svc_packetentities)
Com_Error(ERR_DROP, "CL_ParseFrame: not packetentities");
CL_ParsePacketEntities(old, &cl.frame);
// save the frame off in the backup array for later delta comparisons
cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
if (cl.frame.valid)
{
// getting a valid frame message ends the connection process
if (cls.state != ca_active)
{
cls.state = ca_active;
//cl_scores_setinuse_all(false); // jitscores - clear scoreboard
cl.force_refdef = true;
cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles);
//.........这里部分代码省略.........
//.........这里部分代码省略.........
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_DPrintf( "Delta frame too old.\n" );
}
else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - 128 )
{
Com_DPrintf( "Delta parseEntitiesNum too old.\n" );
}
else
{
newSnap.valid = qtrue; // valid delta parse
}
}
// read areamask
len = MSG_ReadByte( msg );
if ( len > sizeof( newSnap.areamask ) )
{
Com_Error( ERR_DROP, "CL_ParseSnapshot: Invalid size %d for areamask.", len );
}
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 )
{
请发表评论