2005-09-24 04:48:20 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the included ( GNU . txt ) GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2005-09-06 01:09:36 +00:00
# include "qtv.h"
# define ParseError(m) (m)->cursize = (m)->cursize+1 //
void InitNetMsg ( netmsg_t * b , char * buffer , int bufferlength )
{
b - > data = buffer ;
b - > maxsize = bufferlength ;
b - > readpos = 0 ;
b - > cursize = 0 ;
}
//probably not the place for these any more..
unsigned char ReadByte ( netmsg_t * b )
{
if ( b - > readpos > = b - > cursize )
{
b - > readpos = b - > cursize + 1 ;
return 0 ;
}
return b - > data [ b - > readpos + + ] ;
}
unsigned short ReadShort ( netmsg_t * b )
{
int b1 , b2 ;
b1 = ReadByte ( b ) ;
b2 = ReadByte ( b ) ;
return b1 | ( b2 < < 8 ) ;
}
unsigned int ReadLong ( netmsg_t * b )
{
int s1 , s2 ;
s1 = ReadShort ( b ) ;
s2 = ReadShort ( b ) ;
return s1 | ( s2 < < 16 ) ;
}
float ReadFloat ( netmsg_t * b )
{
union {
unsigned int i ;
float f ;
} u ;
u . i = ReadLong ( b ) ;
return u . f ;
}
void ReadString ( netmsg_t * b , char * string , int maxlen )
{
maxlen - - ; //for null terminator
while ( maxlen )
{
* string = ReadByte ( b ) ;
if ( ! * string )
return ;
string + + ;
maxlen - - ;
}
* string + + = ' \0 ' ; //add the null
}
void WriteByte ( netmsg_t * b , unsigned char c )
{
if ( b - > cursize > = b - > maxsize )
return ;
b - > data [ b - > cursize + + ] = c ;
}
void WriteShort ( netmsg_t * b , unsigned short l )
{
WriteByte ( b , ( l & 0x00ff ) > > 0 ) ;
WriteByte ( b , ( l & 0xff00 ) > > 8 ) ;
}
void WriteLong ( netmsg_t * b , unsigned int l )
{
WriteByte ( b , ( l & 0x000000ff ) > > 0 ) ;
WriteByte ( b , ( l & 0x0000ff00 ) > > 8 ) ;
WriteByte ( b , ( l & 0x00ff0000 ) > > 16 ) ;
WriteByte ( b , ( l & 0xff000000 ) > > 24 ) ;
}
void WriteFloat ( netmsg_t * b , float f )
{
union {
unsigned int i ;
float f ;
} u ;
u . f = f ;
WriteLong ( b , u . i ) ;
}
void WriteString2 ( netmsg_t * b , const char * str )
{ //no null terminator, convienience function.
while ( * str )
WriteByte ( b , * str + + ) ;
}
void WriteString ( netmsg_t * b , const char * str )
{
while ( * str )
WriteByte ( b , * str + + ) ;
WriteByte ( b , 0 ) ;
}
void WriteData ( netmsg_t * b , const char * data , int length )
{
int i ;
unsigned char * buf ;
if ( b - > cursize + length > b - > maxsize ) //urm, that's just too big. :(
return ;
buf = b - > data + b - > cursize ;
for ( i = 0 ; i < length ; i + + )
* buf + + = * data + + ;
b - > cursize + = length ;
}
# define DF_ORIGIN 1
# define DF_ANGLES (1<<3)
# define DF_EFFECTS (1<<6)
# define DF_SKINNUM (1<<7)
# define DF_DEAD (1<<8)
# define DF_GIB (1<<9)
# define DF_WEAPONFRAME (1<<10)
# define DF_MODEL (1<<11)
void SendBufferToViewer ( viewer_t * v , const char * buffer , int length , qboolean reliable )
{
if ( reliable )
{
//try and put it in the normal reliable
if ( ! v - > backbuffered & & v - > netchan . message . cursize + length < v - > netchan . message . maxsize )
WriteData ( & v - > netchan . message , buffer , length ) ;
else if ( v - > backbuffered > 0 & & v - > backbuf [ v - > backbuffered - 1 ] . cursize + length < v - > backbuf [ v - > backbuffered - 1 ] . maxsize ) //try and put it in the current backbuffer
WriteData ( & v - > backbuf [ v - > backbuffered - 1 ] , buffer , length ) ;
else if ( v - > backbuffered = = MAX_BACK_BUFFERS )
v - > drop = true ; //we would need too many backbuffers.
else
{
//create a new backbuffer
if ( ! v - > backbuf [ v - > backbuffered ] . data )
{
InitNetMsg ( & v - > backbuf [ v - > backbuffered ] , ( unsigned char * ) malloc ( MAX_BACKBUF_SIZE ) , MAX_BACKBUF_SIZE ) ;
}
v - > backbuf [ v - > backbuffered ] . cursize = 0 ; //make sure it's empty
WriteData ( & v - > backbuf [ v - > backbuffered ] , buffer , length ) ;
v - > backbuffered + + ;
}
}
}
void Multicast ( sv_t * tv , char * buffer , int length , int to , unsigned int playermask )
{
viewer_t * v ;
switch ( to )
{
case dem_multiple :
case dem_single :
case dem_stats :
//check and send to them only if they're tracking this player(s).
2005-10-07 02:02:15 +00:00
for ( v = tv - > cluster - > viewers ; v ; v = v - > next )
2005-09-06 01:09:36 +00:00
{
2005-10-07 02:02:15 +00:00
if ( v - > server = = tv )
if ( v - > trackplayer > = 0 )
if ( ( 1 < < v - > trackplayer ) & playermask )
SendBufferToViewer ( v , buffer , length , true ) ; //FIXME: change the reliable depending on message type
2005-09-06 01:09:36 +00:00
}
break ;
default :
//send to all
2005-10-07 02:02:15 +00:00
for ( v = tv - > cluster - > viewers ; v ; v = v - > next )
2005-09-06 01:09:36 +00:00
{
2005-10-07 02:02:15 +00:00
if ( v - > server = = tv )
SendBufferToViewer ( v , buffer , length , true ) ; //FIXME: change the reliable depending on message type
2005-09-06 01:09:36 +00:00
}
break ;
}
}
2005-10-09 09:40:26 +00:00
void Broadcast ( cluster_t * cluster , char * buffer , int length )
{
viewer_t * v ;
for ( v = cluster - > viewers ; v ; v = v - > next )
{
SendBufferToViewer ( v , buffer , length , true ) ;
}
}
2005-09-06 01:09:36 +00:00
static void ParseServerData ( sv_t * tv , netmsg_t * m , int to , unsigned int playermask )
{
int protocol ;
viewer_t * v ;
2005-09-25 20:50:57 +00:00
2005-09-06 01:09:36 +00:00
protocol = ReadLong ( m ) ;
if ( protocol ! = PROTOCOL_VERSION )
{
ParseError ( m ) ;
return ;
}
tv - > parsingconnectiondata = true ;
ReadLong ( m ) ; //we don't care about server's servercount, it's all reliable data anyway.
ReadString ( m , tv - > gamedir , sizeof ( tv - > gamedir ) ) ;
/*tv->servertime =*/ ReadFloat ( m ) ;
ReadString ( m , tv - > mapname , sizeof ( tv - > mapname ) ) ;
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " Gamedir: %s \n " , tv - > gamedir ) ;
Sys_Printf ( tv - > cluster , " --------------------- \n " ) ;
Sys_Printf ( tv - > cluster , " %s \n " , tv - > mapname ) ;
Sys_Printf ( tv - > cluster , " --------------------- \n " ) ;
2005-09-06 01:09:36 +00:00
// get the movevars
tv - > movevars . gravity = ReadFloat ( m ) ;
tv - > movevars . stopspeed = ReadFloat ( m ) ;
tv - > movevars . maxspeed = ReadFloat ( m ) ;
tv - > movevars . spectatormaxspeed = ReadFloat ( m ) ;
tv - > movevars . accelerate = ReadFloat ( m ) ;
tv - > movevars . airaccelerate = ReadFloat ( m ) ;
tv - > movevars . wateraccelerate = ReadFloat ( m ) ;
tv - > movevars . friction = ReadFloat ( m ) ;
tv - > movevars . waterfriction = ReadFloat ( m ) ;
tv - > movevars . entgrav = ReadFloat ( m ) ;
2005-10-07 02:02:15 +00:00
for ( v = tv - > cluster - > viewers ; v ; v = v - > next )
{
if ( v - > server = = tv )
v - > thinksitsconnected = false ;
}
2005-09-06 01:09:36 +00:00
tv - > maxents = 0 ; //clear these
memset ( tv - > modellist , 0 , sizeof ( tv - > modellist ) ) ;
memset ( tv - > soundlist , 0 , sizeof ( tv - > soundlist ) ) ;
memset ( tv - > lightstyle , 0 , sizeof ( tv - > lightstyle ) ) ;
tv - > staticsound_count = 0 ;
2005-09-24 04:48:20 +00:00
memset ( tv - > staticsound , 0 , sizeof ( tv - > staticsound ) ) ;
memset ( tv - > players , 0 , sizeof ( tv - > players ) ) ;
2005-09-06 01:09:36 +00:00
}
static void ParseCDTrack ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
tv - > cdtrack = ReadByte ( m ) ;
2005-09-24 21:31:01 +00:00
if ( ! tv - > parsingconnectiondata )
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
2005-09-06 01:09:36 +00:00
}
static void ParseStufftext ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
viewer_t * v ;
char text [ 1024 ] ;
2005-09-24 04:48:20 +00:00
char value [ 256 ] ;
qboolean fromproxy ;
2005-09-06 01:09:36 +00:00
ReadString ( m , text , sizeof ( text ) ) ;
if ( ! strcmp ( text , " skins \n " ) )
{
const char newcmd [ 10 ] = { svc_stufftext , ' c ' , ' m ' , ' d ' , ' ' , ' n ' , ' e ' , ' w ' , ' \n ' , ' \0 ' } ;
tv - > parsingconnectiondata = false ;
2005-09-24 04:48:20 +00:00
2005-10-07 02:02:15 +00:00
for ( v = tv - > cluster - > viewers ; v ; v = v - > next )
2005-09-06 01:09:36 +00:00
{
2005-10-07 02:02:15 +00:00
if ( v - > server = = tv )
{
v - > servercount + + ;
SendBufferToViewer ( v , newcmd , sizeof ( newcmd ) , true ) ;
}
2005-09-06 01:09:36 +00:00
}
return ;
}
else if ( ! strncmp ( text , " fullserverinfo " , 15 ) )
{
2005-09-24 04:48:20 +00:00
text [ strlen ( text ) - 1 ] = ' \0 ' ;
text [ strlen ( text ) - 1 ] = ' \0 ' ;
//copy over the server's serverinfo
strncpy ( tv - > serverinfo , text + 16 , sizeof ( tv - > serverinfo ) - 1 ) ;
Info_ValueForKey ( tv - > serverinfo , " *qtv " , value , sizeof ( value ) ) ;
if ( * value )
fromproxy = true ;
else
fromproxy = false ;
//add on our extra infos
Info_SetValueForStarKey ( tv - > serverinfo , " *qtv " , VERSION , sizeof ( tv - > serverinfo ) ) ;
Info_SetValueForStarKey ( tv - > serverinfo , " *z_ext " , Z_EXT_STRING , sizeof ( tv - > serverinfo ) ) ;
//change the hostname (the qtv's hostname with the server's hostname in brackets)
Info_ValueForKey ( tv - > serverinfo , " hostname " , value , sizeof ( value ) ) ;
if ( fromproxy & & strchr ( value , ' ( ' ) & & value [ strlen ( value ) - 1 ] = = ' ) ' ) //already has brackets
{ //the fromproxy check is because it's fairly common to find a qw server with brackets after it's name.
char * s ;
s = strchr ( value , ' ( ' ) ; //so strip the parent proxy's hostname, and put our hostname first, leaving the origional server's hostname within the brackets
2005-10-07 02:02:15 +00:00
snprintf ( text , sizeof ( text ) , " %s %s " , tv - > cluster - > hostname , s ) ;
2005-09-24 04:48:20 +00:00
}
else
{
if ( tv - > file )
2005-10-07 02:02:15 +00:00
snprintf ( text , sizeof ( text ) , " %s (recorded from: %s) " , tv - > cluster - > hostname , value ) ;
2005-09-24 04:48:20 +00:00
else
2005-10-07 02:02:15 +00:00
snprintf ( text , sizeof ( text ) , " %s (live: %s) " , tv - > cluster - > hostname , value ) ;
2005-09-24 04:48:20 +00:00
}
Info_SetValueForStarKey ( tv - > serverinfo , " hostname " , text , sizeof ( tv - > serverinfo ) ) ;
2005-09-06 01:09:36 +00:00
return ;
}
else if ( ! strncmp ( text , " cmd " , 4 ) )
return ; //commands the game server asked for are pointless.
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
2005-10-07 02:02:15 +00:00
static void ParseSetInfo ( sv_t * tv , netmsg_t * m )
{
int pnum ;
char key [ 64 ] ;
char value [ 256 ] ;
pnum = ReadByte ( m ) ;
ReadString ( m , key , sizeof ( key ) ) ;
ReadString ( m , value , sizeof ( value ) ) ;
if ( pnum < MAX_CLIENTS )
Info_SetValueForStarKey ( tv - > players [ pnum ] . userinfo , key , value , sizeof ( tv - > players [ pnum ] . userinfo ) ) ;
if ( ! tv - > parsingconnectiondata )
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , dem_all , ( unsigned ) - 1 ) ;
}
2005-09-06 01:09:36 +00:00
static void ParseServerinfo ( sv_t * tv , netmsg_t * m )
{
char key [ 64 ] ;
2005-09-24 21:31:01 +00:00
char value [ 256 ] ;
2005-09-06 01:09:36 +00:00
ReadString ( m , key , sizeof ( key ) ) ;
ReadString ( m , value , sizeof ( value ) ) ;
2005-09-24 21:31:01 +00:00
if ( strcmp ( key , " hostname " ) ) //don't allow the hostname to change, but allow the server to change other serverinfos.
Info_SetValueForStarKey ( tv - > serverinfo , key , value , sizeof ( tv - > serverinfo ) ) ;
if ( ! tv - > parsingconnectiondata )
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , dem_all , ( unsigned ) - 1 ) ;
2005-09-06 01:09:36 +00:00
}
static void ParsePrint ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
2005-09-24 11:44:26 +00:00
unsigned char * t ;
2005-09-06 01:09:36 +00:00
char text [ 1024 ] ;
int level ;
2005-09-24 11:44:26 +00:00
2005-09-06 01:09:36 +00:00
level = ReadByte ( m ) ;
ReadString ( m , text , sizeof ( text ) ) ;
if ( to = = dem_all | | to = = dem_read )
{
if ( level > 1 )
2005-09-24 11:44:26 +00:00
{
for ( t = ( unsigned char * ) text ; * t ; t + + )
{
2005-09-24 14:50:14 +00:00
if ( * t > = 146 & & * t < 156 )
* t = * t - 146 + ' 0 ' ;
if ( * t = = 143 )
* t = ' . ' ;
if ( * t = = 157 | | * t = = 158 | | * t = = 159 )
* t = ' - ' ;
if ( * t > = 128 )
2005-09-24 11:44:26 +00:00
* t - = 128 ;
if ( * t = = 16 )
* t = ' [ ' ;
2005-09-24 14:50:14 +00:00
if ( * t = = 17 )
* t = ' ] ' ;
2005-10-07 02:02:15 +00:00
if ( * t = = 29 )
* t = ' - ' ;
if ( * t = = 30 )
* t = ' - ' ;
if ( * t = = 31 )
* t = ' - ' ;
2005-09-25 20:50:57 +00:00
if ( * t = = ' \a ' ) //doh. :D
* t = ' ' ;
2005-09-24 11:44:26 +00:00
}
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " %s " , text ) ;
2005-09-24 11:44:26 +00:00
}
2005-09-06 01:09:36 +00:00
}
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseCenterprint ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
char text [ 1024 ] ;
ReadString ( m , text , sizeof ( text ) ) ;
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
2005-09-24 04:48:20 +00:00
static int ParseList ( sv_t * tv , netmsg_t * m , filename_t * list , int to , unsigned int mask )
2005-09-06 01:09:36 +00:00
{
int first ;
first = ReadByte ( m ) + 1 ;
for ( ; first < MAX_LIST ; first + + )
{
ReadString ( m , list [ first ] . name , sizeof ( list [ first ] . name ) ) ;
2005-09-24 04:48:20 +00:00
// printf("read %i: %s\n", first, list[first].name);
2005-09-06 01:09:36 +00:00
if ( ! * list [ first ] . name )
break ;
// printf("%i: %s\n", first, list[first].name);
}
2005-09-24 04:48:20 +00:00
return ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
}
2005-09-24 04:48:20 +00:00
static void ParseEntityState ( entity_state_t * es , netmsg_t * m ) //for baselines/static entities
2005-09-06 01:09:36 +00:00
{
int i ;
2005-09-24 04:48:20 +00:00
es - > modelindex = ReadByte ( m ) ;
es - > frame = ReadByte ( m ) ;
es - > colormap = ReadByte ( m ) ;
es - > skinnum = ReadByte ( m ) ;
for ( i = 0 ; i < 3 ; i + + )
{
es - > origin [ i ] = ReadShort ( m ) ;
es - > angles [ i ] = ReadByte ( m ) ;
}
}
static void ParseBaseline ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
2005-09-06 01:09:36 +00:00
unsigned int entnum ;
entnum = ReadShort ( m ) ;
if ( entnum > = MAX_ENTITIES )
{
ParseError ( m ) ;
return ;
}
2005-09-24 04:48:20 +00:00
ParseEntityState ( & tv - > entity [ entnum ] . baseline , m ) ;
2005-09-06 01:09:36 +00:00
}
static void ParseStaticSound ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
if ( tv - > staticsound_count = = MAX_STATICSOUNDS )
{
2005-09-24 04:48:20 +00:00
tv - > staticsound_count - - ; // don't be fatal.
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " Too many static sounds \n " ) ;
2005-09-06 01:09:36 +00:00
}
tv - > staticsound [ tv - > staticsound_count ] . origin [ 0 ] = ReadShort ( m ) ;
tv - > staticsound [ tv - > staticsound_count ] . origin [ 1 ] = ReadShort ( m ) ;
tv - > staticsound [ tv - > staticsound_count ] . origin [ 2 ] = ReadShort ( m ) ;
tv - > staticsound [ tv - > staticsound_count ] . soundindex = ReadByte ( m ) ;
tv - > staticsound [ tv - > staticsound_count ] . volume = ReadByte ( m ) ;
tv - > staticsound [ tv - > staticsound_count ] . attenuation = ReadByte ( m ) ;
tv - > staticsound_count + + ;
2005-09-24 21:31:01 +00:00
if ( ! tv - > parsingconnectiondata )
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
2005-09-06 01:09:36 +00:00
}
2005-09-24 04:48:20 +00:00
static void ParseIntermission ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadByte ( m ) ;
ReadByte ( m ) ;
ReadByte ( m ) ;
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
void ParseSpawnStatic ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
if ( tv - > spawnstatic_count = = MAX_STATICENTITIES )
{
tv - > spawnstatic_count - - ; // don't be fatal.
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " Too many static entities \n " ) ;
2005-09-24 04:48:20 +00:00
}
ParseEntityState ( & tv - > spawnstatic [ tv - > spawnstatic_count ] , m ) ;
tv - > spawnstatic_count + + ;
2005-09-24 21:31:01 +00:00
if ( ! tv - > parsingconnectiondata )
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
2005-09-24 04:48:20 +00:00
}
2005-10-07 02:02:15 +00:00
static void ParsePlayerInfo ( sv_t * tv , netmsg_t * m , qboolean clearoldplayers )
2005-09-06 01:09:36 +00:00
{
int flags ;
int num ;
int i ;
2005-10-07 02:02:15 +00:00
if ( clearoldplayers )
{
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{ //hide players
//they'll be sent after this packet.
tv - > players [ i ] . active = false ;
}
}
2005-09-06 01:09:36 +00:00
num = ReadByte ( m ) ;
if ( num > = MAX_CLIENTS )
{
num = 0 ; // don't be fatal.
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " Too many svc_playerinfos, wrapping \n " ) ;
2005-09-06 01:09:36 +00:00
}
tv - > players [ num ] . old = tv - > players [ num ] . current ;
flags = ReadShort ( m ) ;
tv - > players [ num ] . gibbed = ! ! ( flags & DF_GIB ) ;
tv - > players [ num ] . dead = ! ! ( flags & DF_DEAD ) ;
tv - > players [ num ] . current . frame = ReadByte ( m ) ;
for ( i = 0 ; i < 3 ; i + + )
{
if ( flags & ( DF_ORIGIN < < i ) )
tv - > players [ num ] . current . origin [ i ] = ReadShort ( m ) ;
}
for ( i = 0 ; i < 3 ; i + + )
{
if ( flags & ( DF_ANGLES < < i ) )
{
tv - > players [ num ] . current . angles [ i ] = ReadShort ( m ) ;
}
}
if ( flags & DF_MODEL )
tv - > players [ num ] . current . modelindex = ReadByte ( m ) ;
if ( flags & DF_SKINNUM )
tv - > players [ num ] . current . skinnum = ReadByte ( m ) ;
if ( flags & DF_EFFECTS )
tv - > players [ num ] . current . effects = ReadByte ( m ) ;
if ( flags & DF_WEAPONFRAME )
tv - > players [ num ] . current . weaponframe = ReadByte ( m ) ;
tv - > players [ num ] . active = true ;
2005-09-24 04:48:20 +00:00
2005-09-25 20:50:57 +00:00
tv - > players [ num ] . leafcount = BSP_SphereLeafNums ( tv - > bsp , MAX_ENTITY_LEAFS , tv - > players [ num ] . leafs ,
2005-09-24 04:48:20 +00:00
tv - > players [ num ] . current . origin [ 0 ] / 8.0f ,
tv - > players [ num ] . current . origin [ 1 ] / 8.0f ,
tv - > players [ num ] . current . origin [ 2 ] / 8.0f , 32 ) ;
2005-09-06 01:09:36 +00:00
}
static void FlushPacketEntities ( sv_t * tv )
{
int i ;
for ( i = 0 ; i < MAX_ENTITIES ; i + + )
2005-09-24 04:48:20 +00:00
tv - > entity [ i ] . current . modelindex = 0 ;
2005-09-06 01:09:36 +00:00
}
static void ParsePacketEntities ( sv_t * tv , netmsg_t * m )
{
int entnum ;
int flags ;
2005-09-24 04:48:20 +00:00
qboolean forcerelink ;
2005-09-06 01:09:36 +00:00
viewer_t * v ;
2005-09-24 04:48:20 +00:00
tv - > physicstime = tv - > parsetime ;
2005-10-07 02:02:15 +00:00
if ( tv - > cluster - > chokeonnotupdated )
for ( v = tv - > cluster - > viewers ; v ; v = v - > next )
2005-09-06 01:09:36 +00:00
{
2005-10-07 02:02:15 +00:00
if ( v - > server = = tv )
v - > chokeme = false ;
2005-09-06 01:09:36 +00:00
}
//luckilly, only updated entities are here, so that keeps cpu time down a bit.
for ( ; ; )
{
flags = ReadShort ( m ) ;
if ( ! flags )
break ;
entnum = flags & 511 ;
if ( tv - > maxents < entnum )
tv - > maxents = entnum ;
flags & = ~ 511 ;
2005-09-24 04:48:20 +00:00
memcpy ( & tv - > entity [ entnum ] . old , & tv - > entity [ entnum ] . current , sizeof ( entity_state_t ) ) ; //ow.
2005-09-06 01:09:36 +00:00
if ( flags & U_REMOVE )
{
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . modelindex = 0 ;
2005-09-06 01:09:36 +00:00
continue ;
}
2005-09-24 04:48:20 +00:00
if ( ! tv - > entity [ entnum ] . current . modelindex ) //lerp from baseline
{
memcpy ( & tv - > entity [ entnum ] . current , & tv - > entity [ entnum ] . baseline , sizeof ( entity_state_t ) ) ;
forcerelink = true ;
}
else
forcerelink = false ;
2005-09-06 01:09:36 +00:00
if ( flags & U_MOREBITS )
flags | = ReadByte ( m ) ;
if ( flags & U_MODEL )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . modelindex = ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_FRAME )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . frame = ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_COLORMAP )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . colormap = ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_SKIN )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . skinnum = ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_EFFECTS )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . effects = ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_ORIGIN1 )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . origin [ 0 ] = ReadShort ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_ANGLE1 )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . angles [ 0 ] = ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_ORIGIN2 )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . origin [ 1 ] = ReadShort ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_ANGLE2 )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . angles [ 1 ] = ReadByte ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_ORIGIN3 )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . origin [ 2 ] = ReadShort ( m ) ;
2005-09-06 01:09:36 +00:00
if ( flags & U_ANGLE3 )
2005-09-24 04:48:20 +00:00
tv - > entity [ entnum ] . current . angles [ 2 ] = ReadByte ( m ) ;
tv - > entity [ entnum ] . updatetime = tv - > curtime ;
if ( ! tv - > entity [ entnum ] . old . modelindex ) //no old state
memcpy ( & tv - > entity [ entnum ] . old , & tv - > entity [ entnum ] . current , sizeof ( entity_state_t ) ) ; //copy the new to the old, so we don't end up with interpolation glitches
2005-09-06 01:09:36 +00:00
2005-09-24 04:48:20 +00:00
if ( ( flags & ( U_ORIGIN1 | U_ORIGIN2 | U_ORIGIN3 ) ) | | forcerelink )
tv - > entity [ entnum ] . leafcount = BSP_SphereLeafNums ( tv - > bsp , MAX_ENTITY_LEAFS , tv - > entity [ entnum ] . leafs ,
tv - > entity [ entnum ] . current . origin [ 0 ] / 8.0f ,
tv - > entity [ entnum ] . current . origin [ 1 ] / 8.0f ,
tv - > entity [ entnum ] . current . origin [ 2 ] / 8.0f , 32 ) ;
2005-09-06 01:09:36 +00:00
}
}
static void ParseUpdatePing ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
int pnum ;
int ping ;
pnum = ReadByte ( m ) ;
ping = ReadShort ( m ) ;
2005-09-24 21:31:01 +00:00
if ( pnum < MAX_CLIENTS )
tv - > players [ pnum ] . ping = ping ;
else
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_updateping: invalid player number \n " ) ;
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseUpdateFrags ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
int pnum ;
int frags ;
pnum = ReadByte ( m ) ;
frags = ReadShort ( m ) ;
2005-09-24 21:31:01 +00:00
if ( pnum < MAX_CLIENTS )
tv - > players [ pnum ] . frags = frags ;
else
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_updatefrags: invalid player number \n " ) ;
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseUpdateStat ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
unsigned int pnum ;
int value ;
int statnum ;
statnum = ReadByte ( m ) ;
value = ReadByte ( m ) ;
2005-09-24 21:31:01 +00:00
if ( statnum < MAX_STATS )
2005-09-06 01:09:36 +00:00
{
2005-09-24 21:31:01 +00:00
for ( pnum = 0 ; pnum < MAX_CLIENTS ; pnum + + )
{
if ( mask & ( 1 < < pnum ) )
tv - > players [ pnum ] . stats [ statnum ] = value ;
}
2005-09-06 01:09:36 +00:00
}
2005-09-24 21:31:01 +00:00
else
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_updatestat: invalid stat number \n " ) ;
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseUpdateStatLong ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
unsigned int pnum ;
int value ;
int statnum ;
statnum = ReadByte ( m ) ;
value = ReadLong ( m ) ;
2005-09-24 21:31:01 +00:00
if ( statnum < MAX_STATS )
2005-09-06 01:09:36 +00:00
{
2005-09-24 21:31:01 +00:00
for ( pnum = 0 ; pnum < MAX_CLIENTS ; pnum + + )
{
if ( mask & ( 1 < < pnum ) )
tv - > players [ pnum ] . stats [ statnum ] = value ;
}
2005-09-06 01:09:36 +00:00
}
2005-09-24 21:31:01 +00:00
else
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_updatestatlong: invalid stat number \n " ) ;
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseUpdateUserinfo ( sv_t * tv , netmsg_t * m )
{
int pnum ;
pnum = ReadByte ( m ) ;
ReadLong ( m ) ;
2005-09-24 21:31:01 +00:00
if ( pnum < MAX_CLIENTS )
ReadString ( m , tv - > players [ pnum ] . userinfo , sizeof ( tv - > players [ pnum ] . userinfo ) ) ;
else
{
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_updateuserinfo: invalid player number \n " ) ;
2005-09-24 21:31:01 +00:00
while ( ReadByte ( m ) ) //suck out the message.
{
}
}
2005-09-06 01:09:36 +00:00
}
static void ParsePacketloss ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
unsigned int pnum ;
int value ;
pnum = ReadByte ( m ) % MAX_CLIENTS ;
value = ReadByte ( m ) ;
2005-09-24 21:31:01 +00:00
if ( pnum < MAX_CLIENTS )
tv - > players [ pnum ] . packetloss = value ;
else
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_updatepl: invalid player number \n " ) ;
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseUpdateEnterTime ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
unsigned int pnum ;
float value ;
pnum = ReadByte ( m ) % MAX_CLIENTS ;
value = ReadFloat ( m ) ;
2005-09-24 21:31:01 +00:00
if ( pnum < MAX_CLIENTS )
tv - > players [ pnum ] . entertime = value ;
else
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_updateentertime: invalid player number \n " ) ;
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseSound ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
# define SND_VOLUME (1<<15) // a qbyte
# define SND_ATTENUATION (1<<14) // a qbyte
# define DEFAULT_SOUND_PACKET_VOLUME 255
# define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
int i ;
unsigned short chan ;
unsigned char vol ;
unsigned char atten ;
unsigned char sound_num ;
short org [ 3 ] ;
2005-09-25 20:50:57 +00:00
chan = ReadShort ( m ) ;
2005-09-06 01:09:36 +00:00
if ( chan & SND_VOLUME )
vol = ReadByte ( m ) ;
else
vol = DEFAULT_SOUND_PACKET_VOLUME ;
2005-09-25 20:50:57 +00:00
2005-09-06 01:09:36 +00:00
if ( chan & SND_ATTENUATION )
atten = ReadByte ( m ) / 64.0 ;
else
atten = DEFAULT_SOUND_PACKET_ATTENUATION ;
2005-09-25 20:50:57 +00:00
2005-09-06 01:09:36 +00:00
sound_num = ReadByte ( m ) ;
for ( i = 0 ; i < 3 ; i + + )
org [ i ] = ReadShort ( m ) ;
2005-09-25 20:50:57 +00:00
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
static void ParseDamage ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
ReadByte ( m ) ;
ReadByte ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
enum {
TE_SPIKE = 0 ,
TE_SUPERSPIKE = 1 ,
TE_GUNSHOT = 2 ,
TE_EXPLOSION = 3 ,
TE_TAREXPLOSION = 4 ,
TE_LIGHTNING1 = 5 ,
TE_LIGHTNING2 = 6 ,
TE_WIZSPIKE = 7 ,
TE_KNIGHTSPIKE = 8 ,
TE_LIGHTNING3 = 9 ,
TE_LAVASPLASH = 10 ,
TE_TELEPORT = 11 ,
TE_BLOOD = 12 ,
TE_LIGHTNINGBLOOD = 13 ,
} ;
static void ParseTempEntity ( sv_t * tv , netmsg_t * m , int to , unsigned int mask )
{
int i ;
i = ReadByte ( m ) ;
switch ( i )
{
case TE_SPIKE :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_SUPERSPIKE :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_GUNSHOT :
ReadByte ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_EXPLOSION :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_TAREXPLOSION :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_LIGHTNING1 :
case TE_LIGHTNING2 :
case TE_LIGHTNING3 :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_WIZSPIKE :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_KNIGHTSPIKE :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_LAVASPLASH :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_TELEPORT :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_BLOOD :
ReadByte ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
case TE_LIGHTNINGBLOOD :
ReadShort ( m ) ;
ReadShort ( m ) ;
ReadShort ( m ) ;
break ;
default :
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " temp entity %i not recognised \n " , i ) ;
2005-09-06 01:09:36 +00:00
return ;
}
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , to , mask ) ;
}
void ParseLightstyle ( sv_t * tv , netmsg_t * m )
{
int style ;
style = ReadByte ( m ) ;
2005-09-24 21:31:01 +00:00
if ( style < MAX_LIGHTSTYLES )
ReadString ( m , tv - > lightstyle [ style ] . name , sizeof ( tv - > lightstyle [ style ] . name ) ) ;
else
{
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " svc_lightstyle: invalid lightstyle index (%i) \n " , style ) ;
2005-09-24 21:31:01 +00:00
while ( ReadByte ( m ) ) //suck out the message.
{
}
}
2005-09-06 01:09:36 +00:00
Multicast ( tv , m - > data + m - > startpos , m - > readpos - m - > startpos , dem_read , ( unsigned ) - 1 ) ;
}
void ParseMessage ( sv_t * tv , char * buffer , int length , int to , int mask )
{
netmsg_t buf ;
2005-10-07 02:02:15 +00:00
qboolean clearoldplayers = true ;
2005-09-06 01:09:36 +00:00
buf . cursize = length ;
buf . maxsize = length ;
buf . readpos = 0 ;
buf . data = buffer ;
buf . startpos = 0 ;
while ( buf . readpos < buf . cursize )
{
if ( buf . readpos > buf . cursize )
{
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " Read past end of parse buffer \n " ) ;
2005-09-06 01:09:36 +00:00
return ;
}
// printf("%i\n", buf.buffer[0]);
buf . startpos = buf . readpos ;
switch ( ReadByte ( & buf ) )
{
case svc_bad :
ParseError ( & buf ) ;
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " ParseMessage: svc_bad \n " ) ;
2005-09-06 01:09:36 +00:00
return ;
case svc_nop : //quakeworld isn't meant to send these.
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " nop \n " ) ;
2005-09-06 01:09:36 +00:00
break ;
2005-09-24 04:48:20 +00:00
case svc_disconnect :
2005-09-24 21:31:01 +00:00
//mvdsv safely terminates it's mvds with an svc_disconnect.
//the client is meant to read that and disconnect without reading the intentionally corrupt packet following it.
//however, our demo playback is chained and looping and buffered.
//so we've already found the end of the source file and restarted parsing.
//so there's very little we can do except crash ourselves on the EndOfDemo text following the svc_disconnect
//that's a bad plan, so just stop reading this packet.
return ;
2005-09-06 01:09:36 +00:00
case svc_updatestat :
ParseUpdateStat ( tv , & buf , to , mask ) ;
break ;
//#define svc_version 4 // [long] server version
//#define svc_setview 5 // [short] entity number
case svc_sound :
ParseSound ( tv , & buf , to , mask ) ;
break ;
//#define svc_time 7 // [float] server time
case svc_print :
ParsePrint ( tv , & buf , to , mask ) ;
break ;
case svc_stufftext :
ParseStufftext ( tv , & buf , to , mask ) ;
break ;
case svc_setangle :
ReadByte ( & buf ) ;
ReadByte ( & buf ) ;
ReadByte ( & buf ) ;
ReadByte ( & buf ) ;
break ;
case svc_serverdata :
ParseServerData ( tv , & buf , to , mask ) ;
break ;
case svc_lightstyle :
ParseLightstyle ( tv , & buf ) ;
break ;
//#define svc_updatename 13 // [qbyte] [string]
case svc_updatefrags :
ParseUpdateFrags ( tv , & buf , to , mask ) ;
break ;
//#define svc_clientdata 15 // <shortbits + data>
//#define svc_stopsound 16 // <see code>
//#define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte]
//#define svc_particle 18 // [vec3] <variable>
case svc_damage :
ParseDamage ( tv , & buf , to , mask ) ;
break ;
2005-09-25 20:50:57 +00:00
2005-09-24 04:48:20 +00:00
case svc_spawnstatic :
ParseSpawnStatic ( tv , & buf , to , mask ) ;
break ;
2005-09-06 01:09:36 +00:00
//#define svc_spawnstatic2 21
case svc_spawnbaseline :
ParseBaseline ( tv , & buf , to , mask ) ;
break ;
2005-09-25 20:50:57 +00:00
2005-09-06 01:09:36 +00:00
case svc_temp_entity :
ParseTempEntity ( tv , & buf , to , mask ) ;
break ;
//#define svc_setpause 24 // [qbyte] on / off
//#define svc_signonnum 25 // [qbyte] used for the signon sequence
case svc_centerprint :
ParseCenterprint ( tv , & buf , to , mask ) ;
break ;
//#define svc_killedmonster 27
//#define svc_foundsecret 28
case svc_spawnstaticsound :
ParseStaticSound ( tv , & buf , to , mask ) ;
break ;
2005-09-24 04:48:20 +00:00
case svc_intermission :
ParseIntermission ( tv , & buf , to , mask ) ;
break ;
2005-09-06 01:09:36 +00:00
//#define svc_finale 31 // [string] text
case svc_cdtrack :
ParseCDTrack ( tv , & buf , to , mask ) ;
break ;
//#define svc_sellscreen 33
//#define svc_cutscene 34 //hmm... nq only... added after qw tree splitt?
case svc_smallkick :
case svc_bigkick :
Multicast ( tv , buf . data + buf . startpos , buf . readpos - buf . startpos , to , mask ) ;
break ;
case svc_updateping :
ParseUpdatePing ( tv , & buf , to , mask ) ;
break ;
case svc_updateentertime :
ParseUpdateEnterTime ( tv , & buf , to , mask ) ;
break ;
case svc_updatestatlong :
ParseUpdateStatLong ( tv , & buf , to , mask ) ;
break ;
case svc_muzzleflash :
ReadShort ( & buf ) ;
Multicast ( tv , buf . data + buf . startpos , buf . readpos - buf . startpos , to , mask ) ;
break ;
case svc_updateuserinfo :
ParseUpdateUserinfo ( tv , & buf ) ;
break ;
//#define svc_download 41 // [short] size [size bytes]
case svc_playerinfo :
2005-10-07 02:02:15 +00:00
ParsePlayerInfo ( tv , & buf , clearoldplayers ) ;
clearoldplayers = false ;
2005-09-06 01:09:36 +00:00
break ;
2005-09-25 20:50:57 +00:00
//#define svc_nails 43 // [qbyte] num [48 bits] xyzpy 12 12 12 4 8
2005-09-06 01:09:36 +00:00
case svc_chokecount :
ReadByte ( & buf ) ;
break ;
case svc_modellist :
2005-09-24 04:48:20 +00:00
if ( ! ParseList ( tv , & buf , tv - > modellist , to , mask ) )
{
int i ;
if ( tv - > bsp )
BSP_Free ( tv - > bsp ) ;
2005-10-07 02:02:15 +00:00
if ( tv - > cluster - > nobsp )
2005-09-24 04:48:20 +00:00
tv - > bsp = NULL ;
else
2005-10-07 02:02:15 +00:00
tv - > bsp = BSP_LoadModel ( tv - > cluster , tv - > gamedir , tv - > modellist [ 1 ] . name ) ;
2005-09-24 04:48:20 +00:00
tv - > numinlines = 0 ;
for ( i = 2 ; i < 256 ; i + + )
{
if ( * tv - > modellist [ i ] . name ! = ' * ' )
break ;
tv - > numinlines = i ;
}
}
2005-09-06 01:09:36 +00:00
break ;
case svc_soundlist :
ParseList ( tv , & buf , tv - > soundlist , to , mask ) ;
break ;
case svc_packetentities :
FlushPacketEntities ( tv ) ;
ParsePacketEntities ( tv , & buf ) ;
break ;
case svc_deltapacketentities :
ReadByte ( & buf ) ;
ParsePacketEntities ( tv , & buf ) ;
break ;
//#define svc_maxspeed 49 // maxspeed change, for prediction
//#define svc_entgravity 50 // gravity change, for prediction
2005-10-07 02:02:15 +00:00
case svc_setinfo :
ParseSetInfo ( tv , & buf ) ;
break ;
2005-09-06 01:09:36 +00:00
case svc_serverinfo :
ParseServerinfo ( tv , & buf ) ;
break ;
case svc_updatepl :
ParsePacketloss ( tv , & buf , to , mask ) ;
break ;
2005-09-25 20:50:57 +00:00
//#define svc_nails2 54 //qwe - [qbyte] num [52 bits] nxyzpy 8 12 12 12 4 8
2005-09-06 01:09:36 +00:00
default :
buf . readpos = buf . startpos ;
2005-10-07 02:02:15 +00:00
Sys_Printf ( tv - > cluster , " Can't handle svc %i \n " , ( unsigned int ) ReadByte ( & buf ) ) ;
2005-09-06 01:09:36 +00:00
return ;
}
}
}