I WILL SORT THE FORMATTING OUT IN THIS POST EVENTUALLY, BEAR WITH ME FOR NOW OR USE THE ORIGINAL LINK BELOW.
This document describes the demo format that later releases of quake 3 use. It is not my work, but that of Andrey Nazarov. I am mirroring it here as it is hard to find and makes it easier for me to reference and append to if required. Here is the original Quake 3 Demo Specification and a mirror of the Quake 3 Demo Specification.
Quake III Arena Demo File Specifications
File formats: *.dm_66, *.dm_67, *.dm_68
- About
- Sizebuf_t structure
- Demofile format
- MSG_ReadBits and MSG_WriteBits
- Common MSG_* functions
- Delta encoding of game structures
- Huffman encoding
- Server to Client commands
- Operations with gameState_t
- Parsing whole demo file
- Thanks to
1. About
This document contains complete Quake III Arena Demo File specifications, useful for programmers working in C or C++ demo players/editors. It introduces demo message encoding/decoding routines that allow parsing and writing Quake III Arena Demo Files.
Note this code doesn’t provide full Quake III Arena network protocol support, as it uses much more encryption. All network-only stuff was removed from this document.
This code is redistributed under the terms of GNU General Public License
You can also download this example application (source code + binary) from http://skuller-vidnoe.narod.ru/downloads/dm_68.zip
It contains all source code present in this document and all necessary headers. The only thing this app does is dumping obituaries and some other info from a *.dm_68 file.
2. Sizebuf_t structure
All MSG_* functions operate with the sizebuf_t structure, which holds all necessary information about current buffer state and is used both when reading and writing bits to the buffer. Normally nothing outside MSG_* functions should modify this structure.
typedef struct sizebuf_s {
qboolean allowoverflow; // if false, do a Com_Error
qboolean overflowed; // set to true if the buffer size failed
qboolean uncompressed; // don't do Huffman encoding, write raw bytes
byte *data; // pointer to message buffer, set by MSG_Init
int maxsize; // size in bytes of message buffer, set by MSG_Init
int cursize; // number of bytes written to the buffer, set by MSG_WriteBits
int readcount; // number of bytes read from the buffer, set by MSG_ReadBits
int bit; // number of bits written to or read from the buffer
} sizebuf_t;
3. Demofile format
Actually Quake III Demo File is a version of server-to-client communication protocol, written
to a disk in the following format:
Demo block structure:
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;mso-border-insideh:.5pt solid windowtext;
mso-border-insidev:.5pt solid windowtext'>
style='mso-bidi-font-weight:normal'>Size, bytes
style='mso-bidi-font-weight:normal'>Description
style='font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>4
style='font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>Message
sequence, <seq>
style='font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>4
style='font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>Message
length, <msglen>
style='font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'><msglen>
style='font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>Message
data
Demo
is parsed until <seq> and <msglen> are not equal to -1 (
style='color:green'>end block), which indicates demofile EOF. <msglen>
should be always less than MAX_MSGLEN
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>.
#define
style='mso-tab-count:1'> MAX_MSGLEN 0×4000
style='mso-tab-count:1'> // max length of demo
message
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>Sample routine for demo file
parsing:
|
style='mso-ansi-language:EN-US'>FILE *demofile;
style='color:blue;mso-ansi-language:EN-US'>int
style='mso-ansi-language:EN-US'> demoMessageSequence; // used for delta decoding
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>=====================
style='color:green;mso-ansi-language:EN-US'>Parse_NextDemoMessage
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>=====================
lang=EN-US style='color:blue;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>*/
style='mso-ansi-language:EN-US'>qboolean Parse_NextDemoMessage(
style='color:blue'>void ) {
style='mso-ansi-language:EN-US'> sizebuf_t
style='mso-tab-count:1'> msg;
style='mso-ansi-language:EN-US'> byte
style='mso-tab-count:2'> buffer[MAX_MSGLEN];
style='mso-ansi-language:EN-US'>
style='color:blue'>int len;
style='mso-ansi-language:EN-US'>
style='color:blue'>int seq;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( fread( &seq, 1, 4, demofile ) != 4 ) {
style='mso-ansi-language:EN-US'> Com_Printf(
style='mso-ansi-language:EN-US'>
style='color:blue'>return qfalse;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( fread( &len, 1, 4, demofile ) != 4 ) {
style='mso-ansi-language:EN-US'> Com_Printf(
style='mso-ansi-language:EN-US'>
style='color:blue'>return qfalse;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( seq == -1 || len == -1 ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return qfalse; // demo
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> MSG_Init(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> demoMessageSequence
style='mso-ansi-language:EN-US'> msg.cursize
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg.cursize <= 0 || msg.cursize >=
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( fread( msg.data, 1, msg.cursize, demofile ) !=
style='mso-ansi-language:EN-US'> Com_Printf(
style='mso-ansi-language:EN-US'>
style='color:blue'>return qfalse;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> Parse_DemoMessage(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return qtrue;
style='mso-ansi-language:EN-US'>} |
lang=EN-US style='mso-bidi-font-size:10.0pt;font-family:Arial;mso-ansi-language:
EN-US'>4. MSG_ReadBits and MSG_WriteBits
style='mso-bidi-font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>
The
basic functions for performing i/o operations on message data are
style='color:green'>MSG_WriteBits and MSG_ReadBits,
which do Huffman encoding/decoding of the data bitstream using
style='color:green'>Huff_* code. If uncompressed
flag is set on the sizebuf, then raw bytes are used, i.e.
style='color:green'>bits value is rounded to a full byte (q2-style).
Currently this is not used when working with demo files.
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_WriteBits
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteBits( sizebuf_t *msg,
style='color:blue'>int value, int bits
style='mso-ansi-language:EN-US'>
style='color:blue'>int remaining;
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'> byte
style='mso-tab-count:3'> *buf;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->maxsize – msg->cursize < 4 ) {
style='mso-ansi-language:EN-US'> msg->overflowed
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !bits || bits < -31 || bits > 32 ) {
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bits < 0 ) {
style='mso-ansi-language:EN-US'> bits
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->uncompressed ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bits <= 8 ) {
style='mso-ansi-language:EN-US'> buf
style='mso-ansi-language:EN-US'> buf[0]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> buf
style='mso-ansi-language:EN-US'> buf[0]
style='mso-ansi-language:EN-US'> buf[1]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> buf
style='mso-ansi-language:EN-US'> buf[0]
style='mso-ansi-language:EN-US'> buf[1]
style='mso-ansi-language:EN-US'> buf[2]
style='mso-ansi-language:EN-US'> buf[3]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> value
style='mso-ansi-language:EN-US'> remaining
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<remaining ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !(msg->bit & 7) ) {
style='mso-ansi-language:EN-US'> msg->data[msg->bit
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> msg->data[msg->bit
style='mso-ansi-language:EN-US'> msg->bit++;
style='mso-ansi-language:EN-US'> value
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'> bits
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bits > 0 ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<(bits+7)>>3 ; i++ ) {
style='mso-ansi-language:EN-US'> Huff_EmitByte(
style='mso-ansi-language:EN-US'> value
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> msg->cursize }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> |
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_ReadBits
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>int
style='mso-ansi-language:EN-US'> MSG_ReadBits( sizebuf_t *msg,
style='color:blue'>int bits ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='color:blue'>int val;
style='mso-ansi-language:EN-US'>
style='color:blue'>int bitmask = 0;
style='mso-ansi-language:EN-US'>
style='color:blue'>int remaining;
style='mso-ansi-language:EN-US'> qboolean
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !bits || bits < -31 || bits > 32 ) {
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bits < 0 ) {
style='mso-ansi-language:EN-US'> bits
style='mso-ansi-language:EN-US'> extend
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->uncompressed ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bits <= 8 ) {
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'> msg->readcount++;
style='mso-ansi-language:EN-US'> msg->bit
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'> +
style='mso-ansi-language:EN-US'> msg->readcount
style='mso-ansi-language:EN-US'> msg->bit
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'> +
style='mso-ansi-language:EN-US'> +
style='mso-ansi-language:EN-US'> +
style='mso-ansi-language:EN-US'> msg->readcount
style='mso-ansi-language:EN-US'> msg->bit
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> remaining
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<remaining ; i++ ) {
style='mso-ansi-language:EN-US'> val
style='mso-ansi-language:EN-US'> msg->bit++;
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<bits-remaining ; i+=8 ) {
style='mso-ansi-language:EN-US'> val
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> msg->readcount
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( extend ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bitmask & (1 << (bits – 1)) ) {
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return bitmask;
style='mso-ansi-language:EN-US'>} |
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>There is a wrapper interface for
writing/reading bytes, shorts and ints. It is implemented as macros and inline
functions.
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>
|
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> MSG_WriteByte(msg,c)
style='mso-tab-count:3'> MSG_WriteBits(msg,c,8)
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> MSG_WriteShort(msg,c)
style='mso-tab-count:3'> MSG_WriteBits(msg,c,16)
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> MSG_WriteSignedShort(msg,c)
style='mso-tab-count:2'> MSG_WriteBits(msg,c,-16)
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> MSG_WriteLong(msg,c)
style='mso-tab-count:3'> MSG_WriteBits(msg,c,32)
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>static
style='mso-ansi-language:EN-US'> ID_INLINE int
style='mso-ansi-language:EN-US'>
style='color:blue'>int c = MSG_ReadBits( msg, 8 ) & 0xFF;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->readcount > msg->cursize ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return -1;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return c;
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>static
style='mso-ansi-language:EN-US'> ID_INLINE int
style='mso-ansi-language:EN-US'>
style='color:blue'>int c = MSG_ReadBits( msg, 16 );
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->readcount > msg->cursize ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return -1;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return c;
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>static
style='mso-ansi-language:EN-US'> ID_INLINE int
style='mso-ansi-language:EN-US'>
style='color:blue'>int c = MSG_ReadBits( msg, -16 );
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->readcount > msg->cursize ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return -1;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return c;
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>static
style='mso-ansi-language:EN-US'> ID_INLINE int
style='mso-ansi-language:EN-US'>
style='color:blue'>int c = MSG_ReadBits( msg, 32 );
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->readcount > msg->cursize ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return -1;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return c;
style='mso-ansi-language:EN-US'>} |
style='font-size:9.0pt;mso-bidi-font-size:12.0pt;font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";mso-ansi-language:EN-US'>
lang=EN-US style='mso-bidi-font-size:10.0pt;font-family:Arial;mso-ansi-language:
EN-US'>5. Common MSG_* functions
style='mso-bidi-font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>
style='font-size:9.0pt;mso-bidi-font-size:12.0pt;font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";mso-ansi-language:EN-US'>
|
style='color:green;mso-ansi-language:EN-US'>// initialize sizebuf_t and
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_Init( sizebuf_t *msg, byte *buffer,
style='color:blue'>int size );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// initialize sizebuf_t,
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_InitRaw( sizebuf_t *msg, byte *buffer,
style='color:blue'>int size );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// clear sizebuf_t, prepare it
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_Clear( sizebuf_t *msg );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// unset uncompressed flag for
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_SetBitstream( sizebuf_t *msg );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// strcat raw data to the
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteRawData( sizebuf_t *msg,
style='color:blue'>const void *data, int
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// prepare sizebuf_t for writing
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_BeginWriting( sizebuf_t *msg );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// write data as bytes
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteData( sizebuf_t *msg,
style='color:blue'>const void *data, int
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// write string as bytes up to
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteString( sizebuf_t *msg,
style='color:blue'>const char *string );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// write string as bytes up to BIG_INFO_STRING
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteBigString( sizebuf_t *msg,
style='color:blue'>const char *string );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// prepare sizebuf_t for reading and
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_BeginReading( sizebuf_t *msg );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// read data as bytes
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_ReadData( sizebuf_t *msg,
style='color:blue'>void *data, int len
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// read string as bytes up to
style='color:blue;mso-ansi-language:EN-US'>char
style='mso-ansi-language:EN-US'> *MSG_ReadString( sizebuf_t *msg );
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// read string as bytes up to BIG_INFO_STRING
lang=EN-US style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>char
style='mso-ansi-language:EN-US'> *MSG_ReadBigString( sizebuf_t *msg ); |
style='font-size:9.0pt;mso-bidi-font-size:12.0pt;font-family:"Courier New";
mso-bidi-font-family:"Times New Roman";mso-ansi-language:EN-US'>
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_GetSpace
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>static void
lang=EN-US style='mso-ansi-language:EN-US'> *MSG_GetSpace( sizebuf_t *msg,
style='color:blue'>int length ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>void *data;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( msg->cursize + length > msg->maxsize )
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !msg->allowoverflow ) {
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( length > msg->maxsize ) {
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> MSG_Clear(
style='mso-ansi-language:EN-US'> msg->overflowed
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> data
style='mso-ansi-language:EN-US'> msg->cursize
style='mso-ansi-language:EN-US'> msg->bit
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return data;
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_Init
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_Init( sizebuf_t *msg, byte *buffer,
style='color:blue'>int size ) {
style='mso-ansi-language:EN-US'> memset(
style='mso-ansi-language:EN-US'> msg->data
style='mso-ansi-language:EN-US'> msg->maxsize
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_InitRaw
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_InitRaw( sizebuf_t *msg, byte *buffer,
style='color:blue'>int size ) {
style='mso-ansi-language:EN-US'> memset(
style='mso-ansi-language:EN-US'> msg->data
style='mso-ansi-language:EN-US'> msg->maxsize
style='mso-ansi-language:EN-US'> msg->uncompressed
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_Clear
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_Clear( sizebuf_t *msg ) {
style='mso-ansi-language:EN-US'> msg->cursize
style='mso-ansi-language:EN-US'> msg->overflowed
style='mso-ansi-language:EN-US'> msg->uncompressed
style='mso-ansi-language:EN-US'> msg->bit
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_SetBitstream
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_SetBitstream( sizebuf_t *msg ) {
style='mso-ansi-language:EN-US'> msg->uncompressed
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_WriteRawData
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteRawData( sizebuf_t *msg,
style='color:blue'>const void *data, int
style='mso-ansi-language:EN-US'>
style='color:blue'>if( length > 0 ) {
style='mso-ansi-language:EN-US'> memcpy(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_BeginWriting
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_BeginWriting( sizebuf_t *msg ) {
style='mso-ansi-language:EN-US'> msg->uncompressed
style='mso-ansi-language:EN-US'> msg->overflowed
style='mso-ansi-language:EN-US'> msg->cursize
style='mso-ansi-language:EN-US'> msg->bit
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_WriteData
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteData( sizebuf_t *msg,
style='color:blue'>const void *data, int
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<length ; i++ ) {
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_WriteString
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteString( sizebuf_t *msg,
style='color:blue'>const char *string ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>char buffer[MAX_STRING_CHARS];
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='color:blue'>int len;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !string ) {
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> len
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( len >= sizeof(
style='mso-ansi-language:EN-US'> Com_Printf(
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> Q_strncpyz(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<len ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( buffer[i] > 127 ) {
style='mso-ansi-language:EN-US'> buffer[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<=len ; i++ ) {
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_WriteString
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteBigString( sizebuf_t *msg,
style='color:blue'>const char *string ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>char buffer[BIG_INFO_STRING];
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='color:blue'>int len;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !string ) {
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> len
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( len >= sizeof(
style='mso-ansi-language:EN-US'> Com_Printf(
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> Q_strncpyz(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<len ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( buffer[i] > 127 ) {
style='mso-ansi-language:EN-US'> buffer[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<=len ; i++ ) {
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_BeginReading
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_BeginReading( sizebuf_t *msg ) {
style='mso-ansi-language:EN-US'> msg->readcount
style='mso-ansi-language:EN-US'> msg->bit
style='mso-ansi-language:EN-US'> msg->uncompressed
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_ReadData
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_ReadData( sizebuf_t *msg,
style='color:blue'>void *data, int len
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='color:blue'>int c;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<len ; i++ ) {
style='mso-ansi-language:EN-US'> c
style='mso-ansi-language:EN-US'>
style='color:blue'>if( c == -1 ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>break;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='color:blue'>if( data ) {
style='mso-ansi-language:EN-US'> ((byte
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_ReadString
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>char
style='mso-ansi-language:EN-US'> *MSG_ReadString( sizebuf_t *msg ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>static char string[MAX_STRING_CHARS];
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='color:blue'>int c;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<sizeof(
style='mso-ansi-language:EN-US'> c
style='mso-ansi-language:EN-US'>
style='color:blue'>if( c == -1 || c == 0 ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>break;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='color:blue'>if( c == ‘%’ || c > 127 ) {
style='mso-ansi-language:EN-US'> c
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> string[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> string[i]
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return string;
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
lang=EN-US style='color:blue;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>MSG_ReadBigString
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>char
style='mso-ansi-language:EN-US'> *MSG_ReadBigString( sizebuf_t *msg ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>static char string[BIG_INFO_STRING];
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='color:blue'>int c;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<sizeof(
style='mso-ansi-language:EN-US'> c
style='mso-ansi-language:EN-US'>
style='color:blue'>if( c == -1 || c == 0 ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>break;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='color:blue'>if( c == ‘%’ || c > 127 ) {
style='mso-ansi-language:EN-US'> c
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> string[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> string[i]
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>return string;
style='mso-ansi-language:EN-US'>} |
lang=EN-US style='mso-bidi-font-size:10.0pt;font-family:Arial;mso-ansi-language:
EN-US'>6. Delta encoding of game structures
style='mso-bidi-font-size:10.0pt;font-family:Arial;mso-ansi-language:EN-US'>
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>For network bandwidth saving the following
entityState_t and playerState_t structures are delta compressed when
transmitted over the network:
|
style='color:green;mso-ansi-language:EN-US'>// playerState_t is the
style='color:green;mso-ansi-language:EN-US'>// to predict player motion and
style='color:green;mso-ansi-language:EN-US'>// nothing outside of pmove
style='color:green;mso-ansi-language:EN-US'>// will occur
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// you can’t add anything to this
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// playerState_t is a full
style='color:green;mso-ansi-language:EN-US'>// so if a playerState_t is
style='color:green;mso-ansi-language:EN-US'>// from it.
style='color:blue;mso-ansi-language:EN-US'>typedef struct
lang=EN-US style='mso-ansi-language:EN-US'> playerState_s {
style='mso-ansi-language:EN-US'>
style='color:blue'>int commandTime;
style='mso-tab-count:1'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int pm_type;
style='mso-ansi-language:EN-US'>
style='color:blue'>int bobCycle;
style='mso-tab-count:2'> // for
style='mso-ansi-language:EN-US'>
style='color:blue'>int pm_flags;
style='mso-tab-count:2'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int pm_time;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:2'> origin;
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:2'> velocity;
style='mso-ansi-language:EN-US'>
style='color:blue'>int weaponTime;
style='mso-ansi-language:EN-US'>
style='color:blue'>int gravity;
style='mso-ansi-language:EN-US'>
style='color:blue'>int speed;
style='mso-ansi-language:EN-US'>
style='color:blue'>int delta_angles[3];
style='mso-tab-count:1'> // add to
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int groundEntityNum;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int legsTimer;
style='mso-tab-count:2'> // don’t
style='mso-ansi-language:EN-US'>
style='color:blue'>int legsAnim;
style='mso-tab-count:2'> // mask
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int torsoTimer;
style='mso-tab-count:2'> // don’t
style='mso-ansi-language:EN-US'>
style='color:blue'>int torsoAnim;
style='mso-tab-count:2'> // mask
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int movementDir;
style='mso-tab-count:1'> // a number 0 to 7
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'>
style='mso-tab-count:6'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:2'> grapplePoint; // location of grapple to pull towards
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int eFlags;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int eventSequence;
style='mso-tab-count:1'> // pmove
style='mso-ansi-language:EN-US'>
style='color:blue'>int events[MAX_PS_EVENTS];
style='mso-ansi-language:EN-US'>
style='color:blue'>int eventParms[MAX_PS_EVENTS];
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int externalEvent;
style='mso-tab-count:1'> // events set
style='mso-ansi-language:EN-US'>
style='color:blue'>int externalEventParm;
style='mso-ansi-language:EN-US'>
style='color:blue'>int externalEventTime;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int clientNum;
style='mso-tab-count:2'> // ranges
style='mso-ansi-language:EN-US'>
style='color:blue'>int weapon;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int weaponstate;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:2'> viewangles; // for fixed views
style='mso-ansi-language:EN-US'>
style='color:blue'>int viewheight;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// damage feedback
style='mso-ansi-language:EN-US'>
style='color:blue'>int damageEvent;
style='mso-tab-count:1'> // when it changes,
style='mso-ansi-language:EN-US'>
style='color:blue'>int damageYaw;
style='mso-ansi-language:EN-US'>
style='color:blue'>int damagePitch;
style='mso-ansi-language:EN-US'>
style='color:blue'>int damageCount;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int stats[MAX_STATS];
style='mso-ansi-language:EN-US'>
style='color:blue'>int persistant[MAX_PERSISTANT];
style='mso-tab-count:1'> // stats that
style='mso-ansi-language:EN-US'>
style='color:blue'>int powerups[MAX_POWERUPS];
style='mso-tab-count:1'> // level.time
style='mso-ansi-language:EN-US'>
style='color:blue'>int ammo[MAX_WEAPONS];
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int generic1;
style='mso-ansi-language:EN-US'>
style='color:blue'>int loopSound;
style='mso-ansi-language:EN-US'>
style='color:blue'>int jumppad_ent;
style='mso-tab-count:1'> // jumppad entity
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// not communicated over the net at all
style='mso-ansi-language:EN-US'>
style='color:blue'>int ping;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int pmove_framecount;
style='mso-tab-count:1'> // FIXME: don’t
style='mso-ansi-language:EN-US'>
style='color:blue'>int jumppad_frame;
style='mso-ansi-language:EN-US'>
style='color:blue'>int entityEventSequence;
style='mso-ansi-language:EN-US'>} playerState_t; |
|
style='color:green;mso-ansi-language:EN-US'>// if entityState->solid ==
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> SOLID_BMODEL
style='mso-tab-count:1'> 0xffffff
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>typedef enum
lang=EN-US style='mso-ansi-language:EN-US'> {
style='mso-ansi-language:EN-US'> TR_STATIONARY,
style='mso-ansi-language:EN-US'> TR_INTERPOLATE,
style='mso-tab-count:4'>
style='color:green'>// non-parametric, but interpolate between snapshots
style='mso-ansi-language:EN-US'> TR_LINEAR,
style='mso-ansi-language:EN-US'> TR_LINEAR_STOP,
style='mso-ansi-language:EN-US'> TR_SINE,
style='mso-tab-count:5'>
style='color:green'>// value = base + sin( time / duration ) * delta
style='mso-ansi-language:EN-US'> TR_GRAVITY
style='mso-ansi-language:EN-US'>} trType_t;
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>typedef struct
lang=EN-US style='mso-ansi-language:EN-US'> {
style='mso-ansi-language:EN-US'> trType_t
style='mso-tab-count:1'> trType;
style='mso-ansi-language:EN-US'>
style='color:blue'>int trTime;
style='mso-ansi-language:EN-US'>
style='color:blue'>int trDuration;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:1'> trBase;
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:1'> trDelta;
style='color:green'>// velocity, etc
style='mso-ansi-language:EN-US'>} trajectory_t;
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// entityState_t is the
style='color:green;mso-ansi-language:EN-US'>// in an update message about
style='color:green;mso-ansi-language:EN-US'>// need to render in some way
style='color:green;mso-ansi-language:EN-US'>// Different eTypes may use the
style='color:green;mso-ansi-language:EN-US'>// The messages are delta
style='color:green;mso-ansi-language:EN-US'>// the structure size is fairly
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>typedef
style='mso-ansi-language:EN-US'> struct
style='mso-ansi-language:EN-US'>
style='color:blue'>int number;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int eType;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int eFlags;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> trajectory_t
style='mso-tab-count:1'> pos;
style='color:green'>// for calculating position
style='mso-ansi-language:EN-US'> trajectory_t
style='mso-tab-count:1'> apos;
style='color:green'>// for calculating angles
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int time;
style='mso-ansi-language:EN-US'>
style='color:blue'>int time2;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:1'> origin;
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:1'> origin2;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:1'> angles;
style='mso-ansi-language:EN-US'> vec3_t
style='mso-tab-count:1'> angles2;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int otherEntityNum;
style='mso-tab-count:1'> // shotgun
style='mso-ansi-language:EN-US'>
style='color:blue'>int otherEntityNum2;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int groundEntityNum;
style='mso-tab-count:1'> // -1 = in air
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int constantLight;
style='mso-tab-count:1'> // r +
style='mso-ansi-language:EN-US'>
style='color:blue'>int loopSound;
style='mso-tab-count:2'> //
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int modelindex;
style='mso-ansi-language:EN-US'>
style='color:blue'>int modelindex2;
style='mso-ansi-language:EN-US'>
style='color:blue'>int clientNum;
style='mso-tab-count:2'> // 0 to
style='mso-ansi-language:EN-US'>
style='color:blue'>int frame;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int solid;
style='mso-tab-count:3'> // for
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int event;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int eventParm;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// for players
style='mso-ansi-language:EN-US'>
style='color:blue'>int powerups;
style='mso-tab-count:2'> // bit
style='mso-ansi-language:EN-US'>
style='color:blue'>int weapon;
style='mso-tab-count:3'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>int legsAnim;
style='mso-tab-count:2'> // mask
style='mso-ansi-language:EN-US'>
style='color:blue'>int torsoAnim;
style='mso-tab-count:2'> // mask
style='color:blue;mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int generic1;
style='mso-ansi-language:EN-US'>} entityState_t; |
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>The following tables define offsets
of each field in these structures and size of it (in bits):
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>======================================================================================
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>======================================================================================
style='color:green;mso-ansi-language:EN-US'>*/
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>typedef struct
lang=EN-US style='mso-ansi-language:EN-US'> {
style='mso-ansi-language:EN-US'>
style='color:blue'>int offset;
style='mso-ansi-language:EN-US'>
style='color:blue'>int bits;
style='mso-tab-count:1'> // bits >
style='mso-ansi-language:EN-US'>
style='mso-tab-count:2'> // bits
style='mso-ansi-language:EN-US'>
style='color:green'>// bits < 0
style='mso-ansi-language:EN-US'>} field_t;
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// field declarations
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> PS_FIELD(n,b) { ((int)&(((playerState_t
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> ES_FIELD(n,b) { ((int)&(((entityState_t
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>// field data accessing
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> FIELD_INTEGER(s) (*(int
style='mso-spacerun:yes'> *)((byte *)(s)+field->offset))
style='color:blue;mso-ansi-language:EN-US'>#define
style='mso-ansi-language:EN-US'> FIELD_FLOAT(s) (*(float *)((byte
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>//
style='color:green;mso-ansi-language:EN-US'>// playerState_t
style='color:green;mso-ansi-language:EN-US'>//
style='color:blue;mso-ansi-language:EN-US'>static
style='mso-ansi-language:EN-US'> field_t psTable[] = {
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'> PS_FIELD(
style='mso-ansi-language:EN-US'>};
style='mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>//
style='color:green;mso-ansi-language:EN-US'>// entityState_t
style='color:green;mso-ansi-language:EN-US'>//
style='color:blue;mso-ansi-language:EN-US'>static
style='mso-ansi-language:EN-US'> field_t esTable[] = {
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'> ES_FIELD(
style='mso-ansi-language:EN-US'>};
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>static const int
lang=EN-US style='mso-ansi-language:EN-US'> psTableSize =
style='color:blue'>sizeof( psTable ) / sizeof(
style='color:blue;mso-ansi-language:EN-US'>static const int
lang=EN-US style='mso-ansi-language:EN-US'> esTableSize =
style='color:blue'>sizeof( esTable ) / sizeof(
style='mso-ansi-language:EN-US'>
style='color:blue;mso-ansi-language:EN-US'>static const
lang=EN-US style='mso-ansi-language:EN-US'> entityState_t
style='mso-tab-count:1'> nullEntityState;
style='color:blue;mso-ansi-language:EN-US'>static const
lang=EN-US style='mso-ansi-language:EN-US'> playerState_t
style='mso-tab-count:1'> nullPlayerState; |
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>Float values (or
style='color:green'>‘vectors’) can be written as 32 bits or 13 bits.
style='color:green'>‘Snapped’ vectors, i.e. floats without fractional
part, are written as unsigned 13-bit integers for network bandwidth saving, if
their values donÂ’t exceed MAX_SNAPPED.
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>
// snapped vectors are packed in 13 bits instead of 32
#define
SNAPPED_BITS 13
#define
MAX_SNAPPED (1<<SNAPPED_BITS)
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>Delta compressed structures are
read/write using the following functions:
style='font-size:10.0pt;mso-bidi-font-size:12.0pt;font-family:Arial;mso-bidi-font-family:
"Times New Roman";mso-ansi-language:EN-US'>
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_WriteDeltaEntity
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteDeltaEntity( sizebuf_t *msg,
style='color:blue'>const entityState_t *from, const
style='mso-ansi-language:EN-US'> field_t
style='mso-tab-count:1'> *field;
style='mso-ansi-language:EN-US'>
style='color:blue'>int to_value;
style='mso-ansi-language:EN-US'>
style='color:blue'>int to_integer;
style='mso-ansi-language:EN-US'>
style='color:blue'>float to_float;
style='mso-ansi-language:EN-US'>
style='color:blue'>int maxFieldNum;
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !to ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( from ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='color:blue'>return; // removed
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( to->number < 0 || to->number >
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !from ) {
style='mso-ansi-language:EN-US'> from
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'> maxFieldNum
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0, field=esTable ; i<esTableSize ; i++,
style='mso-ansi-language:EN-US'>
style='color:blue'>if( FIELD_INTEGER( from ) != FIELD_INTEGER( to ) )
style='mso-ansi-language:EN-US'> maxFieldNum
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !maxFieldNum ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !force ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return; // don’t emit any
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='color:blue'>return; // unchanged
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0, field=esTable ; i<maxFieldNum ; i++,
style='mso-ansi-language:EN-US'> to_value
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( FIELD_INTEGER( from ) == to_value ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // field
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !to_value ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // field set to
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( field->bits ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // integer
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'> to_float
style='mso-ansi-language:EN-US'> to_integer
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( (float)to_integer
style='mso-ansi-language:EN-US'> &&
style='mso-ansi-language:EN-US'> &&
style='mso-ansi-language:EN-US'> {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteLong(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>} |
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_ReadDeltaEntity
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_ReadDeltaEntity( sizebuf_t *msg,
style='color:blue'>const entityState_t *from, entityState_t *to,
style='color:blue'>int number ) {
style='mso-ansi-language:EN-US'> field_t
style='mso-tab-count:1'> *field;
style='mso-ansi-language:EN-US'>
style='color:blue'>int maxFieldNum;
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( number < 0 || number >= MAX_GENTITIES ) {
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !to ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> memset(
style='mso-ansi-language:EN-US'> to->number
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='color:green'>// removed
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !from ) {
style='mso-ansi-language:EN-US'> memset(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> memcpy(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> to->number
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return; // unchanged
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> maxFieldNum
style='mso-ansi-language:EN-US'>
style='color:blue'>if( maxFieldNum > esTableSize ) {
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0, field=esTable ; i<maxFieldNum ; i++,
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // field
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> FIELD_INTEGER(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // field set to
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( field->bits ) {
style='mso-ansi-language:EN-US'> FIELD_INTEGER(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue;
style='color:green'>// integer value
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> FIELD_FLOAT(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> FIELD_INTEGER(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>} |
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_WriteDeltaPlayerstate
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_WriteDeltaPlayerstate( sizebuf_t *msg,
style='color:blue'>const playerState_t *from, const
style='mso-ansi-language:EN-US'> field_t
style='mso-tab-count:1'> *field;
style='mso-ansi-language:EN-US'>
style='color:blue'>int
style='mso-tab-count:1'> to_value;
style='mso-ansi-language:EN-US'>
style='color:blue'>float to_float;
style='mso-ansi-language:EN-US'>
style='color:blue'>int to_integer;
style='mso-ansi-language:EN-US'>
style='color:blue'>int maxFieldNum;
style='mso-ansi-language:EN-US'>
style='color:blue'>int statsMask;
style='mso-ansi-language:EN-US'>
style='color:blue'>int persistantMask;
style='mso-ansi-language:EN-US'>
style='color:blue'>int ammoMask;
style='mso-ansi-language:EN-US'>
style='color:blue'>int powerupsMask;
style='mso-tab-count:1'>
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !to ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !from ) {
style='mso-ansi-language:EN-US'> from
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'> maxFieldNum
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0, field=psTable ; i<psTableSize ; i++,
style='mso-ansi-language:EN-US'>
style='color:blue'>if( FIELD_INTEGER( from ) != FIELD_INTEGER( to ) )
style='mso-ansi-language:EN-US'> maxFieldNum
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> MSG_WriteByte(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0, field=psTable ; i<maxFieldNum ; i++,
style='mso-ansi-language:EN-US'> to_value
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( FIELD_INTEGER( from ) == to_value ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // field
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( field->bits ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // integer
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'> to_float
style='mso-ansi-language:EN-US'> to_integer
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( (float)to_integer
style='mso-ansi-language:EN-US'> &&
style='mso-ansi-language:EN-US'> &&
style='mso-ansi-language:EN-US'> {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteLong(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'> statsMask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_STATS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( from->stats[i] != to->stats[i] ) {
style='mso-ansi-language:EN-US'> statsMask
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> persistantMask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_PERSISTANT ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( from->persistant[i] != to->persistant[i]
style='mso-ansi-language:EN-US'> persistantMask
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> ammoMask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_WEAPONS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( from->ammo[i] != to->ammo[i] ) {
style='mso-ansi-language:EN-US'> ammoMask
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> powerupsMask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_POWERUPS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( from->powerups[i] != to->powerups[i] ) {
style='mso-ansi-language:EN-US'> powerupsMask
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !statsMask && !persistantMask
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='color:blue'>return; // no arrays
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_STATS
style='mso-ansi-language:EN-US'>
style='color:blue'>if( statsMask ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteShort(
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_STATS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( statsMask & (1 << i) ) {
style='mso-ansi-language:EN-US'> MSG_WriteSignedShort(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_PERSISTANT
style='mso-ansi-language:EN-US'>
style='color:blue'>if( persistantMask ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteShort(
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_PERSISTANT ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( persistantMask & (1 << i) ) {
style='mso-ansi-language:EN-US'> MSG_WriteSignedShort(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_AMMO
style='mso-ansi-language:EN-US'>
style='color:blue'>if( ammoMask ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteShort(
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_WEAPONS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( ammoMask & (1 << i) ) {
style='mso-ansi-language:EN-US'> MSG_WriteShort(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_POWERUPS
style='mso-ansi-language:EN-US'>
style='color:blue'>if( powerupsMask ) {
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> MSG_WriteShort(
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_POWERUPS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( powerupsMask & (1 << i) ) {
style='mso-ansi-language:EN-US'> MSG_WriteLong(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> MSG_WriteBits(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>}
style='mso-ansi-language:EN-US'> |
|
style='color:green;mso-ansi-language:EN-US'>/*
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>MSG_ReadDeltaPlayerstate
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>
style='color:green;mso-ansi-language:EN-US'>============
style='color:green;mso-ansi-language:EN-US'>*/
style='color:blue;mso-ansi-language:EN-US'>void
style='mso-ansi-language:EN-US'> MSG_ReadDeltaPlayerstate( sizebuf_t *msg,
style='color:blue'>const playerState_t *from, playerState_t *to ) {
style='mso-ansi-language:EN-US'> field_t
style='mso-tab-count:1'> *field;
style='mso-ansi-language:EN-US'>
style='color:blue'>int maxFieldNum;
style='mso-ansi-language:EN-US'>
style='color:blue'>int bitmask;
style='mso-ansi-language:EN-US'>
style='color:blue'>int i;
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !to ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return;
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !from ) {
style='mso-ansi-language:EN-US'> memset(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> memcpy(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'> maxFieldNum
style='mso-ansi-language:EN-US'>
style='color:blue'>if( maxFieldNum > psTableSize ) {
style='mso-ansi-language:EN-US'> Com_Error(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0, field=psTable ; i<maxFieldNum ; i++,
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>continue; // field
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:blue'>if( field->bits ) {
style='mso-ansi-language:EN-US'> FIELD_INTEGER(
style='mso-ansi-language:EN-US'>
style='color:blue'>continue;
style='color:green'>// integer value
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> FIELD_FLOAT(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> FIELD_INTEGER(
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>//
style='color:green;mso-ansi-language:EN-US'> //
style='color:green;mso-ansi-language:EN-US'> //
style='mso-ansi-language:EN-US'>
style='color:blue'>if( !MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>return; // no arrays modified
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_STATS
style='mso-ansi-language:EN-US'>
style='color:blue'>if( MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_STATS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bitmask & (1 << i) ) {
style='mso-ansi-language:EN-US'> to->stats[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_PERSISTANT
style='mso-ansi-language:EN-US'>
style='color:blue'>if( MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_PERSISTANT ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bitmask & (1 << i) ) {
style='mso-ansi-language:EN-US'> to->persistant[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_AMMO
style='mso-ansi-language:EN-US'>
style='color:blue'>if( MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_WEAPONS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bitmask & (1 << i) ) {
style='mso-ansi-language:EN-US'> to->ammo[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>
style='mso-ansi-language:EN-US'>
style='color:green'>// PS_POWERUPS
style='mso-ansi-language:EN-US'>
style='color:blue'>if( MSG_ReadBits( msg, 1 ) ) {
style='mso-ansi-language:EN-US'> bitmask
style='mso-ansi-language:EN-US'>
style='color:blue'>for( i=0 ; i<MAX_POWERUPS ; i++ ) {
style='mso-ansi-language:EN-US'>
style='color:blue'>if( bitmask & (1 << i) ) {
style='mso-ansi-language:EN-US'> to->powerups[i]
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'> }
style='mso-ansi-language:EN-US'>} |
7. Huffman encoding
The following routines do Huffman encoding/decoding. Note that you have to do a Huff_Init call before using any MSG_* functions.
//
// huff.c - Huffman compression routines for data bitstream
//
#define VALUE(a) ((int )(a))
#define NODE(a) ((void *)(a))
#define NODE_START NODE( 1)
#define NODE_NONE NODE(256)
#define NODE_NEXT NODE(257)
#define HUFF_TREE_SIZE 7175
typedef void *tree_t[HUFF_TREE_SIZE];
//
// pre-defined frequency counts for all bytes [0..255]
//
static int huffCounts[256] = {
0x3D1CB, 0x0A0E9, 0x01894, 0x01BC2, 0x00E92, 0x00EA6, 0x017DE, 0x05AF3,
0x08225, 0x01B26, 0x01E9E, 0x025F2, 0x02429, 0x0436B, 0x00F6D, 0x006F2,
0x02060, 0x00644, 0x00636, 0x0067F, 0x0044C, 0x004BD, 0x004D6, 0x0046E,
0x006D5, 0x00423, 0x004DE, 0x0047D, 0x004F9, 0x01186, 0x00AF5, 0x00D90,
0x0553B, 0x00487, 0x00686, 0x0042A, 0x00413, 0x003F4, 0x0041D, 0x0042E,
0x006BE, 0x00378, 0x0049C, 0x00352, 0x003C0, 0x0030C, 0x006D8, 0x00CE0,
0x02986, 0x011A2, 0x016F9, 0x00A7D, 0x0122A, 0x00EFD, 0x0082D, 0x0074B,
0x00A18, 0x0079D, 0x007B4, 0x003AC, 0x0046E, 0x006FC, 0x00686, 0x004B6,
0x01657, 0x017F0, 0x01C36, 0x019FE, 0x00E7E, 0x00ED3, 0x005D4, 0x005F4,
0x008A7, 0x00474, 0x0054B, 0x003CB, 0x00884, 0x004E0, 0x00530, 0x004AB,
0x006EA, 0x00436, 0x004F0, 0x004F2, 0x00490, 0x003C5, 0x00483, 0x004A2,
0x00543, 0x004CC, 0x005F9, 0x00640, 0x00A39, 0x00800, 0x009F2, 0x00CCB,
0x0096A, 0x00E01, 0x009C8, 0x00AF0, 0x00A73, 0x01802, 0x00E4F, 0x00B18,
0x037AD, 0x00C5C, 0x008AD, 0x00697, 0x00C88, 0x00AB3, 0x00DB8, 0x012BC,
0x00FFB, 0x00DBB, 0x014A8, 0x00FB0, 0x01F01, 0x0178F, 0x014F0, 0x00F54,
0x0131C, 0x00E9F, 0x011D6, 0x012C7, 0x016DC, 0x01900, 0x01851, 0x02063,
0x05ACB, 0x01E9E, 0x01BA1, 0x022E7, 0x0153D, 0x01183, 0x00E39, 0x01488,
0x014C0, 0x014D0, 0x014FA, 0x00DA4, 0x0099A, 0x0069E, 0x0071D, 0x00849,
0x0077C, 0x0047D, 0x005EC, 0x00557, 0x004D4, 0x00405, 0x004EA, 0x00450,
0x004DD, 0x003EE, 0x0047D, 0x00401, 0x004D9, 0x003B8, 0x00507, 0x003E5,
0x006B1, 0x003F1, 0x004A3, 0x0036F, 0x0044B, 0x003A1, 0x00436, 0x003B7,
0x00678, 0x003A2, 0x00481, 0x00406, 0x004EE, 0x00426, 0x004BE, 0x00424,
0x00655, 0x003A2, 0x00452, 0x00390, 0x0040A, 0x0037C, 0x00486, 0x003DE,
0x00497, 0x00352, 0x00461, 0x00387, 0x0043F, 0x00398, 0x00478, 0x00420,
0x00D86, 0x008C0, 0x0112D, 0x02F68, 0x01E4E, 0x00541, 0x0051B, 0x00CCE,
0x0079E, 0x00376, 0x003FF, 0x00458, 0x00435, 0x00412, 0x00425, 0x0042F,
0x005CC, 0x003E9, 0x00448, 0x00393, 0x0041C, 0x003E3, 0x0042E, 0x0036C,
0x00457, 0x00353, 0x00423, 0x00325, 0x00458, 0x0039B, 0x0044F, 0x00331,
0x0076B, 0x00750, 0x003D0, 0x00349, 0x00467, 0x003BC, 0x00487, 0x003B6,
0x01E6F, 0x003BA, 0x00509, 0x003A5, 0x00467, 0x00C87, 0x003FC, 0x0039F,
0x0054B, 0x00300, 0x00410, 0x002E9, 0x003B8, 0x00325, 0x00431, 0x002E4,
0x003F5, 0x00325, 0x003F0, 0x0031C, 0x003E4, 0x00421, 0x02CC1, 0x034C0
};
//
// static Huffman tree
//
static tree_t huffTree;
//
// received from MSG_* code
//
static int huffBitPos;
/*
======================================================================================
HUFFMAN TREE CONSTRUCTION
======================================================================================
*/
/*
============
Huff_PrepareTree
============
*/
static ID_INLINE void Huff_PrepareTree( tree_t tree ) {
void **node;
memset( tree, 0, sizeof( tree_t ) );
// create first node
node = &tree[263];
VALUE( tree[0] )++;
node[7] = NODE_NONE;
tree[2] = node;
tree[3] = node;
tree[4] = node;
tree[261] = node;
}
/*
============
Huff_GetNode
============
*/
static void **Huff_GetNode( void **tree ) {
void **node;
int value;
node = tree[262];
if( !node ) {
value = VALUE( tree[1] )++;
node = &tree[value + 6407];
return node;
}
tree[262] = node[0];
return node;
}
/*
============
Huff_Swap
============
*/
static void Huff_Swap( void **tree1, void **tree2, void **tree3 ) {
void **a, **b;
a = tree2[2];
if( a ) {
if( a[0] == tree2 ) {
a[0] = tree3;
} else {
a[1] = tree3;
}
} else {
tree1[2] = tree3;
}
b = tree3[2];
if( b ) {
if( b[0] == tree3 ) {
b[0] = tree2;
tree2[2] = b;
tree3[2] = a;
return;
}
b[1] = tree2;
tree2[2] = b;
tree3[2] = a;
return;
}
tree1[2] = tree2;
tree2[2] = NULL;
tree3[2] = a;
}
/*
============
Huff_SwapTrees
============
*/
static void Huff_SwapTrees( void **tree1, void **tree2 ) {
void **temp;
temp = tree1[3];
tree1[3] = tree2[3];
tree2[3] = temp;
temp = tree1[4];
tree1[4] = tree2[4];
tree2[4] = temp;
if( tree1[3] == tree1 ) {
tree1[3] = tree2;
}
if( tree2[3] == tree2 ) {
tree2[3] = tree1;
}
temp = tree1[3];
if( temp ) {
temp[4] = tree1;
}
temp = tree2[3];
if( temp ) {
temp[4] = tree2;
}
temp = tree1[4];
if( temp ) {
temp[3] = tree1;
}
temp = tree2[4];
if( temp ) {
temp[3] = tree2;
}
}
/*
============
Huff_DeleteNode
============
*/
static void Huff_DeleteNode( void **tree1, void **tree2 ) {
tree2[0] = tree1[262];
tree1[262] = tree2;
}
/*
============
Huff_IncrementFreq_r
============
*/
static void Huff_IncrementFreq_r( void **tree1, void **tree2 ) {
void **a, **b;
if( !tree2 ) {
return;
}
a = tree2[3];
if( a && a[6] == tree2[6] ) {
b = tree2[5];
if( b[0] != tree2[2] ) {
Huff_Swap( tree1, b[0], tree2 );
}
Huff_SwapTrees( b[0], tree2 );
}
a = tree2[4];
if( a && a[6] == tree2[6] ) {
b = tree2[5];
b[0] = a;
} else {
a = tree2[5];
a[0] = 0;
Huff_DeleteNode( tree1, tree2[5] );
}
VALUE( tree2[6] )++;
a = tree2[3];
if( a && a[6] == tree2[6] ) {
tree2[5] = a[5];
} else {
a = Huff_GetNode( tree1 );
tree2[5] = a;
a[0] = tree2;
}
if( tree2[2] ) {
Huff_IncrementFreq_r( tree1, tree2[2] );
if( tree2[4] == tree2[2] ) {
Huff_SwapTrees( tree2, tree2[2] );
a = tree2[5];
if( a[0] == tree2 ) {
a[0] = tree2[2];
}
}
}
}
/*
============
Huff_AddReference
Insert 'ch' into the tree or increment it's frequency
============
*/
static void Huff_AddReference( void **tree, int ch ) {
void **a, **b, **c, **d;
int value;
ch &= 255;
if( tree[ch + 5] ) {
Huff_IncrementFreq_r( tree, tree[ch + 5] );
return; // already added
}
value = VALUE( tree[0] )++;
b = &tree[value * 8 + 263];
value = VALUE( tree[0] )++;
a = &tree[value * 8 + 263];
a[7] = NODE_NEXT;
a[6] = NODE_START;
d = tree[3];
a[3] = d[3];
if( a[3] ) {
d = a[3];
d[4] = a;
d = a[3];
if( d[6] == NODE_START ) {
a[5] = d[5];
} else {
d = Huff_GetNode( tree );
a[5] = d;
d[0] = a;
}
} else {
d = Huff_GetNode( tree );
a[5] = d;
d[0] = a;
}
d = tree[3];
d[3] = a;
a[4] = tree[3];
b[7] = NODE( ch );
b[6] = NODE_START;
d = tree[3];
b[3] = d[3];
if( b[3] ) {
d = b[3];
d[4] = b;
if( d[6] == NODE_START ) {
b[5] = d[5];
} else {
d = Huff_GetNode( tree );
b[5] = d;
d[0] = a;
}
} else {
d = Huff_GetNode( tree );
b[5] = d;
d[0] = b;
}
d = tree[3];
d[3] = b;
b[4] = tree[3];
b[1] = NULL;
b[0] = NULL;
d = tree[3];
c = d[2];
if( c ) {
if( c[0] == tree[3] ) {
c[0] = a;
} else {
c[1] = a;
}
} else {
tree[2] = a;
}
a[1] = b;
d = tree[3];
a[0] = d;
a[2] = d[2];
b[2] = a;
d = tree[3];
d[2] = a;
tree[ch + 5] = b;
Huff_IncrementFreq_r( tree, a[2] );
}
/*
======================================================================================
BITSTREAM I/O
======================================================================================
*/
/*
============
Huff_EmitBit
Put one bit into buffer
============
*/
static ID_INLINE void Huff_EmitBit( int bit, byte *buffer ) {
if( !(huffBitPos & 7) ) {
buffer[huffBitPos >> 3] = 0;
}
buffer[huffBitPos >> 3] |= bit << (huffBitPos & 7);
huffBitPos++;
}
/*
============
Huff_GetBit
Read one bit from buffer
============
*/
static ID_INLINE int Huff_GetBit( byte *buffer ) {
int bit;
bit = buffer[huffBitPos >> 3] >> (huffBitPos & 7);
huffBitPos++;
return (bit & 1);
}
/*
============
Huff_EmitPathToByte
============
*/
static ID_INLINE void Huff_EmitPathToByte( void **tree, void **subtree, byte *buffer ) {
if( tree[2] ) {
Huff_EmitPathToByte( tree[2], tree, buffer );
}
if( !subtree ) {
return;
}
//
// emit tree walking control bits
//
if( tree[1] == subtree ) {
Huff_EmitBit( 1, buffer );
} else {
Huff_EmitBit( 0, buffer );
}
}
/*
============
Huff_GetByteFromTree
Get one byte using dynamic or static tree
============
*/
static ID_INLINE int Huff_GetByteFromTree( void **tree, byte *buffer ) {
if( !tree ) {
return 0;
}
//
// walk through the tree until we get a value
//
while( tree[7] == NODE_NEXT ) {
if( !Huff_GetBit( buffer ) ) {
tree = tree[0];
} else {
tree = tree[1];
}
if( !tree ) {
return 0;
}
}
return VALUE( tree[7] );
}
/*
======================================================================================
PUBLIC INTERFACE
======================================================================================
*/
/*
============
Huff_EmitByte
============
*/
void Huff_EmitByte( int ch, byte *buffer, int *count ) {
huffBitPos = *count;
Huff_EmitPathToByte( huffTree[ch + 5], NULL, buffer );
*count = huffBitPos;
}
/*
============
Huff_GetByte
============
*/
int Huff_GetByte( byte *buffer, int *count ) {
int ch;
huffBitPos = *count;
ch = Huff_GetByteFromTree( huffTree[2], buffer );
*count = huffBitPos;
return ch;
}
/*
============
Huff_Init
============
*/
void Huff_Init( void ) {
int i, j;
// build empty tree
Huff_PrepTreeComp( huffTree );
// add all pre-defined byte references
for( i=0 ; i<256 ; i++ ) {
for( j=0 ; j<huffCounts[i] ; j++ ) {
Huff_AddReference( huffTree, i );
}
}
}
8. Server to Client commands
SerVer to Client commands (SVC_*) are hints to the client how to parse data stream received from server. There are 8 SVC_* types, but only 6 of them are used in demo files.
//
// possible server to client commands
//
typedef enum svc_ops_e {
SVC_BAD, // not used in demos
SVC_NOP, // not used in demos
SVC_GAMESTATE,
SVC_CONFIGSTRING, // only inside gameState
SVC_BASELINE, // only inside gameState
SVC_SERVERCOMMAND,
SVC_DOWNLOAD, // not used in demos
SVC_SNAPSHOT,
SVC_EOM
} svc_ops_t;
SVC_BAD – zero command, should never appear in network messages and demos
SVC_NOP – No OPeration command, should never appear in demos
SVC_SERVERCOMMAND – reliable text command to be processed by the client
SVC_DOWNLOAD – should never appear in demos
SVC_SNAPSHOT – contains delta compressed updates of playerState and entityStates
SVC_EOM – indicates End Of Message, also used inside gameState
Each demo message should contain either SVC_GAMESTATE or SVC_SNAPSHOT, but never them both and never no one of them.
9. Operations with gameState_t
#define MAX_CONFIGSTRINGS 1024
// these are the only configstrings that the system reserves, all the
// other ones are strictly for servergame to clientgame communication
#define CS_SERVERINFO 0 // an info string with all the serverinfo cvars
#define CS_SYSTEMINFO 1 // an info string for server system to client system configuration (timescale, etc)
#define RESERVED_CONFIGSTRINGS 2 // game can't modify below this, only the system can
#define MAX_GAMESTATE_CHARS 16000
typedef struct {
int stringOffsets[MAX_CONFIGSTRINGS];
char stringData[MAX_GAMESTATE_CHARS];
int dataCount;
} gameState_t;
gameState_t structure is used to hold all configStrings in a single text buffer. Because configStrings can be up to BIG_INFO_STRING chars, it would be better to use 20100 bytes of gameState_t instead of 8388608 bytes of static array of configStrings.
The following functions allow inserting and fetching configStrings from gameState_t:
/*
============
Com_AppendToGameState
============
*/
static void Com_AppendToGameState( gameState_t *gameState, int index, const char *configString ) {
int len;
if( !configString || !(len=strlen( configString )) ) {
return;
}
if( gameState->dataCount + len + 2 >= MAX_GAMESTATE_CHARS ) {
Com_Error( ERR_DROP, "Com_AppendToGameState: MAX_GAMESTATE_CHARS" );
}
gameState->stringOffsets[index] = gameState->dataCount + 1;
strcpy( &gameState->stringData[gameState->dataCount + 1], configString );
gameState->dataCount += len + 1;
}
/*
============
Com_InsertIntoGameState
============
*/
void Com_InsertIntoGameState( gameState_t *gameState, int index, const char *configString ) {
char *strings[MAX_CONFIGSTRINGS];
int ofs;
int i;
if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
Com_Error( ERR_DROP, "Com_InsertIntoGameState: bad index %i", index );
}
if( !gameState->stringOffsets[index] ) {
// just append to the end of gameState
Com_AppendToGameState( gameState, index, configString );
return;
}
//
// resort gameState
//
for( i=0 ; i<MAX_CONFIGSTRINGS ; i++ ) {
ofs = gameState->stringOffsets[i];
if( !ofs ) {
strings[i] = NULL;
} else if( i == index ) {
strings[i] = CopyString( configString );
} else {
strings[i] = CopyString( &gameState->stringData[ofs] );
}
}
memset( gameState, 0, sizeof( *gameState ) );
for( i=0 ; i<MAX_CONFIGSTRINGS ; i++ ) {
if( strings[i] ) {
Com_AppendToGameState( gameState, i, strings[i] );
Z_Free( strings[i] );
}
}
}
/*
============
Com_GetStringFromGameState
============
*/
char *Com_GetStringFromGameState( gameState_t *gameState, int index ) {
int ofs;
if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
Com_Error( ERR_DROP, "Com_GetStringFromGameState: bad index %i", index );
}
ofs = gameState->stringOffsets[index ];
if( !ofs ) {
return "";
}
return &gameState->stringData[ofs];
}
10. Parsing whole demo file
//
// sizes of misc circular buffers in client and server system
//
// for delta compression of snapshots
#define MAX_SNAPSHOTS 32
#define SNAPSHOT_MASK (MAX_SNAPSHOTS-1)
// for keeping reliable text commands not acknowledged by receiver yet
#define MAX_SERVERCMDS 64
#define SERVERCMD_MASK (MAX_SERVERCMDS-1)
// for keeping all entityStates for delta encoding
#define MAX_PARSE_ENTITIES (MAX_GENTITIES*2)
#define PARSE_ENTITIES_MASK (MAX_PARSE_ENTITIES-1)
//
// max number of entityState_t present in a single update
//
#define MAX_ENTITIES_IN_SNAPSHOT 256
typedef struct {
qboolean valid;
int seq; // die seqeunc number des snapshots
int deltaSeq;
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
int serverTime; // server time the message is valid for (in msec)
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
playerState_t ps; // complete information about the current player at this time
int numEntities; // all of the entities that need to be presented
int firstEntity; // ab dieser Position sind im Ringbuffer die numEntities viele Entities des Snapshots
// ersetzt entities[Max_entities_in snapshot]
} snapshot_t;
typedef struct {
int lastServerCommandNum;
int currentServerCommandNum;
char serverCommands[MAX_SERVERCMDS][MAX_STRING_CHARS];
gameState_t gameState;
entityState_t baselines[MAX_GENTITIES];
entityState_t parseEntities[MAX_PARSE_ENTITIES];
int firstParseEntity;
snapshot_t snapshots[MAX_SNAPSHOTS];
snapshot_t *snap;
} demoState_t;
demoState_t ds;
/*
==================
Parse_GameState
==================
*/
static void Parse_GameState( sizebuf_t *msg ) {
int c;
int index;
char *configString;
memset( &ds, 0, sizeof( ds ) );
ds.lastServerCommandNum = MSG_ReadLong( msg );
ds.currentServerCommandNum = ds.lastServerCommandNum;
while( 1 ) {
c = MSG_ReadByte( msg );
if( c == -1 ) {
Com_Error( ERR_DROP, "Parse_GameState: read past end of demo message" );
}
if( c == SVC_EOM ) {
break;
}
switch( c ) {
default:
Com_Error( ERR_DROP, "Parse_GameState: bad command byte" );
break;
case SVC_CONFIGSTRING:
index = MSG_ReadShort( msg );
if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
Com_Error( ERR_DROP, "Parse_GameState: configString index %i out of range", index );
}
configString = MSG_ReadBigString( msg );
Com_InsertIntoGameState( &ds.gameState, index, configString );
break;
case SVC_BASELINE:
index = MSG_ReadBits( msg, GENTITYNUM_BITS );
if( index < 0 || index >= MAX_GENTITIES ) {
Com_Error( ERR_DROP, "Parse_GameState: baseline index %i out of range", index );
}
MSG_ReadDeltaEntity( msg, NULL, &ds.baselines[index], index );
break;
}
}
// FIXME: unknown stuff, not used in demos?
MSG_ReadLong( msg );
MSG_ReadLong( msg );
demo.gameStatesParsed++;
}
/*
=====================================================================
ACTION MESSAGES
=====================================================================
*/
/*
=====================
Parse_ServerCommand
=====================
*/
static void Parse_ServerCommand( sizebuf_t *msg ) {
int number;
char *string;
number = MSG_ReadLong( msg );
string = MSG_ReadString( msg );
if( number < ds.lastServerCommandNum ) {
return; // we have already received this command
}
ds.lastServerCommandNum = number;
// archive the command to be processed later
Q_strncpyz( ds.serverCommands[number & SERVERCMD_MASK], string, sizeof( ds.serverCommands[0] ) );
}
/*
==================
Parse_DeltaEntity
Parses deltas from the given base and adds the resulting entity
to the current frame
==================
*/
static void Parse_DeltaEntity( sizebuf_t *msg, snapshot_t *frame, int newnum, entityState_t *old, qboolean unchanged ) {
entityState_t *state;
state = &ds.parseEntities[ds.firstParseEntity & PARSE_ENTITIES_MASK];
if( unchanged ) {
memcpy( state, old, sizeof( *state ) ); // don't read any bits
} else {
MSG_ReadDeltaEntity( msg, old, state, newnum );
if( state->number == ENTITYNUM_NONE ) {
// the entity present in oldframe is not in the current frame
return;
}
}
ds.firstParseEntity++;
frame->numEntities++;
}
/*
==================
Parse_PacketEntities
An svc_packetentities has just been parsed, deal with the
rest of the data stream.
==================
*/
static void Parse_PacketEntities( sizebuf_t *msg, snapshot_t *oldframe, snapshot_t *newframe ) {
int newnum;
entityState_t *oldstate;
int oldindex, oldnum;
newframe->firstEntity = ds.firstParseEntity;
newframe->numEntities = 0;
// delta from the entities present in oldframe
oldindex = 0;
if( !oldframe ) {
oldnum = 99999;
} else {
if( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &ds.parseEntities[(oldframe->firstEntity + oldindex) & PARSE_ENTITIES_MASK];
oldnum = oldstate->number;
}
}
while( 1 ) {
newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
if( newnum < 0 || newnum >= MAX_GENTITIES ) {
Com_Error( ERR_DROP, "Parse_PacketEntities: bad number %i", newnum );
}
if( msg->readcount > msg->cursize ) {
Com_Error( ERR_DROP, "Parse_PacketEntities: end of message" );
}
if( newnum == ENTITYNUM_NONE ) {
break; // end of packetentities
}
while( oldnum < newnum ) {
// one or more entities from the old packet are unchanged
Parse_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
oldindex++;
if( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &ds.parseEntities[(oldframe->firstEntity + oldindex) & PARSE_ENTITIES_MASK];
oldnum = oldstate->number;
}
}
if( oldnum == newnum ) {
// delta from previous state
Parse_DeltaEntity( msg, newframe, newnum, oldstate, qfalse );
oldindex++;
if( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &ds.parseEntities[(oldframe->firstEntity + oldindex) & PARSE_ENTITIES_MASK];
oldnum = oldstate->number;
}
continue;
}
if( oldnum > newnum ) {
// delta from baseline
Parse_DeltaEntity( msg, newframe, newnum, &ds.baselines[newnum], qfalse );
}
}
// any remaining entities in the old frame are copied over
while( oldnum != 99999 ) {
// one or more entities from the old packet are unchanged
Parse_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
oldindex++;
if( oldindex >= oldframe->numEntities ) {
oldnum = 99999;
} else {
oldstate = &ds.parseEntities[(oldframe->firstEntity + oldindex) & PARSE_ENTITIES_MASK];
oldnum = oldstate->number;
}
}
}
/*
=====================
ParseSnapshot
=====================
*/
static void Parse_Snapshot( sizebuf_t *msg ) {
snapshot_t *oldsnap;
int delta;
int len;
// save the frame off in the backup array for later delta comparisons
ds.snap = &ds.snapshots[demo.demoMessageSequence & SNAPSHOT_MASK];
memset( ds.snap, 0, sizeof( *ds.snap ) );
ds.snap->seq = demo.demoMessageSequence;
ds.snap->serverTime = MSG_ReadLong( 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
delta = MSG_ReadByte( msg );
if( delta ) {
ds.snap->deltaSeq = demo.demoMessageSequence - delta;
oldsnap = &ds.snapshots[ds.snap->deltaSeq & SNAPSHOT_MASK];
if( !oldsnap->valid ) {
// should never happen
Com_Printf( "Delta from invalid frame (not supposed to happen!).n" );
} else if( oldsnap->seq != ds.snap->deltaSeq ) {
// 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( ds.firstParseEntity - oldsnap->firstEntity > MAX_PARSE_ENTITIES - MAX_ENTITIES_IN_SNAPSHOT) {
Com_Printf( "Delta parse_entities too old.n" );
} else {
ds.snap->valid = qtrue; // valid delta parse
}
} else {
oldsnap = NULL;
ds.snap->deltaSeq = -1;
ds.snap->valid = qtrue; // uncompressed frame
}
// read snapFlags
ds.snap->snapFlags = MSG_ReadByte( msg );
// read areabits
len = MSG_ReadByte( msg );
MSG_ReadData( msg, ds.snap->areamask, len );
// read playerinfo
MSG_ReadDeltaPlayerstate( msg, oldsnap ? &oldsnap->ps : NULL, &ds.snap->ps );
// read packet entities
Parse_PacketEntities( msg, oldsnap, ds.snap );
}
/*
=====================
Parse_DemoMessage
=====================
*/
static void Parse_DemoMessage( sizebuf_t *msg ) {
int cmd;
// remaining data is Huffman compressed
MSG_SetBitstream( msg );
MSG_ReadLong( msg ); // FIXME: not used in demos
//
// parse the message
//
while( 1 ) {
if( msg->readcount > msg->cursize ) {
Com_Error( ERR_DROP, "Parse_DemoMessage: read past end of demo message" );
break;
}
cmd = MSG_ReadByte( msg );
if( cmd == SVC_EOM ) {
break;
}
// other commands
switch( cmd ) {
default:
case SVC_BASELINE:
case SVC_CONFIGSTRING:
case SVC_DOWNLOAD:
Com_Error( ERR_DROP, "Parse_DemoMessage: illegible demo message" );
break;
case SVC_NOP: /* do nothing */ break;
case SVC_GAMESTATE: Parse_GameState( msg ); break;
case SVC_SERVERCOMMAND: Parse_ServerCommand( msg ); break;
case SVC_SNAPSHOT: Parse_Snapshot( msg ); break;
}
}
}
11. Thanks to
- Martin Otten for Argus
- ID Software for releasing Quake II source code and Q3 SDK
Copyright (C) 2003 Andrey Nazarov (skuller-vidnoe@narod.ru)