This prepares for moving the net_svc code to a branch allowing both network

code cleanups and general performance work to be developed in relative peace.
While cleaning up the networking code /is/ important, fixing QF's perfomance
issues is of much higher priority.
This commit is contained in:
Bill Currie 2001-11-07 08:24:56 +00:00
parent f60c39e0bc
commit c5aec15569
25 changed files with 1371 additions and 1507 deletions

View file

@ -62,10 +62,11 @@
#define MAX_LIGHTSTYLES 64 #define MAX_LIGHTSTYLES 64
#define MAX_MODELS 256 // these are sent over the net as bytes #define MAX_MODELS 256 // these are sent over the net as bytes
#define MAX_SOUNDS 256 // so they cannot be blindly increased #define MAX_SOUNDS 256 // so they cannot be blindly increased
#define MAX_PROJECTILES 32
#define SAVEGAME_COMMENT_LENGTH 39 #define SAVEGAME_COMMENT_LENGTH 39
#define MAX_STYLESTRING 64
// //
// stats are integers communicated to the client by the server // stats are integers communicated to the client by the server
// //

View file

@ -36,8 +36,7 @@ void CL_SetUpPlayerPrediction(qboolean dopred);
void CL_EmitEntities (void); void CL_EmitEntities (void);
void CL_ClearProjectiles (void); void CL_ClearProjectiles (void);
void CL_ParseProjectiles (void); void CL_ParseProjectiles (void);
void CL_ParsePacketEntities (void); void CL_ParsePacketEntities (qboolean delta);
void CL_ParseDeltaPacketEntities ();
void CL_SetSolidEntities (void); void CL_SetSolidEntities (void);
void CL_ParsePlayerinfo (void); void CL_ParsePlayerinfo (void);
void CL_Ents_Init (void); void CL_Ents_Init (void);

View file

@ -338,7 +338,7 @@ void CL_UpdateScreen (double realtime);
void CL_SetState (cactive_t state); void CL_SetState (cactive_t state);
void CL_ParseDamage (void); void V_ParseDamage (void);
void V_PrepBlend (void); void V_PrepBlend (void);

View file

@ -60,7 +60,6 @@ void Host_InitCommands (void);
void Host_Init (void); void Host_Init (void);
void Host_Shutdown(void); void Host_Shutdown(void);
void Host_Error (const char *error, ...) __attribute__((format(printf,1,2))); void Host_Error (const char *error, ...) __attribute__((format(printf,1,2)));
void Host_NetError (const char *error, ...) __attribute((format(printf,1,2)));
void Host_EndGame (const char *message, ...) __attribute__((format(printf,1,2))); void Host_EndGame (const char *message, ...) __attribute__((format(printf,1,2)));
void Host_Frame (float time); void Host_Frame (float time);
void Host_Quit_f (void); void Host_Quit_f (void);

View file

@ -138,8 +138,6 @@ int Net_Log_Init (const char **sound_precache);
void Log_Incoming_Packet (const char *p, int len); void Log_Incoming_Packet (const char *p, int len);
void Log_Outgoing_Packet (const char *p, int len); void Log_Outgoing_Packet (const char *p, int len);
void Net_LogStop (void); void Net_LogStop (void);
void Analyze_Server_Packet (const byte *data, int len);
void Analyze_Client_Packet (const byte *data, int len);
extern struct cvar_s *net_packetlog; extern struct cvar_s *net_packetlog;

View file

@ -214,22 +214,6 @@
#define U_UNUSED30 (1<<30) // future expansion #define U_UNUSED30 (1<<30) // future expansion
#define U_EXTEND3 (1<<31) // another byte to follow, future expansion #define U_EXTEND3 (1<<31) // another byte to follow, future expansion
#define U_GROUP_ORIG (U_ORIGIN1 | U_ORIGIN2 | U_ORIGIN3 | \
U_ANGLE2 | U_FRAME | U_REMOVE | U_MOREBITS)
#define U_GROUP_MOREBITS (U_ANGLE1 | U_ANGLE3 | U_MODEL | \
U_COLORMAP | U_SKIN | U_EFFECTS | \
U_SOLID | U_EXTEND1)
#define U_GROUP_EXTEND1 (U_ALPHA | U_SCALE | U_EFFECTS2 | \
U_GLOWSIZE | U_GLOWCOLOR | U_COLORMOD | \
U_EXTEND2)
#define U_GROUP_EXTEND2 (U_GLOWTRAIL | U_VIEWMODEL | U_FRAME2)
// I skip the UNUSED and EXTEND3 bits because although they exist in
// QSG2, they're not usable
#define U_VERSION_ID ((U_GROUP_ORIG | U_GROUP_MOREBITS) & ~U_EXTEND1)
#define U_VERSION_QSG2 (U_VERSION_ID | U_EXTEND1 | U_GROUP_EXTEND1 | \
U_GROUP_EFFECTS2)
//============================================== //==============================================
// a sound with no channel is a local only sound // a sound with no channel is a local only sound

View file

@ -499,7 +499,7 @@ void SV_SendClientMessages (void);
void SV_Multicast (vec3_t origin, int to); void SV_Multicast (vec3_t origin, int to);
void SV_StartSound (struct edict_s *entity, int channel, const char *sample, void SV_StartSound (struct edict_s *entity, int channel, const char *sample,
float volume, float attenuation); int volume, float attenuation);
void SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...) __attribute__((format(printf,3,4))); void SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...) __attribute__((format(printf,3,4)));
void SV_BroadcastPrintf (int level, const char *fmt, ...) __attribute__((format(printf,2,3))); void SV_BroadcastPrintf (int level, const char *fmt, ...) __attribute__((format(printf,2,3)));
void SV_BroadcastCommand (const char *fmt, ...) __attribute__((format(printf,1,2))); void SV_BroadcastCommand (const char *fmt, ...) __attribute__((format(printf,1,2)));

View file

@ -52,7 +52,7 @@ libasm_la_SOURCES= $(asm_src)
noinst_LTLIBRARIES= libqfnet.la $(asm) noinst_LTLIBRARIES= libqfnet.la $(asm)
common_sources= buildnum.c com.c game.c msg_ucmd.c pmove.c pmovetst.c \ common_sources= buildnum.c com.c game.c msg_ucmd.c pmove.c pmovetst.c \
net_packetlog.c net_svc.c net_packetlog.c
common_ldflags= -export-dynamic common_ldflags= -export-dynamic

View file

@ -265,7 +265,7 @@ CL_GetDemoMessage (void)
(net_message->message->cursize); (net_message->message->cursize);
// Con_Printf("read: %ld bytes\n", net_message->message->cursize); // Con_Printf("read: %ld bytes\n", net_message->message->cursize);
if (net_message->message->cursize > MAX_MSGLEN + 8) //+8 for header if (net_message->message->cursize > MAX_MSGLEN + 8) //+8 for header
Host_Error ("Demo message > MAX_MSGLEN + 8: %d/%d", Host_EndGame ("Demo message > MAX_MSGLEN + 8: %d/%d",
net_message->message->cursize, MAX_MSGLEN + 8); net_message->message->cursize, MAX_MSGLEN + 8);
r = Qread (cls.demofile, net_message->message->data, r = Qread (cls.demofile, net_message->message->data,
net_message->message->cursize); net_message->message->cursize);

View file

@ -43,7 +43,6 @@ static const char rcsid[] =
#include "QF/render.h" #include "QF/render.h"
#include "QF/skin.h" #include "QF/skin.h"
#include "bothdefs.h"
#include "cl_cam.h" #include "cl_cam.h"
#include "cl_ents.h" #include "cl_ents.h"
#include "cl_main.h" #include "cl_main.h"
@ -54,7 +53,6 @@ static const char rcsid[] =
#include "d_iface.h" #include "d_iface.h"
#include "host.h" #include "host.h"
#include "msg_ucmd.h" #include "msg_ucmd.h"
#include "net_svc.h"
#include "pmove.h" #include "pmove.h"
#include "r_cvar.h" #include "r_cvar.h"
#include "r_dynamic.h" #include "r_dynamic.h"
@ -71,7 +69,6 @@ entity_t cl_flag_ents[MAX_CLIENTS];
entity_t cl_player_ents[MAX_CLIENTS]; entity_t cl_player_ents[MAX_CLIENTS];
void void
CL_ClearEnts () CL_ClearEnts ()
{ {
@ -127,168 +124,221 @@ CL_NewDlight (int key, vec3_t org, int effects)
int bitcounts[32]; // / just for protocol profiling int bitcounts[32]; // / just for protocol profiling
/*
CL_ParseDelta
Can go from either a baseline or a previous packet_entity
*/
void void
CL_EntityState_Copy (entity_state_t *src, entity_state_t *dest, int bits) CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits)
{ {
int i;
// set everything to the state we are delta'ing from
*to = *from;
to->number = bits & 511;
bits &= ~511;
if (bits & U_MOREBITS) { // read in the low order bits
i = MSG_ReadByte (net_message);
bits |= i;
}
// count the bits for net profiling
// for (i=0 ; i<16 ; i++)
// if (bits&(1<<i))
// bitcounts[i]++;
// LordHavoc: Endy neglected to mark this as being part of the QSG
// version 2 stuff...
if (bits & U_EXTEND1) {
bits |= MSG_ReadByte (net_message) << 16;
if (bits & U_EXTEND2)
bits |= MSG_ReadByte (net_message) << 24;
}
to->flags = bits;
if (bits & U_MODEL) if (bits & U_MODEL)
dest->modelindex = src->modelindex; to->modelindex = MSG_ReadByte (net_message);
if (bits & U_FRAME) if (bits & U_FRAME)
dest->frame = (dest->frame & 0xFF00) | (src->frame & 0xFF); to->frame = MSG_ReadByte (net_message);
if (bits & U_COLORMAP) if (bits & U_COLORMAP)
dest->colormap = src->colormap; to->colormap = MSG_ReadByte (net_message);
if (bits & U_SKIN) if (bits & U_SKIN)
dest->skinnum = src->skinnum; to->skinnum = MSG_ReadByte (net_message);
if (bits & U_EFFECTS) if (bits & U_EFFECTS)
dest->effects = (dest->effects & 0xFF00) | (src->effects & 0xFF); to->effects = MSG_ReadByte (net_message);
if (bits & U_ORIGIN1) if (bits & U_ORIGIN1)
dest->origin[0] = src->origin[0]; to->origin[0] = MSG_ReadCoord (net_message);
if (bits & U_ANGLE1)
dest->angles[0] = src->angles[0];
if (bits & U_ORIGIN2)
dest->origin[1] = src->origin[1];
if (bits & U_ANGLE2)
dest->angles[1] = src->angles[1];
if (bits & U_ORIGIN3)
dest->origin[2] = src->origin[2];
if (bits & U_ANGLE3)
dest->angles[2] = src->angles[2];
if (bits & U_ANGLE1)
to->angles[0] = MSG_ReadAngle (net_message);
if (bits & U_ORIGIN2)
to->origin[1] = MSG_ReadCoord (net_message);
if (bits & U_ANGLE2)
to->angles[1] = MSG_ReadAngle (net_message);
if (bits & U_ORIGIN3)
to->origin[2] = MSG_ReadCoord (net_message);
if (bits & U_ANGLE3)
to->angles[2] = MSG_ReadAngle (net_message);
// LordHavoc: Endy neglected to mark this as being part of the QSG
// version 2 stuff... rearranged it and implemented missing effects
// Ender (QSG - Begin)
if (bits & U_ALPHA) if (bits & U_ALPHA)
dest->alpha = src->alpha; to->alpha = MSG_ReadByte (net_message);
if (bits & U_SCALE) if (bits & U_SCALE)
dest->scale = src->scale; to->scale = MSG_ReadByte (net_message);
if (bits & U_EFFECTS2) if (bits & U_EFFECTS2)
dest->effects = (dest->effects & 0xFF) | (src->effects & 0xFF00); to->effects = (to->effects & 0xFF) | (MSG_ReadByte (net_message) << 8);
if (bits & U_GLOWSIZE) if (bits & U_GLOWSIZE)
dest->glow_size = src->glow_size; to->glow_size = MSG_ReadByte (net_message);
if (bits & U_GLOWCOLOR) if (bits & U_GLOWCOLOR)
dest->glow_color = src->glow_color; to->glow_color = MSG_ReadByte (net_message);
if (bits & U_COLORMOD) if (bits & U_COLORMOD)
dest->colormod = src->colormod; to->colormod = MSG_ReadByte (net_message);
if (bits & U_FRAME2) if (bits & U_FRAME2)
dest->frame = (dest->frame & 0xFF) | (src->frame & 0xFF00); to->frame = (to->frame & 0xFF) | (MSG_ReadByte (net_message) << 8);
// Ender (QSG - End)
if (bits & U_SOLID) { if (bits & U_SOLID) {
// FIXME // FIXME
} }
/*
if ((!to->alpha) || (!to->colormod))
Con_Printf("fa: %d, fc: %d, ta: %d, tc: %d\n",
from->alpha, from->colormod, to->alpha, to->colormod);
*/
/*
if ((!ent->alpha) || (!ent->colormod[0]) || (!ent->colormod[1]) ||
(!ent->colormod[2])) {
Con_Printf ("ea: %f, ec0: %f, ec1: %f ec2: %f, sa: %d, sc: %d\n",
ent->alpha, ent->colormod[0], ent->colormod[1],
ent->colormod[2], s1->alpha, s1->colormod);
}
*/
} }
void void
CL_ParsePacketEntities (void) FlushEntityPacket (void)
{ {
int index, packetnum; entity_state_t olde, newe;
packet_entities_t *newp; int word;
net_svc_packetentities_t block;
packetnum = cls.netchan.incoming_sequence & UPDATE_MASK; Con_DPrintf ("FlushEntityPacket\n");
newp = &cl.frames[packetnum].packet_entities;
cl.frames[packetnum].invalid = false;
cl.validsequence = cls.netchan.incoming_sequence; memset (&olde, 0, sizeof (olde));
newp->num_entities = 0; cl.validsequence = 0; // can't render a frame
cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].invalid = true;
if (NET_SVC_PacketEntities_Parse (&block, net_message)) { // read it all, but ignore it
Host_NetError ("CL_ParsePacketEntities: Bad Read"); while (1) {
word = (unsigned short) MSG_ReadShort (net_message);
if (net_message->badread) { // something didn't parse right...
Host_EndGame ("msg_badread in packetentities");
return; return;
} }
for (index = 0; block.words[index]; index++) { if (!word)
if (block.words[index] & U_REMOVE) { break; // done
Host_NetError ("CL_ParsePacketEntities: U_REMOVE on full "
"update\n");
cl.validsequence = 0; // XXX
cl.frames[packetnum].invalid = true;
return;
}
if (index >= MAX_PACKET_ENTITIES) { CL_ParseDelta (&olde, &newe, word);
Host_NetError ("CL_ParsePacketEntities: index %i >= "
"MAX_PACKET_ENTITIES", index);
return;
} }
newp->entities[index] = cl_baselines[block.words[index] & 511];
CL_EntityState_Copy (&block.deltas[index],
&newp->entities[index],
block.deltas[index].flags);
newp->entities[index].number = block.deltas[index].number;
if (newp->entities[index].modelindex >= MAX_MODELS) {
Host_NetError ("CL_ParsePacketEntities: modelindex %i >= "
"MAX_MODELS", newp->entities[index].modelindex);
return;
}
continue;
}
newp->num_entities = index;
} }
/* /*
CL_ParseDeltaPacketEntities CL_ParsePacketEntities
An svc_packetentities has just been parsed, deal with the An svc_packetentities has just been parsed, deal with the
rest of the data stream. rest of the data stream.
*/ */
void void
CL_ParseDeltaPacketEntities () CL_ParsePacketEntities (qboolean delta)
{ {
int oldindex = 0, newindex = 0; byte from;
int wordindex = 0, deltaindex = 0; int oldindex, newindex, newnum, oldnum, oldpacket, newpacket, word;
int oldnum, newnum; packet_entities_t *oldp, *newp, dummy;
int oldpacket, newpacket; qboolean full;
packet_entities_t *oldp, *newp;
net_svc_deltapacketentities_t block;
if (NET_SVC_DeltaPacketEntities_Parse (&block, net_message)) {
Host_NetError ("CL_ParseDeltaPacketEntities: Bad Read");
return;
}
newpacket = cls.netchan.incoming_sequence & UPDATE_MASK; newpacket = cls.netchan.incoming_sequence & UPDATE_MASK;
newp = &cl.frames[newpacket].packet_entities; newp = &cl.frames[newpacket].packet_entities;
cl.frames[newpacket].invalid = false; cl.frames[newpacket].invalid = false;
if (delta) {
from = MSG_ReadByte (net_message);
oldpacket = cl.frames[newpacket].delta_sequence; oldpacket = cl.frames[newpacket].delta_sequence;
if ((from & UPDATE_MASK) != (oldpacket & UPDATE_MASK))
Con_DPrintf ("WARNING: from mismatch\n");
} else
oldpacket = -1;
full = false;
if (oldpacket != -1) {
if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) { if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) {
// we can't use this, it is too old // we can't use this, it is too old
Con_DPrintf ("CL_ParseDeltaPacketEntities: old packet\n"); FlushEntityPacket ();
cl.validsequence = 0; // can't render a frame
cl.frames[newpacket].invalid = true;
return; return;
} }
if ((block.from & UPDATE_MASK) != (oldpacket & UPDATE_MASK)) {
Con_DPrintf ("CL_ParseDeltaPacketEntities: from mismatch\n");
cl.validsequence = 0;
cl.frames[newpacket].invalid = true;
return;
}
if (oldpacket == -1) {
Host_NetError ("Cl_ParseDeltaPacketEntities: invalid "
"delta_sequence\n");
return;
}
cl.validsequence = cls.netchan.incoming_sequence; cl.validsequence = cls.netchan.incoming_sequence;
oldp = &cl.frames[oldpacket & UPDATE_MASK].packet_entities; oldp = &cl.frames[oldpacket & UPDATE_MASK].packet_entities;
} else { // a full update that we can start delta compressing from now
oldp = &dummy;
dummy.num_entities = 0;
cl.validsequence = cls.netchan.incoming_sequence;
full = true;
}
oldindex = 0;
newindex = 0;
newp->num_entities = 0; newp->num_entities = 0;
for (; block.words[wordindex];) { while (1) {
newnum = block.words[wordindex] & 511; word = (unsigned short) MSG_ReadShort (net_message);
if (net_message->badread) { // something didn't parse right...
Host_EndGame ("msg_badread in packetentities");
return;
}
if (!word) { // copy rest of ents from old packet
while (oldindex < oldp->num_entities) {
// Con_Printf ("copy %i\n", oldp->entities[oldindex].number);
if (newindex >= MAX_PACKET_ENTITIES)
Host_EndGame ("CL_ParsePacketEntities: newindex == "
"MAX_PACKET_ENTITIES");
newp->entities[newindex] = oldp->entities[oldindex];
newindex++;
oldindex++;
}
break;
}
newnum = word & 511;
oldnum = oldindex >= oldp->num_entities ? 9999 : oldnum = oldindex >= oldp->num_entities ? 9999 :
oldp->entities[oldindex].number; oldp->entities[oldindex].number;
while (newnum > oldnum) { // copy one of the old entities while (newnum > oldnum) {
// over to the new packet unchanged if (full) {
// Con_Printf ("copy %i\n", oldnum); Con_Printf ("WARNING: oldcopy on full update");
if (newindex >= MAX_PACKET_ENTITIES) { FlushEntityPacket ();
Host_NetError ("CL_ParseDeltaPacketEntities: newindex >= "
"MAX_PACKET_ENTITIES (1st)");
return; return;
} }
// Con_Printf ("copy %i\n", oldnum);
// copy one of the old entities over to the new packet unchanged
if (newindex >= MAX_PACKET_ENTITIES)
Host_EndGame ("CL_ParsePacketEntities: newindex == "
"MAX_PACKET_ENTITIES");
newp->entities[newindex] = oldp->entities[oldindex]; newp->entities[newindex] = oldp->entities[oldindex];
newindex++; newindex++;
oldindex++; oldindex++;
@ -298,74 +348,44 @@ CL_ParseDeltaPacketEntities ()
if (newnum < oldnum) { // new from baseline if (newnum < oldnum) { // new from baseline
// Con_Printf ("baseline %i\n", newnum); // Con_Printf ("baseline %i\n", newnum);
if (block.words[wordindex] & U_REMOVE) { if (word & U_REMOVE) {
wordindex++; if (full) {
cl.validsequence = 0;
Con_Printf ("WARNING: U_REMOVE on full update\n");
FlushEntityPacket ();
return;
}
continue; continue;
} }
if (newindex >= MAX_PACKET_ENTITIES) { if (newindex >= MAX_PACKET_ENTITIES)
Host_NetError ("CL_ParseDeltaPacketEntities: newindex >= " Host_EndGame ("CL_ParsePacketEntities: newindex == "
"MAX_PACKET_ENTITIES (2nd)"); "MAX_PACKET_ENTITIES");
return; CL_ParseDelta (&cl_baselines[newnum], &newp->entities[newindex],
} word);
newp->entities[newindex] = cl_baselines[newnum];
CL_EntityState_Copy (&block.deltas[deltaindex],
&newp->entities[newindex],
block.deltas[deltaindex].flags);
newp->entities[newindex].number
= block.deltas[deltaindex].number;
if (newp->entities[newindex].modelindex >= MAX_MODELS) {
Host_NetError ("CL_ParsePacketEntities: modelindex %i >= "
"MAX_MODELS",
newp->entities[newindex].modelindex);
return;
}
wordindex++;
deltaindex++;
newindex++; newindex++;
continue; continue;
} }
if (newnum == oldnum) { // delta from previous if (newnum == oldnum) { // delta from previous
// Con_Printf ("delta %i\n", newnum); if (full) {
if (block.words[wordindex] & U_REMOVE) { // Clear the entity cl.validsequence = 0;
memset (&cl_packet_ents[newnum], 0, sizeof (entity_t)); Con_Printf ("WARNING: delta on full update");
wordindex++; }
if (word & U_REMOVE) { // Clear the entity
entity_t *ent = &cl_packet_ents[newnum];
memset (ent, 0, sizeof (entity_t));
oldindex++; oldindex++;
continue; continue;
} }
newp->entities[newindex] = oldp->entities[oldindex]; // Con_Printf ("delta %i\n", newnum);
CL_EntityState_Copy (&block.deltas[deltaindex], CL_ParseDelta (&oldp->entities[oldindex],
&newp->entities[newindex], &newp->entities[newindex], word);
block.deltas[deltaindex].flags);
newp->entities[newindex].number
= block.deltas[deltaindex].number;
if (newp->entities[newindex].modelindex >= MAX_MODELS) {
Host_NetError ("CL_ParsePacketEntities: modelindex %i >= "
"MAX_MODELS",
newp->entities[newindex].modelindex);
return;
}
wordindex++;
deltaindex++;
newindex++; newindex++;
oldindex++; oldindex++;
} }
} }
while (oldindex < oldp->num_entities) { // copy rest of ents from old packet
// Con_Printf ("copy %i\n", oldp->entities[oldindex].number);
if (newindex >= MAX_PACKET_ENTITIES) {
Host_NetError ("CL_ParseDeltaPacketEntities: newindex >= "
"MAX_PACKET_ENTITIES (3rd)");
return;
}
newp->entities[newindex] = oldp->entities[oldindex];
newindex++;
oldindex++;
}
newp->num_entities = newindex; newp->num_entities = newindex;
} }
@ -523,6 +543,7 @@ typedef struct {
entity_t ent; entity_t ent;
} projectile_t; } projectile_t;
#define MAX_PROJECTILES 32
projectile_t cl_projectiles[MAX_PROJECTILES]; projectile_t cl_projectiles[MAX_PROJECTILES];
int cl_num_projectiles; int cl_num_projectiles;
@ -540,25 +561,27 @@ CL_ClearProjectiles (void)
void void
CL_ParseProjectiles (void) CL_ParseProjectiles (void)
{ {
int i; byte bits[6];
int i, c, j;
projectile_t *pr; projectile_t *pr;
net_svc_nails_t block;
if (NET_SVC_Nails_Parse (&block, net_message)) { c = MSG_ReadByte (net_message);
Host_NetError ("CL_ParseProjectiles: Bad Read\n"); for (i = 0; i < c; i++) {
return; for (j = 0; j < 6; j++)
} bits[j] = MSG_ReadByte (net_message);
for (i = 0; i < block.numnails; i++) {
if (cl_num_projectiles == MAX_PROJECTILES) if (cl_num_projectiles == MAX_PROJECTILES)
break; continue;
pr = &cl_projectiles[cl_num_projectiles]; pr = &cl_projectiles[cl_num_projectiles];
cl_num_projectiles++; cl_num_projectiles++;
pr->modelindex = cl_spikeindex; pr->modelindex = cl_spikeindex;
VectorCopy (block.nails[i].origin, pr->ent.origin); pr->ent.origin[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096;
VectorCopy (block.nails[i].angles, pr->ent.angles); pr->ent.origin[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096;
pr->ent.origin[2] = ((bits[3] + ((bits[4] & 15) << 8)) << 1) - 4096;
pr->ent.angles[0] = 360 * (bits[4] >> 4) / 16;
pr->ent.angles[1] = 360 * bits[5] / 256;
} }
} }
@ -594,57 +617,66 @@ CL_LinkProjectiles (void)
} }
} }
void void
CL_ParsePlayerinfo (void) CL_ParsePlayerinfo (void)
{ {
int flags, msec, num, i;
player_state_t *state; player_state_t *state;
net_svc_playerinfo_t block;
if (NET_SVC_Playerinfo_Parse (&block, net_message)) { num = MSG_ReadByte (net_message);
Host_NetError ("CL_ParsePlayerinfo: Bad Read\n"); if (num > MAX_CLIENTS)
return; // Sys_Error ("CL_ParsePlayerinfo: bad num");
} Host_EndGame ("CL_ParsePlayerinfo: bad num");
if (block.playernum >= MAX_CLIENTS) { state = &cl.frames[parsecountmod].playerstate[num];
Host_NetError ("CL_ParsePlayerinfo: playernum %i >= MAX_CLIENTS",
block.playernum);
return;
}
if (block.modelindex >= MAX_MODELS) {
Host_NetError ("CL_ParsePlayerinfo: modelindex %i >= MAX_MODELS",
block.modelindex);
return;
}
state = &cl.frames[parsecountmod].playerstate[block.playernum]; state->number = num;
flags = state->flags = MSG_ReadShort (net_message);
state->number = block.playernum;
state->flags = block.flags;
state->messagenum = cl.parsecount; state->messagenum = cl.parsecount;
VectorCopy (block.origin, state->origin); state->origin[0] = MSG_ReadCoord (net_message);
state->origin[1] = MSG_ReadCoord (net_message);
state->origin[2] = MSG_ReadCoord (net_message);
state->frame = block.frame; state->frame = MSG_ReadByte (net_message);
// the other player's last move was likely some time // the other player's last move was likely some time
// before the packet was sent out, so accurately track // before the packet was sent out, so accurately track
// the exact time it was valid at // the exact time it was valid at
state->state_time = parsecounttime - block.msec * 0.001; if (flags & PF_MSEC) {
msec = MSG_ReadByte (net_message);
state->state_time = parsecounttime - msec * 0.001;
} else
state->state_time = parsecounttime;
if (block.flags & PF_COMMAND) if (flags & PF_COMMAND)
memcpy (&state->command, &block.usercmd, sizeof (state->command)); MSG_ReadDeltaUsercmd (&nullcmd, &state->command);
VectorCopy (block.velocity, state->velocity); for (i = 0; i < 3; i++) {
if (flags & (PF_VELOCITY1 << i))
if (block.flags & PF_MODEL) state->velocity[i] = MSG_ReadShort (net_message);
state->modelindex = block.modelindex; else
state->velocity[i] = 0;
}
if (flags & PF_MODEL)
state->modelindex = MSG_ReadByte (net_message);
else else
state->modelindex = cl_playerindex; state->modelindex = cl_playerindex;
state->skinnum = block.skinnum; if (flags & PF_SKINNUM)
state->effects = block.effects; state->skinnum = MSG_ReadByte (net_message);
state->weaponframe = block.weaponframe; else
state->skinnum = 0;
if (flags & PF_EFFECTS)
state->effects = MSG_ReadByte (net_message);
else
state->effects = 0;
if (flags & PF_WEAPONFRAME)
state->weaponframe = MSG_ReadByte (net_message);
else
state->weaponframe = 0;
VectorCopy (state->command.angles, state->viewangles); VectorCopy (state->command.angles, state->viewangles);
} }

View file

@ -1318,34 +1318,6 @@ Host_EndGame (const char *message, ...)
longjmp (host_abort, 1); longjmp (host_abort, 1);
} }
/*
Host_NetError
Used for networking errors that disconnect, but don't exit the
client
*/
void
Host_NetError (const char *message, ...)
{
va_list argptr;
int old = 0;
old = net_packetlog->int_val;
if (net_packetlog->int_val)
Cvar_Set (net_packetlog, "0");
Log_Incoming_Packet (net_message->message->data,
net_message->message->cursize);
if (old)
Cvar_SetValue (net_packetlog, old);
va_start (argptr, message);
Host_EndGame (message, argptr);
Con_Printf ("%s", "Please report this to "
"quake-devel@lists.sourceforge.net, including the "
"packet log printed out above\n");
va_end (argptr);
}
/* /*
Host_Error Host_Error

File diff suppressed because it is too large Load diff

View file

@ -206,7 +206,7 @@ CL_NewTranslation (int slot, skin_t *skin)
player_info_t *player; player_info_t *player;
if (slot > MAX_CLIENTS) if (slot > MAX_CLIENTS)
Host_NetError ("CL_NewTranslation: slot > MAX_CLIENTS"); Host_EndGame ("CL_NewTranslation: slot > MAX_CLIENTS");
player = &cl.players[slot]; player = &cl.players[slot];
if (!player->name[0]) if (!player->name[0])

View file

@ -50,8 +50,6 @@ static const char rcsid[] =
#include "cl_main.h" #include "cl_main.h"
#include "cl_tent.h" #include "cl_tent.h"
#include "client.h" #include "client.h"
#include "host.h"
#include "net_svc.h"
#include "r_dynamic.h" #include "r_dynamic.h"
#define MAX_BEAMS 8 #define MAX_BEAMS 8
@ -184,37 +182,42 @@ CL_AllocExplosion (void)
} }
void void
CL_ParseBeam (net_svc_tempentity_t *tempentity, model_t *m) CL_ParseBeam (model_t *m)
{ {
beam_t *b; beam_t *b;
int i; int ent, i;
vec3_t start, end;
if (tempentity->beamentity >= MAX_EDICTS) { ent = MSG_ReadShort (net_message);
Host_NetError ("CL_ParseBeam: beamentity %i >= MAX_EDICTS",
tempentity->beamentity); start[0] = MSG_ReadCoord (net_message);
return; start[1] = MSG_ReadCoord (net_message);
} start[2] = MSG_ReadCoord (net_message);
end[0] = MSG_ReadCoord (net_message);
end[1] = MSG_ReadCoord (net_message);
end[2] = MSG_ReadCoord (net_message);
// override any beam with the same entity // override any beam with the same entity
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++)
if (b->entity == tempentity->beamentity) { if (b->entity == ent) {
b->entity = tempentity->beamentity; b->entity = ent;
b->model = m; b->model = m;
b->endtime = cl.time + 0.2; b->endtime = cl.time + 0.2;
b->seed = rand(); b->seed = rand();
VectorCopy (tempentity->position, b->start); VectorCopy (start, b->start);
VectorCopy (tempentity->beamend, b->end); VectorCopy (end, b->end);
return; return;
} }
// find a free beam // find a free beam
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) { for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) {
if (!b->model || b->endtime < cl.time) { if (!b->model || b->endtime < cl.time) {
b->entity = tempentity->beamentity; b->entity = ent;
b->model = m; b->model = m;
b->endtime = cl.time + 0.2; b->endtime = cl.time + 0.2;
b->seed = rand(); b->seed = rand();
VectorCopy (tempentity->position, b->start); VectorCopy (start, b->start);
VectorCopy (tempentity->beamend, b->end); VectorCopy (end, b->end);
return; return;
} }
} }
@ -224,66 +227,79 @@ CL_ParseBeam (net_svc_tempentity_t *tempentity, model_t *m)
void void
CL_ParseTEnt (void) CL_ParseTEnt (void)
{ {
byte type;
dlight_t *dl; dlight_t *dl;
explosion_t *ex; explosion_t *ex;
int rnd; int colorStart, colorLength, rnd;
net_svc_tempentity_t tempentity; int cnt = -1;
vec3_t pos;
if (NET_SVC_TempEntity_Parse (&tempentity, net_message)) { type = MSG_ReadByte (net_message);
Host_NetError ("CL_ParseTEnt: Bad Read\n"); switch (type) {
return;
}
switch (tempentity.type) {
case TE_WIZSPIKE: // spike hitting wall case TE_WIZSPIKE: // spike hitting wall
R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]); pos[0] = MSG_ReadCoord (net_message);
S_StartSound (-1, 0, cl_sfx_wizhit, tempentity.position, 1, 1); pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_RunSpikeEffect (pos, prot_to_rend[type]);
S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
break; break;
case TE_KNIGHTSPIKE: // spike hitting wall case TE_KNIGHTSPIKE: // spike hitting wall
R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]); pos[0] = MSG_ReadCoord (net_message);
S_StartSound (-1, 0, cl_sfx_knighthit, tempentity.position, 1, 1); pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_RunSpikeEffect (pos, prot_to_rend[type]);
S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
break; break;
case TE_SPIKE: // spike hitting wall case TE_SPIKE: // spike hitting wall
R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]); pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_RunSpikeEffect (pos, prot_to_rend[type]);
if (rand () % 5) if (rand () % 5)
S_StartSound (-1, 0, cl_sfx_tink1, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
else { else {
rnd = rand () & 3; rnd = rand () & 3;
if (rnd == 1) if (rnd == 1)
S_StartSound (-1, 0, cl_sfx_ric1, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
else if (rnd == 2) else if (rnd == 2)
S_StartSound (-1, 0, cl_sfx_ric2, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
else else
S_StartSound (-1, 0, cl_sfx_ric3, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
} }
break; break;
case TE_SUPERSPIKE: // super spike hitting wall case TE_SUPERSPIKE: // super spike hitting wall
R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]); pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_RunSpikeEffect (pos, prot_to_rend[type]);
if (rand () % 5) if (rand () % 5)
S_StartSound (-1, 0, cl_sfx_tink1, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
else { else {
rnd = rand () & 3; rnd = rand () & 3;
if (rnd == 1) if (rnd == 1)
S_StartSound (-1, 0, cl_sfx_ric1, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
else if (rnd == 2) else if (rnd == 2)
S_StartSound (-1, 0, cl_sfx_ric2, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
else else
S_StartSound (-1, 0, cl_sfx_ric3, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
} }
break; break;
case TE_EXPLOSION: // rocket explosion case TE_EXPLOSION: // rocket explosion
// particles // particles
R_ParticleExplosion (tempentity.position); pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_ParticleExplosion (pos);
// light // light
dl = R_AllocDlight (0); dl = R_AllocDlight (0);
VectorCopy (tempentity.position, dl->origin); VectorCopy (pos, dl->origin);
dl->radius = 350; dl->radius = 350;
dl->die = cl.time + 0.5; dl->die = cl.time + 0.5;
dl->decay = 300; dl->decay = 300;
@ -292,78 +308,94 @@ CL_ParseTEnt (void)
dl->color[2] = 0.24; dl->color[2] = 0.24;
// sound // sound
S_StartSound (-1, 0, cl_sfx_r_exp3, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
// sprite // sprite
ex = CL_AllocExplosion (); ex = CL_AllocExplosion ();
VectorCopy (tempentity.position, ex->ent.origin); VectorCopy (pos, ex->ent.origin);
ex->start = cl.time; ex->start = cl.time;
ex->ent.model = cl_spr_explod; ex->ent.model = cl_spr_explod;
break; break;
case TE_TAREXPLOSION: // tarbaby explosion case TE_TAREXPLOSION: // tarbaby explosion
R_BlobExplosion (tempentity.position); pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_BlobExplosion (pos);
S_StartSound (-1, 0, cl_sfx_r_exp3, tempentity.position, 1, 1); S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
break; break;
case TE_LIGHTNING1: // lightning bolts case TE_LIGHTNING1: // lightning bolts
CL_ParseBeam (&tempentity, cl_mod_bolt); CL_ParseBeam (cl_mod_bolt);
break; break;
case TE_LIGHTNING2: // lightning bolts case TE_LIGHTNING2: // lightning bolts
CL_ParseBeam (&tempentity, cl_mod_bolt2); CL_ParseBeam (cl_mod_bolt2);
break; break;
case TE_LIGHTNING3: // lightning bolts case TE_LIGHTNING3: // lightning bolts
CL_ParseBeam (&tempentity, cl_mod_bolt3); CL_ParseBeam (cl_mod_bolt3);
break; break;
// PGM 01/21/97 // PGM 01/21/97
case TE_BEAM: // grappling hook beam case TE_BEAM: // grappling hook beam
CL_ParseBeam (&tempentity, Mod_ForName ("progs/beam.mdl", true)); CL_ParseBeam (Mod_ForName ("progs/beam.mdl", true));
break; break;
// PGM 01/21/97 // PGM 01/21/97
case TE_LAVASPLASH: case TE_LAVASPLASH:
R_LavaSplash (tempentity.position); pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_LavaSplash (pos);
break; break;
case TE_TELEPORT: case TE_TELEPORT:
R_TeleportSplash (tempentity.position); pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_TeleportSplash (pos);
break; break;
case TE_EXPLOSION2: // color mapped explosion case TE_EXPLOSION2: // color mapped explosion
R_ParticleExplosion2 (tempentity.position, pos[0] = MSG_ReadCoord (net_message);
tempentity.colorstart, pos[1] = MSG_ReadCoord (net_message);
tempentity.colorlength); pos[2] = MSG_ReadCoord (net_message);
colorStart = MSG_ReadByte (net_message);
colorLength = MSG_ReadByte (net_message);
R_ParticleExplosion2 (pos, colorStart, colorLength);
dl = R_AllocDlight (0); dl = R_AllocDlight (0);
VectorCopy (tempentity.position, dl->origin); VectorCopy (pos, dl->origin);
dl->radius = 350; dl->radius = 350;
dl->die = cl.time + 0.5; dl->die = cl.time + 0.5;
dl->decay = 300; dl->decay = 300;
dl->color[0] = vid_basepal[(tempentity.colorstart dl->color[0] = vid_basepal[(colorStart + (rand() % colorLength)) *
+ (rand() % tempentity.colorlength)) 3] * (1.0 / 255.0);
* 3] * (1.0 / 255.0); dl->color[1] = vid_basepal[(colorStart + (rand() % colorLength)) *
dl->color[1] = vid_basepal[(tempentity.colorstart 3 + 1] * (1.0 / 255.0);
+ (rand() % tempentity.colorlength)) dl->color[2] = vid_basepal[(colorStart + (rand() % colorLength)) *
* 3 + 1] * (1.0 / 255.0); 3 + 2] * (1.0 / 255.0);
dl->color[2] = vid_basepal[(tempentity.colorstart S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
+ (rand() % tempentity.colorlength))
* 3 + 2] * (1.0 / 255.0);
S_StartSound (-1, 0, cl_sfx_r_exp3, tempentity.position, 1, 1);
break; break;
case TE_GUNSHOT: // bullet hitting wall case TE_GUNSHOT: // bullet hitting wall
case TE_BLOOD: // bullets hitting body case TE_BLOOD: // bullets hitting body
R_RunPuffEffect (tempentity.position, prot_to_rend[tempentity.type], cnt = MSG_ReadByte (net_message) * 20;
tempentity.gunshotcount * 20); pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_RunPuffEffect (pos, prot_to_rend[type], cnt);
break; break;
case TE_LIGHTNINGBLOOD: // lightning hitting body case TE_LIGHTNINGBLOOD: // lightning hitting body
pos[0] = MSG_ReadCoord (net_message);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
// light // light
dl = R_AllocDlight (0); dl = R_AllocDlight (0);
VectorCopy (tempentity.position, dl->origin); VectorCopy (pos, dl->origin);
dl->radius = 150; dl->radius = 150;
dl->die = cl.time + 0.1; dl->die = cl.time + 0.1;
dl->decay = 200; dl->decay = 200;
@ -371,11 +403,11 @@ CL_ParseTEnt (void)
dl->color[1] = 0.40; dl->color[1] = 0.40;
dl->color[2] = 0.65; dl->color[2] = 0.65;
R_RunPuffEffect (tempentity.position, prot_to_rend[tempentity.type], 0); R_RunPuffEffect (pos, prot_to_rend[type], cnt);
break; break;
default: default:
Sys_Error ("CL_ParseTEnt: bad tempentity.type %i", tempentity.type); Sys_Error ("CL_ParseTEnt: bad type");
} }
} }

View file

@ -45,7 +45,6 @@ static const char rcsid[] =
#include "client.h" #include "client.h"
#include "compat.h" #include "compat.h"
#include "host.h" #include "host.h"
#include "net_svc.h"
#include "pmove.h" #include "pmove.h"
#include "view.h" #include "view.h"
@ -241,18 +240,18 @@ V_DriftPitch (void)
/* PALETTE FLASHES */ /* PALETTE FLASHES */
void void
CL_ParseDamage (void) V_ParseDamage (void)
{ {
float count, side; float count, side;
vec3_t forward, right, up; int armor, blood, i;
net_svc_damage_t damage; vec3_t forward, from, right, up;
if (NET_SVC_Damage_Parse (&damage, net_message)) { armor = MSG_ReadByte (net_message);
Host_NetError ("CL_ParseDamage: Bad Read\n"); blood = MSG_ReadByte (net_message);
return; for (i = 0; i < 3; i++)
} from[i] = MSG_ReadCoord (net_message);
count = damage.blood * 0.5 + damage.armor * 0.5; count = blood * 0.5 + armor * 0.5;
if (count < 10) if (count < 10)
count = 10; count = 10;
@ -266,11 +265,11 @@ CL_ParseDamage (void)
cl.cshifts[CSHIFT_DAMAGE].percent = cl.cshifts[CSHIFT_DAMAGE].percent =
bound (0, cl.cshifts[CSHIFT_DAMAGE].percent, 150); bound (0, cl.cshifts[CSHIFT_DAMAGE].percent, 150);
if (damage.armor > damage.blood) { if (armor > blood) {
cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
} else if (damage.armor) { } else if (armor) {
cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
@ -282,15 +281,15 @@ CL_ParseDamage (void)
} }
// calculate view angle kicks // calculate view angle kicks
VectorSubtract (damage.from, cl.simorg, damage.from); VectorSubtract (from, cl.simorg, from);
VectorNormalize (damage.from); VectorNormalize (from);
AngleVectors (cl.simangles, forward, right, up); AngleVectors (cl.simangles, forward, right, up);
side = DotProduct (damage.from, right); side = DotProduct (from, right);
v_dmg_roll = count * side * v_kickroll->value; v_dmg_roll = count * side * v_kickroll->value;
side = DotProduct (damage.from, forward); side = DotProduct (from, forward);
v_dmg_pitch = count * side * v_kickpitch->value; v_dmg_pitch = count * side * v_kickpitch->value;
v_dmg_time = v_kicktime->value; v_dmg_time = v_kicktime->value;

View file

@ -56,7 +56,6 @@ static const char rcsid[] =
#include "compat.h" #include "compat.h"
#include "net.h" #include "net.h"
#include "net_svc.h"
#include "protocol.h" #include "protocol.h"
#include "server.h" #include "server.h"
@ -71,6 +70,81 @@ void Parse_Server_Packet (void);
void Parse_Client_Packet (void); void Parse_Client_Packet (void);
void Net_LogStop (void); void Net_LogStop (void);
// note: this is SUPPOSED to be duplicate, like many others
const char *svc_string[] = {
"svc_bad",
"svc_nop",
"svc_disconnect",
"svc_updatestat",
"svc_version", // [long] server version
"svc_setview", // [short] entity number
"svc_sound", // <see code>
"svc_time", // [float] server time
"svc_print", // [string] null terminated string
"svc_stufftext", // [string] stuffed into client's
// console buffer the string
// should be \n terminated
"svc_setangle", // [vec3] set the view angle to this
// absolute value
"svc_serverdata", // [long] version ...
"svc_lightstyle", // [byte] [string]
"svc_updatename", // [byte] [string]
"svc_updatefrags", // [byte] [short]
"svc_clientdata", // <shortbits + data>
"svc_stopsound", // <see code>
"svc_updatecolors", // [byte] [byte]
"svc_particle", // [vec3] <variable>
"svc_damage", // [byte] impact [byte] blood [vec3]
// from
"svc_spawnstatic",
"svc_spawnbinary",
"svc_spawnbaseline",
"svc_temp_entity", // <variable>
"svc_setpause",
"svc_signonnum",
"svc_centerprint",
"svc_killedmonster",
"svc_foundsecret",
"svc_spawnstaticsound",
"svc_intermission",
"svc_finale", // [string] music [string] text
"svc_cdtrack", // [byte] track [byte] looptrack
"svc_sellscreen",
"svc_smallkick", // Quake svc_cutscene
"svc_bigkick",
"svc_updateping",
"svc_updateentertime",
"svc_updatestatlong",
"svc_muzzleflash",
"svc_updateuserinfo",
"svc_download",
"svc_playerinfo",
"svc_nails",
"svc_chokecount",
"svc_modellist",
"svc_soundlist",
"svc_packetentities",
"svc_deltapacketentities",
"svc_maxspeed",
"svc_entgravity",
"svc_setinfo",
"svc_serverinfo",
"svc_updatepl",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL",
"NEW PROTOCOL"
};
const char *clc_string[] = { const char *clc_string[] = {
"clc_bad", "clc_bad",
"clc_nop", "clc_nop",
@ -95,6 +169,7 @@ const char *clc_string[] = {
#define svc_particle 18 // [vec3] <variable> #define svc_particle 18 // [vec3] <variable>
#define svc_signonnum 25 // [byte] used for the signon #define svc_signonnum 25 // [byte] used for the signon
// sequence // sequence
static VFile *_stdout;
static VFile *Net_PacketLog; static VFile *Net_PacketLog;
static const char **Net_sound_precache; static const char **Net_sound_precache;
static sizebuf_t _packet; static sizebuf_t _packet;
@ -115,12 +190,11 @@ Net_LogPrintf (char *fmt, ...)
va_start (argptr, fmt); va_start (argptr, fmt);
vsnprintf (text, sizeof (text), fmt, argptr); vsnprintf (text, sizeof (text), fmt, argptr);
va_end (argptr); va_end (argptr);
if (!Net_PacketLog)
return;
if (Net_PacketLog) {
Qprintf (Net_PacketLog, "%s", text); Qprintf (Net_PacketLog, "%s", text);
Qflush (Net_PacketLog); Qflush (Net_PacketLog);
} else
Con_Printf ("%s", text);
} }
int int
@ -230,43 +304,30 @@ Log_Outgoing_Packet (const char *p, int len)
return; return;
} }
qboolean void
Log_Delta(int bits) Log_Delta(int bits)
{ {
entity_state_t to; entity_state_t to;
int i; int i;
Net_LogPrintf ("\n\t<%06x> ", MSG_GetReadCount (&packet) - 2); Net_LogPrintf ("\n\t");
if (!bits) {
Net_LogPrintf ("End");
return 1;
}
// set everything to the state we are delta'ing from // set everything to the state we are delta'ing from
to.number = bits & 511; to.number = bits & 511;
bits &= ~511; bits &= ~511;
Net_LogPrintf ("Ent: %d", to.number);
if (bits & U_REMOVE)
Net_LogPrintf (" U_REMOVE");
if (bits & U_MOREBITS) { // read in the low order bits if (bits & U_MOREBITS) { // read in the low order bits
i = MSG_ReadByte (&packet); i = MSG_ReadByte (&packet);
bits |= i; bits |= i;
Net_LogPrintf (" U_MOREBITS");
} }
// LordHavoc: Endy neglected to mark this as being part of the QSG // LordHavoc: Endy neglected to mark this as being part of the QSG
// version 2 stuff... // version 2 stuff...
if (bits & U_EXTEND1) { if (bits & U_EXTEND1) {
bits |= MSG_ReadByte (&packet) << 16; bits |= MSG_ReadByte (&packet) << 16;
Net_LogPrintf (" U_EXTEND1"); if (bits & U_EXTEND2)
if (bits & U_EXTEND2) {
bits |= MSG_ReadByte (&packet) << 24; bits |= MSG_ReadByte (&packet) << 24;
Net_LogPrintf (" U_EXTEND2");
}
} }
to.flags = bits; to.flags = bits;
@ -325,7 +386,7 @@ Log_Delta(int bits)
Net_LogPrintf(" Uframe2: %d", ((to.frame & 0xFF) | (MSG_ReadByte (&packet) << 8))); Net_LogPrintf(" Uframe2: %d", ((to.frame & 0xFF) | (MSG_ReadByte (&packet) << 8)));
// Ender (QSG - End) // Ender (QSG - End)
return 0; return;
} }
@ -333,10 +394,14 @@ Log_Delta(int bits)
void void
Analyze_Server_Packet (const byte * data, int len) Analyze_Server_Packet (const byte * data, int len)
{ {
if (!Net_PacketLog)
Net_PacketLog = _stdout;
packet.message->data = (byte*)data; packet.message->data = (byte*)data;
packet.message->cursize = len; packet.message->cursize = len;
MSG_BeginReading (&packet); MSG_BeginReading (&packet);
Parse_Server_Packet (); Parse_Server_Packet ();
if (Net_PacketLog == _stdout)
Net_PacketLog = NULL;
} }
@ -373,11 +438,10 @@ Parse_Server_Packet ()
if (c == -1) if (c == -1)
break; break;
// Net_LogPrintf("\n<%ld,%ld> ",seq1 & 0x7FFFFFFF,seq2 & 0x7FFFFFFF); // Net_LogPrintf("\n<%ld,%ld> ",seq1 & 0x7FFFFFFF,seq2 & 0x7FFFFFFF);
Net_LogPrintf ("<%06x> [0x%02x] ", Net_LogPrintf ("<%06x> [0x%02x] ", MSG_GetReadCount (&packet), c);
MSG_GetReadCount (&packet) - 1, c);
if (c < 53) if (c < 53)
Net_LogPrintf ("%s: ", NET_SVC_GetString (c)); Net_LogPrintf ("%s: ", svc_string[c]);
// else Net_LogPrintf("(UNK: %d): ",c); // else Net_LogPrintf("(UNK: %d): ",c);
if (MSG_GetReadCount (&packet) > packet.message->cursize) if (MSG_GetReadCount (&packet) > packet.message->cursize)
@ -559,7 +623,7 @@ Parse_Server_Packet ()
Net_LogPrintf ("**QW OBSOLETE**"); Net_LogPrintf ("**QW OBSOLETE**");
break; break;
case svc_centerprint: case svc_centerprint:
Net_LogPrintf ("%s", MSG_ReadString (&packet)); Net_LogPrintf ("%s\n", MSG_ReadString (&packet));
break; break;
case svc_killedmonster: case svc_killedmonster:
break; break;
@ -730,9 +794,6 @@ Parse_Server_Packet ()
else else
Net_LogPrintf ("\n\t*End of sound list*"); Net_LogPrintf ("\n\t*End of sound list*");
break; break;
case svc_deltapacketentities:
Net_LogPrintf ("from: %d", MSG_ReadByte (&packet));
// intentional fallthrough
case svc_packetentities: case svc_packetentities:
while (1) { while (1) {
mask1 = (unsigned short) MSG_ReadShort(&packet); mask1 = (unsigned short) MSG_ReadShort(&packet);
@ -740,10 +801,15 @@ Parse_Server_Packet ()
Net_LogPrintf ("Badread\n"); Net_LogPrintf ("Badread\n");
return; return;
} }
if (Log_Delta(mask1)) if (!mask1) break;
break; if (mask1 & U_REMOVE) Net_LogPrintf("UREMOVE ");
Log_Delta(mask1);
} }
break; break;
case svc_deltapacketentities:
Net_LogPrintf ("idx: %d", MSG_ReadByte (&packet));
return;
break;
case svc_maxspeed: case svc_maxspeed:
Net_LogPrintf ("%f", MSG_ReadFloat (&packet)); Net_LogPrintf ("%f", MSG_ReadFloat (&packet));
break; break;
@ -775,10 +841,14 @@ Parse_Server_Packet ()
void void
Analyze_Client_Packet (const byte * data, int len) Analyze_Client_Packet (const byte * data, int len)
{ {
if (!Net_PacketLog)
Net_PacketLog = _stdout;
packet.message->data = (byte*)data; packet.message->data = (byte*)data;
packet.message->cursize = len; packet.message->cursize = len;
MSG_BeginReading (&packet); MSG_BeginReading (&packet);
Parse_Client_Packet (); Parse_Client_Packet ();
if (Net_PacketLog == _stdout)
Net_PacketLog = NULL;
} }
void void
@ -892,7 +962,7 @@ Net_PacketLog_f (cvar_t *var)
void void
Net_PacketLog_Zap_f (void) Net_PacketLog_Zap_f (void)
{ {
if (Net_PacketLog) { if (Net_PacketLog && Net_PacketLog != _stdout) {
Con_Printf ("truncating packet logfile: %s\n", "qfpacket.log"); Con_Printf ("truncating packet logfile: %s\n", "qfpacket.log");
Qseek (Net_PacketLog, 0, 0); Qseek (Net_PacketLog, 0, 0);
Qwrite (Net_PacketLog, 0, 0); Qwrite (Net_PacketLog, 0, 0);
@ -910,6 +980,8 @@ Net_Log_Init (const char **sound_precache)
{ {
Net_sound_precache = sound_precache; Net_sound_precache = sound_precache;
_stdout = Qdopen (1, "wt"); // create a QFile of stdout
net_packetlog = Cvar_Get ("net_packetlog", "0", CVAR_NONE, Net_PacketLog_f, net_packetlog = Cvar_Get ("net_packetlog", "0", CVAR_NONE, Net_PacketLog_f,
"enable/disable packet logging"); "enable/disable packet logging");

View file

@ -52,7 +52,6 @@ static const char rcsid[] =
#include "bothdefs.h" #include "bothdefs.h"
#include "compat.h" #include "compat.h"
#include "net_svc.h"
#include "server.h" #include "server.h"
#include "sv_progs.h" #include "sv_progs.h"
@ -830,15 +829,12 @@ SV_Heartbeat_f (void)
void void
SV_SendServerInfoChange (const char *key, const char *value) SV_SendServerInfoChange (const char *key, const char *value)
{ {
net_svc_serverinfo_t block;
if (!sv.state) if (!sv.state)
return; return;
block.key = key;
block.value = value;
MSG_WriteByte (&sv.reliable_datagram, svc_serverinfo); MSG_WriteByte (&sv.reliable_datagram, svc_serverinfo);
NET_SVC_ServerInfo_Emit (&block, &sv.reliable_datagram); MSG_WriteString (&sv.reliable_datagram, key);
MSG_WriteString (&sv.reliable_datagram, value);
} }
/* /*

View file

@ -42,7 +42,6 @@ static const char rcsid[] =
#include "compat.h" #include "compat.h"
#include "msg_ucmd.h" #include "msg_ucmd.h"
#include "net_svc.h"
#include "server.h" #include "server.h"
#include "sv_progs.h" #include "sv_progs.h"
@ -126,29 +125,51 @@ SV_AddNailUpdate (edict_t *ent)
void void
SV_EmitNailUpdate (sizebuf_t *msg) SV_EmitNailUpdate (sizebuf_t *msg)
{ {
int i; byte bits[6]; // [48 bits] xyzpy 12 12 12 4 8
net_svc_nails_t block; int i, n, p, x, y, z, yaw;
edict_t *ent;
if (!numnails) if (!numnails)
return; return;
block.numnails = numnails;
for (i = 0; i < numnails; i++) {
VectorCopy (SVvector (nails[i], origin), block.nails[i].origin);
VectorCopy (SVvector (nails[i], angles), block.nails[i].angles);
}
MSG_WriteByte (msg, svc_nails); MSG_WriteByte (msg, svc_nails);
NET_SVC_Nails_Emit (&block, msg); MSG_WriteByte (msg, numnails);
for (n = 0; n < numnails; n++) {
ent = nails[n];
x = (int) (SVvector (ent, origin)[0] + 4096) >> 1;
y = (int) (SVvector (ent, origin)[1] + 4096) >> 1;
z = (int) (SVvector (ent, origin)[2] + 4096) >> 1;
p = (int) (16 * SVvector (ent, angles)[0] / 360) & 15;
yaw = (int) (256 * SVvector (ent, angles)[1] / 360) & 255;
bits[0] = x;
bits[1] = (x >> 8) | (y << 4);
bits[2] = (y >> 4);
bits[3] = z;
bits[4] = (z >> 8) | (p << 4);
bits[5] = yaw;
for (i = 0; i < 6; i++)
MSG_WriteByte (msg, bits[i]);
}
} }
unsigned int /*
SV_EntityState_Diff (entity_state_t *from, entity_state_t *to) SV_WriteDelta
Writes part of a packetentities message.
Can delta from either a baseline or a previous packet_entity
*/
void
SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
qboolean force, int stdver)
{ {
int i; int bits, i;
float miss; float miss;
unsigned int bits = 0;
// send an update
bits = 0;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
miss = to->origin[i] - from->origin[i]; miss = to->origin[i] - from->origin[i];
@ -182,7 +203,7 @@ SV_EntityState_Diff (entity_state_t *from, entity_state_t *to)
// LordHavoc: cleaned up Endy's coding style, and added missing effects // LordHavoc: cleaned up Endy's coding style, and added missing effects
// Ender (QSG - Begin) // Ender (QSG - Begin)
// if (stdver > 1) { if (stdver > 1) {
if (to->alpha != from->alpha) if (to->alpha != from->alpha)
bits |= U_ALPHA; bits |= U_ALPHA;
@ -197,44 +218,20 @@ SV_EntityState_Diff (entity_state_t *from, entity_state_t *to)
if (to->colormod != from->colormod) if (to->colormod != from->colormod)
bits |= U_COLORMOD; bits |= U_COLORMOD;
// } }
// if (bits >= 16777216) if (bits >= 16777216)
if (bits & U_GROUP_EXTEND2)
bits |= U_EXTEND2; bits |= U_EXTEND2;
// if (bits >= 65536) if (bits >= 65536)
if (bits & U_GROUP_EXTEND1)
bits |= U_EXTEND1; bits |= U_EXTEND1;
// Ender (QSG - End) // Ender (QSG - End)
if (bits & 511)
// if (bits & 511)
if (bits & U_GROUP_MOREBITS)
bits |= U_MOREBITS; bits |= U_MOREBITS;
if (to->flags & U_SOLID) if (to->flags & U_SOLID)
bits |= U_SOLID; bits |= U_SOLID;
return bits;
}
/*
SV_WriteDelta
Writes part of a packetentities message.
Can delta from either a baseline or a previous packet_entity
*/
void
SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
qboolean force, int stdver)
{
unsigned int bits;
// send an update
bits = SV_EntityState_Diff (from, to);
if (stdver <= 1)
bits &= U_VERSION_ID; // use old the original fields, no extensions
// write the message // write the message
if (!to->number) if (!to->number)
SV_Error ("Unset entity number"); SV_Error ("Unset entity number");
@ -243,7 +240,10 @@ SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
if (!bits && !force) if (!bits && !force)
return; // nothing to send! return; // nothing to send!
MSG_WriteShort (msg, to->number | (bits & ~511)); i = to->number | (bits & ~511);
if (i & U_REMOVE)
Sys_Error ("U_REMOVE");
MSG_WriteShort (msg, i);
if (bits & U_MOREBITS) if (bits & U_MOREBITS)
MSG_WriteByte (msg, bits & 255); MSG_WriteByte (msg, bits & 255);
@ -302,118 +302,80 @@ SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
/* /*
SV_EmitPacketEntities SV_EmitPacketEntities
Writes an update of a packet_entities_t to the message. Writes a delta update of a packet_entities_t to the message.
*/ */
void void
SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg) SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg)
{ {
int index; int newindex, oldindex, newnum, oldnum, oldmax;
entity_state_t *baseline; edict_t *ent;
net_svc_packetentities_t block; client_frame_t *fromframe;
block.numwords = block.numdeltas = to->num_entities;
for (index = 0; index < to->num_entities; index++) {
baseline = EDICT_NUM (&sv_pr_state,
to->entities[index].number)->data;
block.deltas[index] = to->entities[index];
block.deltas[index].flags =
SV_EntityState_Diff (baseline, &to->entities[index]);
// check if it's a client that doesn't support QSG2
if (client->stdver <= 1)
block.deltas[index].flags &= U_VERSION_ID;
block.words[index] = to->entities[index].number |
(block.deltas[index].flags & ~511);
}
block.words[index] = 0;
MSG_WriteByte (msg, svc_packetentities);
NET_SVC_PacketEntities_Emit (&block, msg);
}
/*
SV_EmitDeltaPacketEntities
Writes a delta update of a packet_entities_t to the message.
*/
void
SV_EmitDeltaPacketEntities (client_t *client, packet_entities_t *to,
sizebuf_t *msg)
{
int newindex, oldindex, newnum, oldnum;
int word;
entity_state_t *baseline;
packet_entities_t *from; packet_entities_t *from;
net_svc_deltapacketentities_t block;
// this is the frame that we are going to delta update from // this is the frame that we are going to delta update from
from = &client->frames[client->delta_sequence & UPDATE_MASK].entities; if (client->delta_sequence != -1) {
fromframe = &client->frames[client->delta_sequence & UPDATE_MASK];
from = &fromframe->entities;
oldmax = from->num_entities;
block.from = client->delta_sequence; MSG_WriteByte (msg, svc_deltapacketentities);
MSG_WriteByte (msg, client->delta_sequence);
} else {
oldmax = 0; // no delta update
from = NULL;
MSG_WriteByte (msg, svc_packetentities);
}
newindex = 0;
oldindex = 0;
// SV_Printf ("---%i to %i ----\n", client->delta_sequence & UPDATE_MASK, // SV_Printf ("---%i to %i ----\n", client->delta_sequence & UPDATE_MASK,
// client->netchan.outgoing_sequence & UPDATE_MASK); // client->netchan.outgoing_sequence & UPDATE_MASK);
for (newindex = 0, oldindex = 0, word = 0; while (newindex < to->num_entities || oldindex < oldmax) {
newindex < to->num_entities || oldindex < from->num_entities; newnum =
word++) { newindex >= to->num_entities ? 9999 :
newnum = newindex >= to->num_entities ? to->entities[newindex].number;
9999 : to->entities[newindex].number; oldnum = oldindex >= oldmax ? 9999 : from->entities[oldindex].number;
oldnum = oldindex >= from->num_entities ?
9999 : from->entities[oldindex].number;
if (newnum == oldnum) { // delta update from old position if (newnum == oldnum) { // delta update from old position
// SV_Printf ("delta %i\n", newnum); // SV_Printf ("delta %i\n", newnum);
block.deltas[newindex] = to->entities[newindex]; SV_WriteDelta (&from->entities[oldindex], &to->entities[newindex],
block.deltas[newindex].flags = msg, false, client->stdver);
SV_EntityState_Diff (&from->entities[oldindex],
&to->entities[newindex]);
// check if it's a client that doesn't support QSG2
if (client->stdver <= 1)
block.deltas[newindex].flags &= U_VERSION_ID;
block.words[word] = newnum | (block.deltas[newindex].flags & ~511);
oldindex++; oldindex++;
newindex++; newindex++;
} else if (newnum < oldnum) { // this is a new entity, send continue;
// it from the baseline }
baseline = EDICT_NUM (&sv_pr_state, newnum)->data;
if (newnum < oldnum) { // this is a new entity, send it from
// the baseline
ent = EDICT_NUM (&sv_pr_state, newnum);
// SV_Printf ("baseline %i\n", newnum); // SV_Printf ("baseline %i\n", newnum);
block.deltas[newindex] = to->entities[newindex]; SV_WriteDelta (ent->data, &to->entities[newindex], msg, true,
block.deltas[newindex].flags = client->stdver);
SV_EntityState_Diff (baseline, &to->entities[newindex]);
// check if it's a client that doesn't support QSG2
if (client->stdver <= 1)
block.deltas[newindex].flags &= U_VERSION_ID;
block.words[word] = newnum | (block.deltas[newindex].flags & ~511);
newindex++; newindex++;
} else if (newnum > oldnum) { // the old entity isn't continue;
// present in the new message }
if (newnum > oldnum) { // the old entity isn't present in
// the new message
// SV_Printf ("remove %i\n", oldnum); // SV_Printf ("remove %i\n", oldnum);
block.words[word] = oldnum | U_REMOVE; MSG_WriteShort (msg, oldnum | U_REMOVE);
oldindex++; oldindex++;
continue;
} }
} }
block.words[word] = 0; MSG_WriteShort (msg, 0); // end of packetentities
MSG_WriteByte (msg, svc_deltapacketentities);
NET_SVC_DeltaPacketEntities_Emit (&block, msg);
} }
void void
SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs, SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs,
sizebuf_t *msg) sizebuf_t *msg)
{ {
int i, j; int i, j, msec, pflags;
client_t *cl; client_t *cl;
edict_t *ent; edict_t *ent;
net_svc_playerinfo_t block; usercmd_t cmd;
for (j = 0, cl = svs.clients; j < MAX_CLIENTS; j++, cl++) { for (j = 0, cl = svs.clients; j < MAX_CLIENTS; j++, cl++) {
if (cl->state != cs_spawned) if (cl->state != cs_spawned)
@ -435,63 +397,82 @@ SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs,
continue; // not visible continue; // not visible
} }
block.flags = PF_MSEC | PF_COMMAND; pflags = PF_MSEC | PF_COMMAND;
if (SVfloat (ent, modelindex) != sv_playermodel) if (SVfloat (ent, modelindex) != sv_playermodel)
block.flags |= PF_MODEL; pflags |= PF_MODEL;
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
if (SVvector (ent, velocity)[i]) if (SVvector (ent, velocity)[i])
block.flags |= PF_VELOCITY1 << i; pflags |= PF_VELOCITY1 << i;
if (SVfloat (ent, effects)) if (SVfloat (ent, effects))
block.flags |= PF_EFFECTS; pflags |= PF_EFFECTS;
if (SVfloat (ent, skin)) if (SVfloat (ent, skin))
block.flags |= PF_SKINNUM; pflags |= PF_SKINNUM;
if (SVfloat (ent, health) <= 0) if (SVfloat (ent, health) <= 0)
block.flags |= PF_DEAD; pflags |= PF_DEAD;
if (SVvector (ent, mins)[2] != -24) if (SVvector (ent, mins)[2] != -24)
block.flags |= PF_GIB; pflags |= PF_GIB;
if (cl->spectator) { // only sent origin and velocity to if (cl->spectator) { // only sent origin and velocity to
// spectators // spectators
block.flags &= PF_VELOCITY1 | PF_VELOCITY2 | PF_VELOCITY3; pflags &= PF_VELOCITY1 | PF_VELOCITY2 | PF_VELOCITY3;
} else if (ent == clent) { // don't send a lot of data on } else if (ent == clent) { // don't send a lot of data on
// personal entity // personal entity
block.flags &= ~(PF_MSEC | PF_COMMAND); pflags &= ~(PF_MSEC | PF_COMMAND);
if (SVfloat (ent, weaponframe)) if (SVfloat (ent, weaponframe))
block.flags |= PF_WEAPONFRAME; pflags |= PF_WEAPONFRAME;
} }
if (client->spec_track && client->spec_track - 1 == j && if (client->spec_track && client->spec_track - 1 == j &&
SVfloat (ent, weaponframe)) SVfloat (ent, weaponframe)) pflags |= PF_WEAPONFRAME;
block.flags |= PF_WEAPONFRAME;
block.playernum = j;
VectorCopy (SVvector (ent, origin), block.origin);
block.frame = SVfloat (ent, frame);
block.msec = 1000 * (sv.time - cl->localtime);
if (block.msec > 255)
block.msec = 255;
block.usercmd = cl->lastcmd;
if (SVfloat (ent, health) <= 0) { // don't show the corpse
// looking around...
block.usercmd.angles[0] = 0;
block.usercmd.angles[1] = SVvector (ent, angles)[1];
block.usercmd.angles[0] = 0;
}
block.usercmd.buttons = 0; // never send buttons
block.usercmd.impulse = 0; // never send impulses
VectorCopy (SVvector (ent, velocity), block.velocity);
block.modelindex = SVfloat (ent, modelindex);
block.skinnum = SVfloat (ent, skin);
block.effects = SVfloat (ent, effects);
block.weaponframe = SVfloat (ent, weaponframe);
MSG_WriteByte (msg, svc_playerinfo); MSG_WriteByte (msg, svc_playerinfo);
NET_SVC_Playerinfo_Emit (&block, msg); MSG_WriteByte (msg, j);
MSG_WriteShort (msg, pflags);
for (i = 0; i < 3; i++)
MSG_WriteCoord (msg, SVvector (ent, origin)[i]);
MSG_WriteByte (msg, SVfloat (ent, frame));
if (pflags & PF_MSEC) {
msec = 1000 * (sv.time - cl->localtime);
if (msec > 255)
msec = 255;
MSG_WriteByte (msg, msec);
}
if (pflags & PF_COMMAND) {
cmd = cl->lastcmd;
if (SVfloat (ent, health) <= 0) { // don't show the corpse
// looking around...
cmd.angles[0] = 0;
cmd.angles[1] = SVvector (ent, angles)[1];
cmd.angles[0] = 0;
}
cmd.buttons = 0; // never send buttons
cmd.impulse = 0; // never send impulses
MSG_WriteDeltaUsercmd (msg, &nullcmd, &cmd);
}
for (i = 0; i < 3; i++)
if (pflags & (PF_VELOCITY1 << i))
MSG_WriteShort (msg, SVvector (ent, velocity)[i]);
if (pflags & PF_MODEL)
MSG_WriteByte (msg, SVfloat (ent, modelindex));
if (pflags & PF_SKINNUM)
MSG_WriteByte (msg, SVfloat (ent, skin));
if (pflags & PF_EFFECTS)
MSG_WriteByte (msg, SVfloat (ent, effects));
if (pflags & PF_WEAPONFRAME)
MSG_WriteByte (msg, SVfloat (ent, weaponframe));
} }
} }
@ -610,9 +591,7 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
// encode the packet entities as a delta from the // encode the packet entities as a delta from the
// last packetentities acknowledged by the client // last packetentities acknowledged by the client
if (client->delta_sequence != -1)
SV_EmitDeltaPacketEntities (client, pack, msg);
else
SV_EmitPacketEntities (client, pack, msg); SV_EmitPacketEntities (client, pack, msg);
// now add the specialized nail update // now add the specialized nail update

View file

@ -46,7 +46,6 @@ static const char rcsid[] =
#include "compat.h" #include "compat.h"
#include "crudefile.h" #include "crudefile.h"
#include "net_svc.h"
#include "server.h" #include "server.h"
#include "sv_progs.h" #include "sv_progs.h"
#include "world.h" #include "world.h"
@ -105,9 +104,8 @@ SV_FlushSignon (void)
void void
SV_CreateBaseline (void) SV_CreateBaseline (void)
{ {
int entnum; int i, entnum;
edict_t *svent; edict_t *svent;
net_svc_spawnbaseline_t block;
for (entnum = 0; entnum < sv.num_edicts; entnum++) { for (entnum = 0; entnum < sv.num_edicts; entnum++) {
svent = EDICT_NUM (&sv_pr_state, entnum); svent = EDICT_NUM (&sv_pr_state, entnum);
@ -145,15 +143,19 @@ SV_CreateBaseline (void)
SV_FlushSignon (); SV_FlushSignon ();
// add to the message // add to the message
block.num = entnum;
block.modelindex = ((entity_state_t*)svent->data)->modelindex;
block.frame = ((entity_state_t*)svent->data)->frame;
block.colormap = ((entity_state_t*)svent->data)->colormap;
block.skinnum = ((entity_state_t*)svent->data)->skinnum;
VectorCopy (((entity_state_t*)svent->data)->origin, block.origin);
VectorCopy (((entity_state_t*)svent->data)->angles, block.angles);
MSG_WriteByte (&sv.signon, svc_spawnbaseline); MSG_WriteByte (&sv.signon, svc_spawnbaseline);
NET_SVC_SpawnBaseline_Emit (&block, &sv.signon); MSG_WriteShort (&sv.signon, entnum);
MSG_WriteByte (&sv.signon, ((entity_state_t*)svent->data)->modelindex);
MSG_WriteByte (&sv.signon, ((entity_state_t*)svent->data)->frame);
MSG_WriteByte (&sv.signon, ((entity_state_t*)svent->data)->colormap);
MSG_WriteByte (&sv.signon, ((entity_state_t*)svent->data)->skinnum);
for (i = 0; i < 3; i++) {
MSG_WriteCoord (&sv.signon,
((entity_state_t*)svent->data)->origin[i]);
MSG_WriteAngle (&sv.signon,
((entity_state_t*)svent->data)->angles[i]);
}
} }
} }

View file

@ -76,7 +76,6 @@ static const char rcsid[] =
#include "crudefile.h" #include "crudefile.h"
#include "game.h" #include "game.h"
#include "net.h" #include "net.h"
#include "net_svc.h"
#include "pmove.h" #include "pmove.h"
#include "server.h" #include "server.h"
#include "sv_progs.h" #include "sv_progs.h"
@ -261,14 +260,11 @@ SV_FinalMessage (const char *message)
{ {
client_t *cl; client_t *cl;
int i; int i;
net_svc_print_t block;
block.level = PRINT_HIGH;
block.message = message;
SZ_Clear (net_message->message); SZ_Clear (net_message->message);
MSG_WriteByte (net_message->message, svc_print); MSG_WriteByte (net_message->message, svc_print);
NET_SVC_Print_Emit (&block, net_message->message); MSG_WriteByte (net_message->message, PRINT_HIGH);
MSG_WriteString (net_message->message, message);
MSG_WriteByte (net_message->message, svc_disconnect); MSG_WriteByte (net_message->message, svc_disconnect);
for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
@ -373,7 +369,6 @@ SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
{ {
char *info; char *info;
int i; int i;
net_svc_updateuserinfo_t block;
i = client - svs.clients; i = client - svs.clients;
@ -398,11 +393,10 @@ SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
info = client->userinfo ? Info_MakeString (client->userinfo, info = client->userinfo ? Info_MakeString (client->userinfo,
make_info_string_filter) : ""; make_info_string_filter) : "";
block.slot = i;
block.userid = client->userid;
block.userinfo = info;
MSG_WriteByte (buf, svc_updateuserinfo); MSG_WriteByte (buf, svc_updateuserinfo);
NET_SVC_UpdateUserInfo_Emit (&block, buf); MSG_WriteByte (buf, i);
MSG_WriteLong (buf, client->userid);
MSG_WriteString (buf, info);
} }
/* /*
@ -2177,7 +2171,6 @@ Master_Shutdown (void)
static inline qboolean static inline qboolean
iswhitespace (char c) iswhitespace (char c)
{ {
c &= 127;
return c == ' ' || c == '\r' || c == '\n' || c == '\t'; return c == ' ' || c == '\r' || c == '\n' || c == '\t';
} }
@ -2207,9 +2200,9 @@ SV_ExtractFromUserinfo (client_t *cl)
for (r = newname; *p && r != newname + sizeof (newname) - 1; p++) { for (r = newname; *p && r != newname + sizeof (newname) - 1; p++) {
if (iswhitespace (*p)) { if (iswhitespace (*p)) {
if (!iswhitespace (p[1]) && p[1] != '\0') if (!iswhitespace (p[1]) && p[1] != '\0')
*r++ = ' '; // get rid of any special chars *r++ = *p;
} else } else
*r++ = *p & 127; // get rid of bold *r++ = *p;
} }
*r = '\0'; *r = '\0';
@ -2217,14 +2210,6 @@ SV_ExtractFromUserinfo (client_t *cl)
if (!*newname) if (!*newname)
badname = true; badname = true;
// ':' is used in chat messages
if (strchr (newname, ':'))
badname = true;
// I dunno if this is possible, but better safe than sorry
if (strchr (newname, '"'))
badname = true;
// impersonating an user-xxx name. if they're using it // impersonating an user-xxx name. if they're using it
// legitimately it'll be a no-op later on // legitimately it'll be a no-op later on
if (!strncasecmp (newname, "user-", 5)) if (!strncasecmp (newname, "user-", 5))
@ -2283,10 +2268,9 @@ SV_ExtractFromUserinfo (client_t *cl)
} }
} }
// finally, report it to all our friends, but only if more // finally, report it to all our friends
// than whitespace changed
// if (cl->state >= cs_spawned && !cl->spectator) // if (cl->state >= cs_spawned && !cl->spectator)
if (*cl->name && strcmp (cl->name, newname)) if (*cl->name)
SV_BroadcastPrintf (PRINT_HIGH, "%s changed name to %s\n", SV_BroadcastPrintf (PRINT_HIGH, "%s changed name to %s\n",
cl->name, newname); cl->name, newname);
strcpy (cl->name, newname); strcpy (cl->name, newname);

View file

@ -36,6 +36,7 @@ static const char rcsid[] =
#include "QF/model.h" #include "QF/model.h"
const int mod_lightmap_bytes = 1; const int mod_lightmap_bytes = 1;
cvar_t *gl_sky_divide; // not used but needed for linking
void Mod_LoadBrushModel (model_t *mod, void *buffer); void Mod_LoadBrushModel (model_t *mod, void *buffer);

View file

@ -607,14 +607,14 @@ SV_CheckWaterTransition (edict_t *ent)
if (cont <= CONTENTS_WATER) { if (cont <= CONTENTS_WATER) {
if (SVfloat (ent, watertype) == CONTENTS_EMPTY) { if (SVfloat (ent, watertype) == CONTENTS_EMPTY) {
// just crossed into water // just crossed into water
SV_StartSound (ent, 0, "misc/h2ohit1.wav", 1, 1); SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
} }
SVfloat (ent, watertype) = cont; SVfloat (ent, watertype) = cont;
SVfloat (ent, waterlevel) = 1; SVfloat (ent, waterlevel) = 1;
} else { } else {
if (SVfloat (ent, watertype) != CONTENTS_EMPTY) { if (SVfloat (ent, watertype) != CONTENTS_EMPTY) {
// just crossed into water // just crossed into water
SV_StartSound (ent, 0, "misc/h2ohit1.wav", 1, 1); SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
} }
SVfloat (ent, watertype) = CONTENTS_EMPTY; SVfloat (ent, watertype) = CONTENTS_EMPTY;
SVfloat (ent, waterlevel) = cont; SVfloat (ent, waterlevel) = cont;
@ -717,7 +717,7 @@ SV_Physics_Step (edict_t *ent)
if ((int) SVfloat (ent, flags) & FL_ONGROUND) // just hit ground if ((int) SVfloat (ent, flags) & FL_ONGROUND) // just hit ground
{ {
if (hitsound) if (hitsound)
SV_StartSound (ent, 0, "demon/dland2.wav", 1, 1); SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
} }
} }
// regular thinking // regular thinking

View file

@ -45,7 +45,6 @@ static const char rcsid[] =
#include "compat.h" #include "compat.h"
#include "crudefile.h" #include "crudefile.h"
#include "net_svc.h"
#include "server.h" #include "server.h"
#include "sv_pr_cmds.h" #include "sv_pr_cmds.h"
#include "sv_progs.h" #include "sv_progs.h"
@ -280,16 +279,17 @@ PF_ambientsound (progs_t *pr)
{ {
const char **check; const char **check;
const char *samp; const char *samp;
net_svc_spawnstaticsound_t block; float *pos;
float vol, attenuation;
int i, soundnum;
VectorCopy (G_VECTOR (pr, OFS_PARM0), block.position); pos = G_VECTOR (pr, OFS_PARM0);
samp = G_STRING (pr, OFS_PARM1); samp = G_STRING (pr, OFS_PARM1);
block.volume = G_FLOAT (pr, OFS_PARM2) * 255; vol = G_FLOAT (pr, OFS_PARM2);
block.attenuation = G_FLOAT (pr, OFS_PARM3) * 64; attenuation = G_FLOAT (pr, OFS_PARM3);
// check to see if samp was properly precached // check to see if samp was properly precached
for (block.sound_num = 0, check = sv.sound_precache; *check; for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++)
check++, block.sound_num++)
if (!strcmp (*check, samp)) if (!strcmp (*check, samp))
break; break;
@ -300,7 +300,14 @@ PF_ambientsound (progs_t *pr)
// add an svc_spawnambient command to the level signon packet // add an svc_spawnambient command to the level signon packet
MSG_WriteByte (&sv.signon, svc_spawnstaticsound); MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
NET_SVC_SpawnStaticSound_Emit (&block, &sv.signon); for (i = 0; i < 3; i++)
MSG_WriteCoord (&sv.signon, pos[i]);
MSG_WriteByte (&sv.signon, soundnum);
MSG_WriteByte (&sv.signon, vol * 255);
MSG_WriteByte (&sv.signon, attenuation * 64);
} }
/* /*
@ -320,13 +327,13 @@ PF_sound (progs_t *pr)
{ {
const char *sample; const char *sample;
edict_t *entity; edict_t *entity;
float volume, attenuation; float attenuation;
int channel; int channel, volume;
entity = G_EDICT (pr, OFS_PARM0); entity = G_EDICT (pr, OFS_PARM0);
channel = G_FLOAT (pr, OFS_PARM1); channel = G_FLOAT (pr, OFS_PARM1);
sample = G_STRING (pr, OFS_PARM2); sample = G_STRING (pr, OFS_PARM2);
volume = G_FLOAT (pr, OFS_PARM3); volume = G_FLOAT (pr, OFS_PARM3) * 255;
attenuation = G_FLOAT (pr, OFS_PARM4); attenuation = G_FLOAT (pr, OFS_PARM4);
SV_StartSound (entity, channel, sample, volume, attenuation); SV_StartSound (entity, channel, sample, volume, attenuation);
@ -1135,21 +1142,25 @@ int SV_ModelIndex (const char *name);
void void
PF_makestatic (progs_t *pr) PF_makestatic (progs_t *pr)
{ {
const char *model;
edict_t *ent; edict_t *ent;
net_svc_spawnstatic_t block; int i;
ent = G_EDICT (pr, OFS_PARM0); ent = G_EDICT (pr, OFS_PARM0);
// SV_Printf ("Model: %d %s\n", SVstring (ent, model), model);
block.modelindex = SV_ModelIndex (PR_GetString (pr, SVstring (ent, model)));
block.frame = SVfloat (ent, frame);
block.colormap = SVfloat (ent, colormap);
block.skinnum = SVfloat (ent, skin);
VectorCopy (SVvector (ent, origin), block.origin);
VectorCopy (SVvector (ent, angles), block.angles);
MSG_WriteByte (&sv.signon, svc_spawnstatic); MSG_WriteByte (&sv.signon, svc_spawnstatic);
NET_SVC_SpawnStatic_Emit (&block, &sv.signon);
model = PR_GetString (pr, SVstring (ent, model));
// SV_Printf ("Model: %d %s\n", SVstring (ent, model), model);
MSG_WriteByte (&sv.signon, SV_ModelIndex (model));
MSG_WriteByte (&sv.signon, SVfloat (ent, frame));
MSG_WriteByte (&sv.signon, SVfloat (ent, colormap));
MSG_WriteByte (&sv.signon, SVfloat (ent, skin));
for (i = 0; i < 3; i++) {
MSG_WriteCoord (&sv.signon, SVvector (ent, origin)[i]);
MSG_WriteAngle (&sv.signon, SVvector (ent, angles)[i]);
}
// throw the entity away now // throw the entity away now
ED_Free (pr, ent); ED_Free (pr, ent);
@ -1358,7 +1369,6 @@ PF_setinfokey (progs_t *pr)
int e1 = NUM_FOR_EDICT (pr, edict); int e1 = NUM_FOR_EDICT (pr, edict);
const char *key = G_STRING (pr, OFS_PARM1); const char *key = G_STRING (pr, OFS_PARM1);
const char *value = G_STRING (pr, OFS_PARM2); const char *value = G_STRING (pr, OFS_PARM2);
net_svc_setinfo_t block;
if (e1 == 0) { if (e1 == 0) {
if (*value) if (*value)
@ -1372,11 +1382,12 @@ PF_setinfokey (progs_t *pr)
SV_ExtractFromUserinfo (&svs.clients[e1 - 1]); SV_ExtractFromUserinfo (&svs.clients[e1 - 1]);
if (Info_FilterForKey (key, client_info_filters)) { if (Info_FilterForKey (key, client_info_filters)) {
block.slot = e1 - 1;
block.key = key;
block.value = Info_ValueForKey (svs.clients[e1 - 1].userinfo, key);
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
NET_SVC_SetInfo_Emit (&block, &sv.reliable_datagram); MSG_WriteByte (&sv.reliable_datagram, e1 - 1);
MSG_WriteString (&sv.reliable_datagram, key);
MSG_WriteString (&sv.reliable_datagram,
Info_ValueForKey (svs.clients[e1 - 1].userinfo,
key));
} }
} }
} }

View file

@ -49,7 +49,6 @@ static const char rcsid[] =
#include "bothdefs.h" #include "bothdefs.h"
#include "compat.h" #include "compat.h"
#include "net_svc.h"
#include "server.h" #include "server.h"
#include "sv_progs.h" #include "sv_progs.h"
@ -70,7 +69,6 @@ void
SV_FlushRedirect (void) SV_FlushRedirect (void)
{ {
char send[8000 + 6]; char send[8000 + 6];
net_svc_print_t block;
if (sv_redirected == RD_PACKET) { if (sv_redirected == RD_PACKET) {
send[0] = 0xff; send[0] = 0xff;
@ -82,15 +80,10 @@ SV_FlushRedirect (void)
NET_SendPacket (strlen (send) + 1, send, net_from); NET_SendPacket (strlen (send) + 1, send, net_from);
} else if (sv_redirected == RD_CLIENT) { } else if (sv_redirected == RD_CLIENT) {
block.level = PRINT_HIGH;
block.message = outputbuf;
ClientReliableWrite_Begin (host_client, svc_print, ClientReliableWrite_Begin (host_client, svc_print,
strlen (outputbuf) + 3); strlen (outputbuf) + 3);
if (host_client->num_backbuf) { ClientReliableWrite_Byte (host_client, PRINT_HIGH);
NET_SVC_Print_Emit (&block, &host_client->backbuf); ClientReliableWrite_String (host_client, outputbuf);
ClientReliable_FinishWrite (host_client);
} else
NET_SVC_Print_Emit (&block, &host_client->netchan.message);
} }
// clear it // clear it
outputbuf[0] = 0; outputbuf[0] = 0;
@ -227,7 +220,6 @@ SV_PrintToClient (client_t *cl, int level, const char *string)
unsigned char *b; unsigned char *b;
int size; int size;
static int buffer_size; static int buffer_size;
net_svc_print_t block;
size = strlen (string) + 1; size = strlen (string) + 1;
if (size > buffer_size) { if (size > buffer_size) {
@ -247,14 +239,9 @@ SV_PrintToClient (client_t *cl, int level, const char *string)
if (*b != 0xFF) if (*b != 0xFF)
b++; b++;
block.level = level;
block.message = buffer;
ClientReliableWrite_Begin (cl, svc_print, strlen (buffer) + 3); ClientReliableWrite_Begin (cl, svc_print, strlen (buffer) + 3);
if (cl->num_backbuf) { ClientReliableWrite_Byte (cl, level);
NET_SVC_Print_Emit (&block, &cl->backbuf); ClientReliableWrite_String (cl, buffer);
ClientReliable_FinishWrite (cl);
} else
NET_SVC_Print_Emit (&block, &cl->netchan.message);
} }
/* /*
@ -429,16 +416,16 @@ SV_Multicast (vec3_t origin, int to)
Larger attenuations will drop off. (max 4 attenuation) Larger attenuations will drop off. (max 4 attenuation)
*/ */
void void
SV_StartSound (edict_t *entity, int channel, const char *sample, SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
float volume, float attenuation) float attenuation)
{ {
int i, sound_num; int ent, field_mask, sound_num, i;
qboolean use_phs; qboolean use_phs;
qboolean reliable = false; qboolean reliable = false;
net_svc_sound_t block; vec3_t origin;
if (volume < 0 || volume > 1) if (volume < 0 || volume > 255)
SV_Error ("SV_StartSound: volume = %f", volume); SV_Error ("SV_StartSound: volume = %i", volume);
if (attenuation < 0 || attenuation > 4) if (attenuation < 0 || attenuation > 4)
SV_Error ("SV_StartSound: attenuation = %f", attenuation); SV_Error ("SV_StartSound: attenuation = %f", attenuation);
@ -457,9 +444,7 @@ SV_StartSound (edict_t *entity, int channel, const char *sample,
return; return;
} }
block.sound_num = sound_num; ent = NUM_FOR_EDICT (&sv_pr_state, entity);
block.entity = NUM_FOR_EDICT (&sv_pr_state, entity);
if ((channel & 8) || !sv_phs->int_val) // no PHS flag if ((channel & 8) || !sv_phs->int_val) // no PHS flag
{ {
@ -474,34 +459,37 @@ SV_StartSound (edict_t *entity, int channel, const char *sample,
// if (channel == CHAN_BODY || channel == CHAN_VOICE) // if (channel == CHAN_BODY || channel == CHAN_VOICE)
// reliable = true; // reliable = true;
block.channel = channel; channel = (ent << 3) | channel;
block.volume = volume; field_mask = 0;
// 4 * 64 == 256, which overflows a byte. 4 is the stated max for if (volume != DEFAULT_SOUND_PACKET_VOLUME)
// it, and I don't want to break any progs, so I just nudge it channel |= SND_VOLUME;
// down instead if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
if (attenuation == 4) channel |= SND_ATTENUATION;
attenuation = 3.999;
block.attenuation = attenuation;
// use the entity origin unless it is a bmodel // use the entity origin unless it is a bmodel
if (SVfloat (entity, solid) == SOLID_BSP) { if (SVfloat (entity, solid) == SOLID_BSP) {
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
block.position[i] = SVvector (entity, origin)[i] + 0.5 * origin[i] = SVvector (entity, origin)[i] + 0.5 *
(SVvector (entity, mins)[i] + SVvector (entity, maxs)[i]); (SVvector (entity, mins)[i] + SVvector (entity, maxs)[i]);
} else { } else {
VectorCopy (SVvector (entity, origin), block.position); VectorCopy (SVvector (entity, origin), origin);
} }
MSG_WriteByte (&sv.multicast, svc_sound); MSG_WriteByte (&sv.multicast, svc_sound);
NET_SVC_Sound_Emit (&block, &sv.multicast); MSG_WriteShort (&sv.multicast, channel);
if (channel & SND_VOLUME)
MSG_WriteByte (&sv.multicast, volume);
if (channel & SND_ATTENUATION)
MSG_WriteByte (&sv.multicast, attenuation * 64);
MSG_WriteByte (&sv.multicast, sound_num);
for (i = 0; i < 3; i++)
MSG_WriteCoord (&sv.multicast, origin[i]);
if (use_phs) if (use_phs)
SV_Multicast (block.position, SV_Multicast (origin, reliable ? MULTICAST_PHS_R : MULTICAST_PHS);
reliable ? MULTICAST_PHS_R : MULTICAST_PHS);
else else
SV_Multicast (block.position, SV_Multicast (origin, reliable ? MULTICAST_ALL_R : MULTICAST_ALL);
reliable ? MULTICAST_ALL_R : MULTICAST_ALL);
} }
/* FRAME UPDATES */ /* FRAME UPDATES */
@ -534,7 +522,6 @@ SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
{ {
edict_t *ent, *other; edict_t *ent, *other;
int i; int i;
net_svc_damage_t block;
ent = client->edict; ent = client->edict;
@ -547,14 +534,13 @@ SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
// send a damage message if the player got hit this frame // send a damage message if the player got hit this frame
if (SVfloat (ent, dmg_take) || SVfloat (ent, dmg_save)) { if (SVfloat (ent, dmg_take) || SVfloat (ent, dmg_save)) {
other = PROG_TO_EDICT (&sv_pr_state, SVentity (ent, dmg_inflictor)); other = PROG_TO_EDICT (&sv_pr_state, SVentity (ent, dmg_inflictor));
block.armor = SVfloat (ent, dmg_save);
block.blood = SVfloat (ent, dmg_take);
for (i = 0; i < 3; i++)
block.from[i] = SVvector (other, origin)[i] + 0.5 *
(SVvector (other, mins)[i] +
SVvector (other, maxs)[i]);
MSG_WriteByte (msg, svc_damage); MSG_WriteByte (msg, svc_damage);
NET_SVC_Damage_Emit (&block, msg); MSG_WriteByte (msg, SVfloat (ent, dmg_save));
MSG_WriteByte (msg, SVfloat (ent, dmg_take));
for (i = 0; i < 3; i++)
MSG_WriteCoord (msg, SVvector (other, origin)[i] + 0.5 *
(SVvector (other, mins)[i] +
SVvector (other, maxs)[i]));
SVfloat (ent, dmg_take) = 0; SVfloat (ent, dmg_take) = 0;
SVfloat (ent, dmg_save) = 0; SVfloat (ent, dmg_save) = 0;
@ -794,6 +780,7 @@ SV_SendClientMessages (void)
// if the reliable message overflowed, drop the client // if the reliable message overflowed, drop the client
if (c->netchan.message.overflowed) { if (c->netchan.message.overflowed) {
int i; int i;
extern void Analyze_Server_Packet (byte *data, int len);
byte *data = Hunk_TempAlloc (MAX_MSGLEN + 8); byte *data = Hunk_TempAlloc (MAX_MSGLEN + 8);
memset (data, 0, 8); memset (data, 0, 8);

View file

@ -54,7 +54,6 @@ static const char rcsid[] =
#include "compat.h" #include "compat.h"
#include "bothdefs.h" #include "bothdefs.h"
#include "msg_ucmd.h" #include "msg_ucmd.h"
#include "net_svc.h"
#include "pmove.h" #include "pmove.h"
#include "server.h" #include "server.h"
#include "sv_progs.h" #include "sv_progs.h"
@ -97,7 +96,7 @@ void
SV_New_f (void) SV_New_f (void)
{ {
const char *gamedir; const char *gamedir;
net_svc_serverdata_t block; int playernum;
if (host_client->state == cs_spawned) if (host_client->state == cs_spawned)
return; return;
@ -116,23 +115,37 @@ SV_New_f (void)
//NOTE: This doesn't go through ClientReliableWrite since it's before the user //NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow //spawns. These functions are written to not overflow
if (host_client->num_backbuf) { if (host_client->num_backbuf) {
SV_Printf ("WARNING %s: [SV_New] Back buffered (%d), clearing\n", SV_Printf ("WARNING %s: [SV_New] Back buffered (%d0, clearing\n",
host_client->name, host_client->netchan.message.cursize); host_client->name, host_client->netchan.message.cursize);
host_client->num_backbuf = 0; host_client->num_backbuf = 0;
SZ_Clear (&host_client->netchan.message); SZ_Clear (&host_client->netchan.message);
} }
// send the serverdata // send the serverdata
block.protocolversion = PROTOCOL_VERSION;
block.servercount = svs.spawncount;
block.gamedir = gamedir;
block.playernum = NUM_FOR_EDICT (&sv_pr_state, host_client->edict) - 1;
block.spectator = host_client->spectator;
block.levelname = PR_GetString (&sv_pr_state,
SVstring (sv.edicts, message));
block.movevars = movevars;
MSG_WriteByte (&host_client->netchan.message, svc_serverdata); MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
NET_SVC_ServerData_Emit (&block, &host_client->netchan.message); MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
MSG_WriteString (&host_client->netchan.message, gamedir);
playernum = NUM_FOR_EDICT (&sv_pr_state, host_client->edict) - 1;
if (host_client->spectator)
playernum |= 128;
MSG_WriteByte (&host_client->netchan.message, playernum);
// send full levelname
MSG_WriteString (&host_client->netchan.message,
PR_GetString (&sv_pr_state, SVstring (sv.edicts, message)));
// send the movevars
MSG_WriteFloat (&host_client->netchan.message, movevars.gravity);
MSG_WriteFloat (&host_client->netchan.message, movevars.stopspeed);
MSG_WriteFloat (&host_client->netchan.message, movevars.maxspeed);
MSG_WriteFloat (&host_client->netchan.message, movevars.spectatormaxspeed);
MSG_WriteFloat (&host_client->netchan.message, movevars.accelerate);
MSG_WriteFloat (&host_client->netchan.message, movevars.airaccelerate);
MSG_WriteFloat (&host_client->netchan.message, movevars.wateraccelerate);
MSG_WriteFloat (&host_client->netchan.message, movevars.friction);
MSG_WriteFloat (&host_client->netchan.message, movevars.waterfriction);
MSG_WriteFloat (&host_client->netchan.message, movevars.entgravity);
// send music // send music
MSG_WriteByte (&host_client->netchan.message, svc_cdtrack); MSG_WriteByte (&host_client->netchan.message, svc_cdtrack);
@ -152,14 +165,12 @@ void
SV_Soundlist_f (void) SV_Soundlist_f (void)
{ {
const char **s; const char **s;
int i, size; unsigned n;
net_svc_soundlist_t block;
if (host_client->state != cs_connected) { if (host_client->state != cs_connected) {
SV_Printf ("soundlist not valid -- already spawned\n"); SV_Printf ("soundlist not valid -- already spawned\n");
return; return;
} }
// handle the case of a level changing while a client was connecting // handle the case of a level changing while a client was connecting
if (atoi (Cmd_Argv (1)) != svs.spawncount) { if (atoi (Cmd_Argv (1)) != svs.spawncount) {
SV_Printf ("SV_Soundlist_f from different level\n"); SV_Printf ("SV_Soundlist_f from different level\n");
@ -167,40 +178,34 @@ SV_Soundlist_f (void)
return; return;
} }
block.startsound = atoi (Cmd_Argv (2)); n = atoi (Cmd_Argv (2));
if (block.startsound >= MAX_SOUNDS) { if (n >= MAX_SOUNDS) {
SV_Printf ("SV_Soundlist_f: Invalid soundlist index\n"); SV_Printf ("SV_Soundlist_f: Invalid soundlist index\n");
SV_New_f (); SV_New_f ();
return; return;
} }
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
// NOTE: This doesn't go through ClientReliableWrite since it's //spawns. These functions are written to not overflow
// before the user spawns. These functions are written to not
// overflow
if (host_client->num_backbuf) { if (host_client->num_backbuf) {
SV_Printf ("WARNING %s: [SV_Soundlist] Back buffered (%d), clearing", SV_Printf ("WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing",
host_client->name, host_client->netchan.message.cursize); host_client->name, host_client->netchan.message.cursize);
host_client->num_backbuf = 0; host_client->num_backbuf = 0;
SZ_Clear (&host_client->netchan.message); SZ_Clear (&host_client->netchan.message);
} }
for (s = sv.sound_precache + 1 + block.startsound, i = 0, size = 0; MSG_WriteByte (&host_client->netchan.message, svc_soundlist);
*s; i++, s++) { MSG_WriteByte (&host_client->netchan.message, n);
if (host_client->netchan.message.cursize + size >= (MAX_MSGLEN / 2)) for (s = sv.sound_precache + 1 + n;
break; *s && host_client->netchan.message.cursize < (MAX_MSGLEN / 2);
size += strlen (*s) + 1; s++, n++) MSG_WriteString (&host_client->netchan.message, *s);
block.sounds[i] = *s;
} MSG_WriteByte (&host_client->netchan.message, 0);
block.sounds[i] = "";
// next msg // next msg
if (*s) if (*s)
block.nextsound = block.startsound + i; MSG_WriteByte (&host_client->netchan.message, n);
else else
block.nextsound = 0; MSG_WriteByte (&host_client->netchan.message, 0);
MSG_WriteByte (&host_client->netchan.message, svc_soundlist);
NET_SVC_Soundlist_Emit (&block, &host_client->netchan.message);
} }
/* /*
@ -210,14 +215,12 @@ void
SV_Modellist_f (void) SV_Modellist_f (void)
{ {
const char **s; const char **s;
int i, size; unsigned n;
net_svc_modellist_t block;
if (host_client->state != cs_connected) { if (host_client->state != cs_connected) {
SV_Printf ("modellist not valid -- already spawned\n"); SV_Printf ("modellist not valid -- already spawned\n");
return; return;
} }
// handle the case of a level changing while a client was connecting // handle the case of a level changing while a client was connecting
if (atoi (Cmd_Argv (1)) != svs.spawncount) { if (atoi (Cmd_Argv (1)) != svs.spawncount) {
SV_Printf ("SV_Modellist_f from different level\n"); SV_Printf ("SV_Modellist_f from different level\n");
@ -225,40 +228,33 @@ SV_Modellist_f (void)
return; return;
} }
block.startmodel = atoi (Cmd_Argv (2)); n = atoi (Cmd_Argv (2));
if (block.startmodel >= MAX_MODELS) { if (n >= MAX_MODELS) {
SV_Printf ("SV_Modellist_f: Invalid modellist index\n"); SV_Printf ("SV_Modellist_f: Invalid modellist index\n");
SV_New_f (); SV_New_f ();
return; return;
} }
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
// NOTE: This doesn't go through ClientReliableWrite since it's //spawns. These functions are written to not overflow
// before the user spawns. These functions are written to not
// overflow
if (host_client->num_backbuf) { if (host_client->num_backbuf) {
SV_Printf ("WARNING %s: [SV_Modellist] Back buffered (%d), clearing", SV_Printf ("WARNING %s: [SV_Modellist] Back buffered (%d0, clearing",
host_client->name, host_client->netchan.message.cursize); host_client->name, host_client->netchan.message.cursize);
host_client->num_backbuf = 0; host_client->num_backbuf = 0;
SZ_Clear (&host_client->netchan.message); SZ_Clear (&host_client->netchan.message);
} }
for (s = sv.model_precache + 1 + block.startmodel, i = 0, size = 0; MSG_WriteByte (&host_client->netchan.message, svc_modellist);
*s; i++, s++) { MSG_WriteByte (&host_client->netchan.message, n);
if (host_client->netchan.message.cursize + size >= (MAX_MSGLEN / 2)) for (s = sv.model_precache + 1 + n;
break; *s && host_client->netchan.message.cursize < (MAX_MSGLEN / 2);
size += strlen (*s) + 1; s++, n++) MSG_WriteString (&host_client->netchan.message, *s);
block.models[i] = *s; MSG_WriteByte (&host_client->netchan.message, 0);
}
block.models[i] = "";
// next msg // next msg
if (*s) if (*s)
block.nextmodel = block.startmodel + i; MSG_WriteByte (&host_client->netchan.message, n);
else else
block.nextmodel = 0; MSG_WriteByte (&host_client->netchan.message, 0);
MSG_WriteByte (&host_client->netchan.message, svc_modellist);
NET_SVC_Modellist_Emit (&block, &host_client->netchan.message);
} }
/* /*
@ -566,27 +562,27 @@ void
SV_NextDownload_f (void) SV_NextDownload_f (void)
{ {
byte buffer[1024]; byte buffer[1024];
net_svc_download_t block; int r;
int percent;
int size;
if (!host_client->download) if (!host_client->download)
return; return;
block.size = host_client->downloadsize - host_client->downloadcount; r = host_client->downloadsize - host_client->downloadcount;
if (block.size > 768) if (r > 768)
block.size = 768; r = 768;
block.size = Qread (host_client->download, buffer, block.size); r = Qread (host_client->download, buffer, r);
ClientReliableWrite_Begin (host_client, svc_download, 6 + r);
ClientReliableWrite_Short (host_client, r);
host_client->downloadcount += block.size; host_client->downloadcount += r;
block.percent = host_client->downloadcount * 100 / size = host_client->downloadsize;
(host_client->downloadsize ?: 1); if (!size)
size = 1;
block.data = buffer; percent = host_client->downloadcount * 100 / size;
ClientReliableWrite_Begin (host_client, svc_download, 6 + block.size); ClientReliableWrite_Byte (host_client, percent);
if (host_client->num_backbuf) { ClientReliableWrite_SZ (host_client, buffer, r);
NET_SVC_Download_Emit (&block, &host_client->backbuf);
ClientReliable_FinishWrite (host_client);
} else
NET_SVC_Download_Emit (&block, &host_client->netchan.message);
if (host_client->downloadcount != host_client->downloadsize) if (host_client->downloadcount != host_client->downloadsize)
return; return;
@ -695,7 +691,6 @@ SV_BeginDownload_f (void)
int size; int size;
char realname[MAX_OSPATH]; char realname[MAX_OSPATH];
int zip; int zip;
net_svc_download_t block;
name = Cmd_Argv (1); name = Cmd_Argv (1);
// hacked by zoid to allow more conrol over download // hacked by zoid to allow more conrol over download
@ -713,14 +708,9 @@ SV_BeginDownload_f (void)
|| (strncmp (name, "maps/", 5) == 0 && !allow_download_maps->int_val) || (strncmp (name, "maps/", 5) == 0 && !allow_download_maps->int_val)
// MUST be in a subdirectory // MUST be in a subdirectory
|| !strstr (name, "/")) { // don't allow anything with .. path || !strstr (name, "/")) { // don't allow anything with .. path
block.size = -1;
block.percent = 0;
ClientReliableWrite_Begin (host_client, svc_download, 4); ClientReliableWrite_Begin (host_client, svc_download, 4);
if (host_client->num_backbuf) { ClientReliableWrite_Short (host_client, -1);
NET_SVC_Download_Emit (&block, &host_client->backbuf); ClientReliableWrite_Byte (host_client, 0);
ClientReliable_FinishWrite (host_client);
} else
NET_SVC_Download_Emit (&block, &host_client->netchan.message);
return; return;
} }
@ -756,30 +746,19 @@ SV_BeginDownload_f (void)
} }
SV_Printf ("Couldn't download %s to %s\n", name, host_client->name); SV_Printf ("Couldn't download %s to %s\n", name, host_client->name);
block.size = -1;
block.percent = 0;
ClientReliableWrite_Begin (host_client, svc_download, 4); ClientReliableWrite_Begin (host_client, svc_download, 4);
if (host_client->num_backbuf) { ClientReliableWrite_Short (host_client, -1);
NET_SVC_Download_Emit (&block, &host_client->backbuf); ClientReliableWrite_Byte (host_client, 0);
ClientReliable_FinishWrite (host_client);
} else
NET_SVC_Download_Emit (&block, &host_client->netchan.message);
return; return;
} }
if (zip && strcmp (realname, name)) { if (zip && strcmp (realname, name)) {
SV_Printf ("download renamed to %s\n", realname); SV_Printf ("download renamed to %s\n", realname);
block.size = -2;
block.percent = 0;
block.name = realname;
ClientReliableWrite_Begin (host_client, svc_download, ClientReliableWrite_Begin (host_client, svc_download,
strlen (realname) + 5); strlen (realname) + 5);
if (host_client->num_backbuf) ClientReliableWrite_Short (host_client, -2);
NET_SVC_Download_Emit (&block, &host_client->backbuf); ClientReliableWrite_Byte (host_client, 0);
else ClientReliableWrite_String (host_client, realname);
NET_SVC_Download_Emit (&block, &host_client->netchan.message);
ClientReliable_FinishWrite (host_client); ClientReliable_FinishWrite (host_client);
} }
@ -1136,8 +1115,6 @@ SV_Msg_f (void)
void void
SV_SetInfo_f (void) SV_SetInfo_f (void)
{ {
net_svc_setinfo_t block;
if (Cmd_Argc () == 1) { if (Cmd_Argc () == 1) {
SV_Printf ("User info settings:\n"); SV_Printf ("User info settings:\n");
Info_Print (host_client->userinfo); Info_Print (host_client->userinfo);
@ -1176,11 +1153,12 @@ SV_SetInfo_f (void)
SV_ExtractFromUserinfo (host_client); SV_ExtractFromUserinfo (host_client);
if (Info_FilterForKey (Cmd_Argv (1), client_info_filters)) { if (Info_FilterForKey (Cmd_Argv (1), client_info_filters)) {
block.slot = host_client - svs.clients;
block.key = Cmd_Argv (1);
block.value = Info_ValueForKey (host_client->userinfo, Cmd_Argv (1));
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
NET_SVC_SetInfo_Emit (&block, &sv.reliable_datagram); MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
MSG_WriteString (&sv.reliable_datagram, Cmd_Argv (1));
MSG_WriteString (&sv.reliable_datagram,
Info_ValueForKey (host_client->userinfo,
Cmd_Argv (1)));
} }
} }
@ -1839,7 +1817,7 @@ SV_UserInit (void)
"Toggles the ability of spectators to talk to players"); "Toggles the ability of spectators to talk to players");
sv_mapcheck = Cvar_Get ("sv_mapcheck", "1", CVAR_NONE, NULL, sv_mapcheck = Cvar_Get ("sv_mapcheck", "1", CVAR_NONE, NULL,
"Toggle the use of map checksumming to check for players who edit maps to cheat"); "Toggle the use of map checksumming to check for players who edit maps to cheat");
sv_kickfake = Cvar_Get ("sv_kickfake", "0", CVAR_NONE, NULL, sv_kickfake = Cvar_Get ("sv_kickfake", "1", CVAR_NONE, NULL,
"Kick users sending to send fake talk messages"); "Kick users sending to send fake talk messages");
} }