This completes the move of the networking code to its own branch allowing

two conflicting developement tracks to better co-exist. To work on this brance,
use "cvs up -r net_svc" and then update and commit as normal: committing to
the branche will be automatic once the branch is checked out.

Again: cvs up -r net_svc
This commit is contained in:
Bill Currie 2001-11-07 08:31:04 +00:00
parent c5aec15569
commit edb540cd6e
25 changed files with 1495 additions and 1359 deletions

View file

@ -62,11 +62,10 @@
#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,7 +36,8 @@ 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 (qboolean delta); void CL_ParsePacketEntities (void);
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 V_ParseDamage (void); void CL_ParseDamage (void);
void V_PrepBlend (void); void V_PrepBlend (void);

View file

@ -60,6 +60,7 @@ 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,6 +138,8 @@ 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,6 +214,22 @@
#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,
int volume, float attenuation); float 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_packetlog.c net_svc.c
common_ldflags= -export-dynamic common_ldflags= -export-dynamic

View file

@ -265,8 +265,8 @@ 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_EndGame ("Demo message > MAX_MSGLEN + 8: %d/%d", Host_Error ("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);
if (r != net_message->message->cursize) { if (r != net_message->message->cursize) {

View file

@ -43,6 +43,7 @@ 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"
@ -53,6 +54,7 @@ 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"
@ -69,6 +71,7 @@ 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 ()
{ {
@ -124,221 +127,168 @@ 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_ParseDelta (entity_state_t *from, entity_state_t *to, int bits) CL_EntityState_Copy (entity_state_t *src, entity_state_t *dest, 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)
to->modelindex = MSG_ReadByte (net_message); dest->modelindex = src->modelindex;
if (bits & U_FRAME) if (bits & U_FRAME)
to->frame = MSG_ReadByte (net_message); dest->frame = (dest->frame & 0xFF00) | (src->frame & 0xFF);
if (bits & U_COLORMAP) if (bits & U_COLORMAP)
to->colormap = MSG_ReadByte (net_message); dest->colormap = src->colormap;
if (bits & U_SKIN) if (bits & U_SKIN)
to->skinnum = MSG_ReadByte (net_message); dest->skinnum = src->skinnum;
if (bits & U_EFFECTS) if (bits & U_EFFECTS)
to->effects = MSG_ReadByte (net_message); dest->effects = (dest->effects & 0xFF00) | (src->effects & 0xFF);
if (bits & U_ORIGIN1) if (bits & U_ORIGIN1)
to->origin[0] = MSG_ReadCoord (net_message); dest->origin[0] = src->origin[0];
if (bits & U_ANGLE1) if (bits & U_ANGLE1)
to->angles[0] = MSG_ReadAngle (net_message); dest->angles[0] = src->angles[0];
if (bits & U_ORIGIN2) if (bits & U_ORIGIN2)
to->origin[1] = MSG_ReadCoord (net_message); dest->origin[1] = src->origin[1];
if (bits & U_ANGLE2) if (bits & U_ANGLE2)
to->angles[1] = MSG_ReadAngle (net_message); dest->angles[1] = src->angles[1];
if (bits & U_ORIGIN3) if (bits & U_ORIGIN3)
to->origin[2] = MSG_ReadCoord (net_message); dest->origin[2] = src->origin[2];
if (bits & U_ANGLE3) if (bits & U_ANGLE3)
to->angles[2] = MSG_ReadAngle (net_message); dest->angles[2] = src->angles[2];
// 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)
to->alpha = MSG_ReadByte (net_message); dest->alpha = src->alpha;
if (bits & U_SCALE) if (bits & U_SCALE)
to->scale = MSG_ReadByte (net_message); dest->scale = src->scale;
if (bits & U_EFFECTS2) if (bits & U_EFFECTS2)
to->effects = (to->effects & 0xFF) | (MSG_ReadByte (net_message) << 8); dest->effects = (dest->effects & 0xFF) | (src->effects & 0xFF00);
if (bits & U_GLOWSIZE) if (bits & U_GLOWSIZE)
to->glow_size = MSG_ReadByte (net_message); dest->glow_size = src->glow_size;
if (bits & U_GLOWCOLOR) if (bits & U_GLOWCOLOR)
to->glow_color = MSG_ReadByte (net_message); dest->glow_color = src->glow_color;
if (bits & U_COLORMOD) if (bits & U_COLORMOD)
to->colormod = MSG_ReadByte (net_message); dest->colormod = src->colormod;
if (bits & U_FRAME2) if (bits & U_FRAME2)
to->frame = (to->frame & 0xFF) | (MSG_ReadByte (net_message) << 8); dest->frame = (dest->frame & 0xFF) | (src->frame & 0xFF00);
// 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
FlushEntityPacket (void) CL_ParsePacketEntities (void)
{ {
entity_state_t olde, newe; int index, packetnum;
int word; packet_entities_t *newp;
net_svc_packetentities_t block;
Con_DPrintf ("FlushEntityPacket\n"); packetnum = cls.netchan.incoming_sequence & UPDATE_MASK;
newp = &cl.frames[packetnum].packet_entities;
cl.frames[packetnum].invalid = false;
memset (&olde, 0, sizeof (olde)); cl.validsequence = cls.netchan.incoming_sequence;
cl.validsequence = 0; // can't render a frame newp->num_entities = 0;
cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].invalid = true;
// read it all, but ignore it if (NET_SVC_PacketEntities_Parse (&block, net_message)) {
while (1) { Host_NetError ("CL_ParsePacketEntities: Bad Read");
word = (unsigned short) MSG_ReadShort (net_message); return;
if (net_message->badread) { // something didn't parse right... }
Host_EndGame ("msg_badread in packetentities");
for (index = 0; block.words[index]; index++) {
if (block.words[index] & U_REMOVE) {
Host_NetError ("CL_ParsePacketEntities: U_REMOVE on full "
"update\n");
cl.validsequence = 0; // XXX
cl.frames[packetnum].invalid = true;
return; return;
} }
if (!word) if (index >= MAX_PACKET_ENTITIES) {
break; // done Host_NetError ("CL_ParsePacketEntities: index %i >= "
"MAX_PACKET_ENTITIES", index);
return;
}
CL_ParseDelta (&olde, &newe, word); 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_ParsePacketEntities CL_ParseDeltaPacketEntities
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_ParsePacketEntities (qboolean delta) CL_ParseDeltaPacketEntities ()
{ {
byte from; int oldindex = 0, newindex = 0;
int oldindex, newindex, newnum, oldnum, oldpacket, newpacket, word; int wordindex = 0, deltaindex = 0;
packet_entities_t *oldp, *newp, dummy; int oldnum, newnum;
qboolean full; int oldpacket, newpacket;
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) { oldpacket = cl.frames[newpacket].delta_sequence;
from = MSG_ReadByte (net_message);
oldpacket = cl.frames[newpacket].delta_sequence; if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) {
// we can't use this, it is too old
if ((from & UPDATE_MASK) != (oldpacket & UPDATE_MASK)) Con_DPrintf ("CL_ParseDeltaPacketEntities: old packet\n");
Con_DPrintf ("WARNING: from mismatch\n"); cl.validsequence = 0; // can't render a frame
} else cl.frames[newpacket].invalid = true;
oldpacket = -1; return;
}
full = false; if ((block.from & UPDATE_MASK) != (oldpacket & UPDATE_MASK)) {
if (oldpacket != -1) { Con_DPrintf ("CL_ParseDeltaPacketEntities: from mismatch\n");
if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) { cl.validsequence = 0;
// we can't use this, it is too old cl.frames[newpacket].invalid = true;
FlushEntityPacket (); return;
return; }
} if (oldpacket == -1) {
cl.validsequence = cls.netchan.incoming_sequence; Host_NetError ("Cl_ParseDeltaPacketEntities: invalid "
oldp = &cl.frames[oldpacket & UPDATE_MASK].packet_entities; "delta_sequence\n");
} else { // a full update that we can start delta compressing from now return;
oldp = &dummy;
dummy.num_entities = 0;
cl.validsequence = cls.netchan.incoming_sequence;
full = true;
} }
oldindex = 0; cl.validsequence = cls.netchan.incoming_sequence;
newindex = 0; oldp = &cl.frames[oldpacket & UPDATE_MASK].packet_entities;
newp->num_entities = 0; newp->num_entities = 0;
while (1) { for (; block.words[wordindex];) {
word = (unsigned short) MSG_ReadShort (net_message); newnum = block.words[wordindex] & 511;
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) { while (newnum > oldnum) { // copy one of the old entities
if (full) { // over to the new packet unchanged
Con_Printf ("WARNING: oldcopy on full update"); // Con_Printf ("copy %i\n", oldnum);
FlushEntityPacket (); if (newindex >= MAX_PACKET_ENTITIES) {
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++;
@ -348,44 +298,74 @@ CL_ParsePacketEntities (qboolean delta)
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 (word & U_REMOVE) { if (block.words[wordindex] & U_REMOVE) {
if (full) { wordindex++;
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_EndGame ("CL_ParsePacketEntities: newindex == " Host_NetError ("CL_ParseDeltaPacketEntities: newindex >= "
"MAX_PACKET_ENTITIES"); "MAX_PACKET_ENTITIES (2nd)");
CL_ParseDelta (&cl_baselines[newnum], &newp->entities[newindex], return;
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
if (full) { // Con_Printf ("delta %i\n", newnum);
cl.validsequence = 0; if (block.words[wordindex] & U_REMOVE) { // Clear the entity
Con_Printf ("WARNING: delta on full update"); memset (&cl_packet_ents[newnum], 0, sizeof (entity_t));
} 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;
} }
// Con_Printf ("delta %i\n", newnum); newp->entities[newindex] = oldp->entities[oldindex];
CL_ParseDelta (&oldp->entities[oldindex], CL_EntityState_Copy (&block.deltas[deltaindex],
&newp->entities[newindex], word); &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++;
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;
} }
@ -543,7 +523,6 @@ 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;
@ -561,27 +540,25 @@ CL_ClearProjectiles (void)
void void
CL_ParseProjectiles (void) CL_ParseProjectiles (void)
{ {
byte bits[6]; int i;
int i, c, j;
projectile_t *pr; projectile_t *pr;
net_svc_nails_t block;
c = MSG_ReadByte (net_message); if (NET_SVC_Nails_Parse (&block, net_message)) {
for (i = 0; i < c; i++) { Host_NetError ("CL_ParseProjectiles: Bad Read\n");
for (j = 0; j < 6; j++) return;
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)
continue; break;
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;
pr->ent.origin[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; VectorCopy (block.nails[i].origin, pr->ent.origin);
pr->ent.origin[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; VectorCopy (block.nails[i].angles, pr->ent.angles);
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;
} }
} }
@ -617,66 +594,57 @@ 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;
num = MSG_ReadByte (net_message); if (NET_SVC_Playerinfo_Parse (&block, net_message)) {
if (num > MAX_CLIENTS) Host_NetError ("CL_ParsePlayerinfo: Bad Read\n");
// Sys_Error ("CL_ParsePlayerinfo: bad num"); return;
Host_EndGame ("CL_ParsePlayerinfo: bad num"); }
state = &cl.frames[parsecountmod].playerstate[num]; if (block.playernum >= MAX_CLIENTS) {
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->number = num; state = &cl.frames[parsecountmod].playerstate[block.playernum];
flags = state->flags = MSG_ReadShort (net_message);
state->number = block.playernum;
state->flags = block.flags;
state->messagenum = cl.parsecount; state->messagenum = cl.parsecount;
state->origin[0] = MSG_ReadCoord (net_message); VectorCopy (block.origin, state->origin);
state->origin[1] = MSG_ReadCoord (net_message);
state->origin[2] = MSG_ReadCoord (net_message);
state->frame = MSG_ReadByte (net_message); state->frame = block.frame;
// 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
if (flags & PF_MSEC) { state->state_time = parsecounttime - block.msec * 0.001;
msec = MSG_ReadByte (net_message);
state->state_time = parsecounttime - msec * 0.001;
} else
state->state_time = parsecounttime;
if (flags & PF_COMMAND) if (block.flags & PF_COMMAND)
MSG_ReadDeltaUsercmd (&nullcmd, &state->command); memcpy (&state->command, &block.usercmd, sizeof (state->command));
for (i = 0; i < 3; i++) { VectorCopy (block.velocity, state->velocity);
if (flags & (PF_VELOCITY1 << i))
state->velocity[i] = MSG_ReadShort (net_message); if (block.flags & PF_MODEL)
else state->modelindex = block.modelindex;
state->velocity[i] = 0;
}
if (flags & PF_MODEL)
state->modelindex = MSG_ReadByte (net_message);
else else
state->modelindex = cl_playerindex; state->modelindex = cl_playerindex;
if (flags & PF_SKINNUM) state->skinnum = block.skinnum;
state->skinnum = MSG_ReadByte (net_message); state->effects = block.effects;
else state->weaponframe = block.weaponframe;
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,6 +1318,34 @@ 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_EndGame ("CL_NewTranslation: slot > MAX_CLIENTS"); Host_NetError ("CL_NewTranslation: slot > MAX_CLIENTS");
player = &cl.players[slot]; player = &cl.players[slot];
if (!player->name[0]) if (!player->name[0])

View file

@ -50,6 +50,8 @@ 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
@ -182,42 +184,37 @@ CL_AllocExplosion (void)
} }
void void
CL_ParseBeam (model_t *m) CL_ParseBeam (net_svc_tempentity_t *tempentity, model_t *m)
{ {
beam_t *b; beam_t *b;
int ent, i; int i;
vec3_t start, end;
ent = MSG_ReadShort (net_message); if (tempentity->beamentity >= MAX_EDICTS) {
Host_NetError ("CL_ParseBeam: beamentity %i >= MAX_EDICTS",
start[0] = MSG_ReadCoord (net_message); tempentity->beamentity);
start[1] = MSG_ReadCoord (net_message); return;
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 == ent) { if (b->entity == tempentity->beamentity) {
b->entity = ent; b->entity = tempentity->beamentity;
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 (start, b->start); VectorCopy (tempentity->position, b->start);
VectorCopy (end, b->end); VectorCopy (tempentity->beamend, 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 = ent; b->entity = tempentity->beamentity;
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 (start, b->start); VectorCopy (tempentity->position, b->start);
VectorCopy (end, b->end); VectorCopy (tempentity->beamend, b->end);
return; return;
} }
} }
@ -227,79 +224,66 @@ CL_ParseBeam (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 colorStart, colorLength, rnd; int rnd;
int cnt = -1; net_svc_tempentity_t tempentity;
vec3_t pos;
type = MSG_ReadByte (net_message); if (NET_SVC_TempEntity_Parse (&tempentity, net_message)) {
switch (type) { Host_NetError ("CL_ParseTEnt: Bad Read\n");
return;
}
switch (tempentity.type) {
case TE_WIZSPIKE: // spike hitting wall case TE_WIZSPIKE: // spike hitting wall
pos[0] = MSG_ReadCoord (net_message); R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]);
pos[1] = MSG_ReadCoord (net_message); S_StartSound (-1, 0, cl_sfx_wizhit, tempentity.position, 1, 1);
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
pos[0] = MSG_ReadCoord (net_message); R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]);
pos[1] = MSG_ReadCoord (net_message); S_StartSound (-1, 0, cl_sfx_knighthit, tempentity.position, 1, 1);
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
pos[0] = MSG_ReadCoord (net_message); R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]);
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, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_tink1, tempentity.position, 1, 1);
else { else {
rnd = rand () & 3; rnd = rand () & 3;
if (rnd == 1) if (rnd == 1)
S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_ric1, tempentity.position, 1, 1);
else if (rnd == 2) else if (rnd == 2)
S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_ric2, tempentity.position, 1, 1);
else else
S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_ric3, tempentity.position, 1, 1);
} }
break; break;
case TE_SUPERSPIKE: // super spike hitting wall case TE_SUPERSPIKE: // super spike hitting wall
pos[0] = MSG_ReadCoord (net_message); R_RunSpikeEffect (tempentity.position, prot_to_rend[tempentity.type]);
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, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_tink1, tempentity.position, 1, 1);
else { else {
rnd = rand () & 3; rnd = rand () & 3;
if (rnd == 1) if (rnd == 1)
S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_ric1, tempentity.position, 1, 1);
else if (rnd == 2) else if (rnd == 2)
S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_ric2, tempentity.position, 1, 1);
else else
S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_ric3, tempentity.position, 1, 1);
} }
break; break;
case TE_EXPLOSION: // rocket explosion case TE_EXPLOSION: // rocket explosion
// particles // particles
pos[0] = MSG_ReadCoord (net_message); R_ParticleExplosion (tempentity.position);
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 (pos, dl->origin); VectorCopy (tempentity.position, 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;
@ -308,94 +292,78 @@ CL_ParseTEnt (void)
dl->color[2] = 0.24; dl->color[2] = 0.24;
// sound // sound
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_r_exp3, tempentity.position, 1, 1);
// sprite // sprite
ex = CL_AllocExplosion (); ex = CL_AllocExplosion ();
VectorCopy (pos, ex->ent.origin); VectorCopy (tempentity.position, 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
pos[0] = MSG_ReadCoord (net_message); R_BlobExplosion (tempentity.position);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_BlobExplosion (pos);
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); S_StartSound (-1, 0, cl_sfx_r_exp3, tempentity.position, 1, 1);
break; break;
case TE_LIGHTNING1: // lightning bolts case TE_LIGHTNING1: // lightning bolts
CL_ParseBeam (cl_mod_bolt); CL_ParseBeam (&tempentity, cl_mod_bolt);
break; break;
case TE_LIGHTNING2: // lightning bolts case TE_LIGHTNING2: // lightning bolts
CL_ParseBeam (cl_mod_bolt2); CL_ParseBeam (&tempentity, cl_mod_bolt2);
break; break;
case TE_LIGHTNING3: // lightning bolts case TE_LIGHTNING3: // lightning bolts
CL_ParseBeam (cl_mod_bolt3); CL_ParseBeam (&tempentity, 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 (Mod_ForName ("progs/beam.mdl", true)); CL_ParseBeam (&tempentity, Mod_ForName ("progs/beam.mdl", true));
break; break;
// PGM 01/21/97 // PGM 01/21/97
case TE_LAVASPLASH: case TE_LAVASPLASH:
pos[0] = MSG_ReadCoord (net_message); R_LavaSplash (tempentity.position);
pos[1] = MSG_ReadCoord (net_message);
pos[2] = MSG_ReadCoord (net_message);
R_LavaSplash (pos);
break; break;
case TE_TELEPORT: case TE_TELEPORT:
pos[0] = MSG_ReadCoord (net_message); R_TeleportSplash (tempentity.position);
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
pos[0] = MSG_ReadCoord (net_message); R_ParticleExplosion2 (tempentity.position,
pos[1] = MSG_ReadCoord (net_message); tempentity.colorstart,
pos[2] = MSG_ReadCoord (net_message); tempentity.colorlength);
colorStart = MSG_ReadByte (net_message);
colorLength = MSG_ReadByte (net_message);
R_ParticleExplosion2 (pos, colorStart, colorLength);
dl = R_AllocDlight (0); dl = R_AllocDlight (0);
VectorCopy (pos, dl->origin); VectorCopy (tempentity.position, 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[(colorStart + (rand() % colorLength)) * dl->color[0] = vid_basepal[(tempentity.colorstart
3] * (1.0 / 255.0); + (rand() % tempentity.colorlength))
dl->color[1] = vid_basepal[(colorStart + (rand() % colorLength)) * * 3] * (1.0 / 255.0);
3 + 1] * (1.0 / 255.0); dl->color[1] = vid_basepal[(tempentity.colorstart
dl->color[2] = vid_basepal[(colorStart + (rand() % colorLength)) * + (rand() % tempentity.colorlength))
3 + 2] * (1.0 / 255.0); * 3 + 1] * (1.0 / 255.0);
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); dl->color[2] = vid_basepal[(tempentity.colorstart
+ (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
cnt = MSG_ReadByte (net_message) * 20; R_RunPuffEffect (tempentity.position, prot_to_rend[tempentity.type],
pos[0] = MSG_ReadCoord (net_message); tempentity.gunshotcount * 20);
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 (pos, dl->origin); VectorCopy (tempentity.position, 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;
@ -403,11 +371,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 (pos, prot_to_rend[type], cnt); R_RunPuffEffect (tempentity.position, prot_to_rend[tempentity.type], 0);
break; break;
default: default:
Sys_Error ("CL_ParseTEnt: bad type"); Sys_Error ("CL_ParseTEnt: bad tempentity.type %i", tempentity.type);
} }
} }

View file

@ -45,6 +45,7 @@ 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"
@ -240,18 +241,18 @@ V_DriftPitch (void)
/* PALETTE FLASHES */ /* PALETTE FLASHES */
void void
V_ParseDamage (void) CL_ParseDamage (void)
{ {
float count, side; float count, side;
int armor, blood, i; vec3_t forward, right, up;
vec3_t forward, from, right, up; net_svc_damage_t damage;
armor = MSG_ReadByte (net_message); if (NET_SVC_Damage_Parse (&damage, net_message)) {
blood = MSG_ReadByte (net_message); Host_NetError ("CL_ParseDamage: Bad Read\n");
for (i = 0; i < 3; i++) return;
from[i] = MSG_ReadCoord (net_message); }
count = blood * 0.5 + armor * 0.5; count = damage.blood * 0.5 + damage.armor * 0.5;
if (count < 10) if (count < 10)
count = 10; count = 10;
@ -265,11 +266,11 @@ V_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 (armor > blood) { if (damage.armor > damage.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 (armor) { } else if (damage.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;
@ -281,15 +282,15 @@ V_ParseDamage (void)
} }
// calculate view angle kicks // calculate view angle kicks
VectorSubtract (from, cl.simorg, from); VectorSubtract (damage.from, cl.simorg, damage.from);
VectorNormalize (from); VectorNormalize (damage.from);
AngleVectors (cl.simangles, forward, right, up); AngleVectors (cl.simangles, forward, right, up);
side = DotProduct (from, right); side = DotProduct (damage.from, right);
v_dmg_roll = count * side * v_kickroll->value; v_dmg_roll = count * side * v_kickroll->value;
side = DotProduct (from, forward); side = DotProduct (damage.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

@ -1,11 +1,11 @@
/* /*
net_packetlog.c net_packetlog.c
packet logging/parsing - for debugging and educational purposes packet logging/parsing - for debugging and educational purposes
**EXPERIMENTAL** **EXPERIMENTAL**
Copyright (C) 2000 Jukka Sorjonen <jukka.sorjonen@asikkala.fi> Copyright (C) 2000 Jukka Sorjonen <jukka.sorjonen@asikkala.fi>
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
@ -56,6 +56,7 @@ 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"
@ -64,87 +65,12 @@ cvar_t *net_loglevel;
int Net_LogStart (const char *fname); int Net_LogStart (const char *fname);
void Analyze_Server_Packet (const byte * data, int len); void Analyze_Server_Packet (const byte *data, int len);
void Analyze_Client_Packet (const byte * data, int len); void Analyze_Client_Packet (const byte *data, int len);
void Parse_Server_Packet (void); 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",
@ -169,7 +95,6 @@ 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;
@ -190,11 +115,12 @@ 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;
Qprintf (Net_PacketLog, "%s", text); if (Net_PacketLog) {
Qflush (Net_PacketLog); Qprintf (Net_PacketLog, "%s", text);
Qflush (Net_PacketLog);
} else
Con_Printf ("%s", text);
} }
int int
@ -304,104 +230,113 @@ Log_Outgoing_Packet (const char *p, int len)
return; return;
} }
void qboolean
Log_Delta(int bits) Log_Delta(int bits)
{ {
entity_state_t to; entity_state_t to;
int i; int i;
Net_LogPrintf ("\n\t"); Net_LogPrintf ("\n\t<%06x> ", MSG_GetReadCount (&packet) - 2);
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;
if (bits & U_EXTEND2) Net_LogPrintf (" U_EXTEND1");
if (bits & U_EXTEND2) {
bits |= MSG_ReadByte (&packet) << 24; bits |= MSG_ReadByte (&packet) << 24;
Net_LogPrintf (" U_EXTEND2");
}
} }
to.flags = bits; to.flags = bits;
if (bits & U_MODEL) if (bits & U_MODEL)
Net_LogPrintf (" MdlIdx: %d", MSG_ReadByte (&packet)); Net_LogPrintf (" MdlIdx: %d", MSG_ReadByte (&packet));
if (bits & U_FRAME) { if (bits & U_FRAME) {
to.frame = MSG_ReadByte (&packet); to.frame = MSG_ReadByte (&packet);
Net_LogPrintf (" Frame: %d", to.frame); Net_LogPrintf (" Frame: %d", to.frame);
} }
if (bits & U_COLORMAP) if (bits & U_COLORMAP)
Net_LogPrintf (" Colormap: %d", MSG_ReadByte (&packet)); Net_LogPrintf (" Colormap: %d", MSG_ReadByte (&packet));
if (bits & U_SKIN) if (bits & U_SKIN)
Net_LogPrintf (" Skinnum: %d", MSG_ReadByte (&packet)); Net_LogPrintf (" Skinnum: %d", MSG_ReadByte (&packet));
if (bits & U_EFFECTS) { if (bits & U_EFFECTS) {
to.effects = MSG_ReadByte (&packet); to.effects = MSG_ReadByte (&packet);
Net_LogPrintf (" Effects: %d", to.effects); Net_LogPrintf (" Effects: %d", to.effects);
} }
if (bits & U_ORIGIN1) if (bits & U_ORIGIN1)
Net_LogPrintf (" X: %f", MSG_ReadCoord (&packet)); Net_LogPrintf (" X: %f", MSG_ReadCoord (&packet));
if (bits & U_ANGLE1) if (bits & U_ANGLE1)
Net_LogPrintf (" Pitch: %d", MSG_ReadAngle (&packet)); Net_LogPrintf (" Pitch: %d", MSG_ReadAngle (&packet));
if (bits & U_ORIGIN2) if (bits & U_ORIGIN2)
Net_LogPrintf (" Y: %f", MSG_ReadCoord (&packet)); Net_LogPrintf (" Y: %f", MSG_ReadCoord (&packet));
if (bits & U_ANGLE2) if (bits & U_ANGLE2)
Net_LogPrintf (" Yaw: %d", MSG_ReadAngle (&packet)); Net_LogPrintf (" Yaw: %d", MSG_ReadAngle (&packet));
if (bits & U_ORIGIN3) if (bits & U_ORIGIN3)
Net_LogPrintf (" Z: %f", MSG_ReadCoord (&packet)); Net_LogPrintf (" Z: %f", MSG_ReadCoord (&packet));
if (bits & U_ANGLE3) if (bits & U_ANGLE3)
Net_LogPrintf (" Roll: %d", MSG_ReadAngle (&packet)); Net_LogPrintf (" Roll: %d", MSG_ReadAngle (&packet));
// Ender (QSG - Begin) // Ender (QSG - Begin)
if (bits & U_ALPHA) if (bits & U_ALPHA)
Net_LogPrintf(" Alpha: %d", MSG_ReadByte (&packet)); Net_LogPrintf(" Alpha: %d", MSG_ReadByte (&packet));
if (bits & U_SCALE) if (bits & U_SCALE)
Net_LogPrintf(" Scale: %d", MSG_ReadByte (&packet)); Net_LogPrintf(" Scale: %d", MSG_ReadByte (&packet));
if (bits & U_EFFECTS2) if (bits & U_EFFECTS2)
Net_LogPrintf(" U_EFFECTS2: %d", (to.effects & 0xFF) | (MSG_ReadByte (&packet) << 8)); Net_LogPrintf(" U_EFFECTS2: %d", (to.effects & 0xFF) | (MSG_ReadByte (&packet) << 8));
if (bits & U_GLOWSIZE) if (bits & U_GLOWSIZE)
Net_LogPrintf(" GlowSize: %d", MSG_ReadByte (&packet)); Net_LogPrintf(" GlowSize: %d", MSG_ReadByte (&packet));
if (bits & U_GLOWCOLOR) if (bits & U_GLOWCOLOR)
Net_LogPrintf(" ColorGlow: %d", MSG_ReadByte (&packet)); Net_LogPrintf(" ColorGlow: %d", MSG_ReadByte (&packet));
if (bits & U_COLORMOD) if (bits & U_COLORMOD)
Net_LogPrintf(" Colormod: %d", MSG_ReadByte (&packet)); Net_LogPrintf(" Colormod: %d", MSG_ReadByte (&packet));
if (bits & U_FRAME2) if (bits & U_FRAME2)
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; return 0;
} }
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;
} }
@ -438,10 +373,11 @@ 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] ", MSG_GetReadCount (&packet), c); Net_LogPrintf ("<%06x> [0x%02x] ",
MSG_GetReadCount (&packet) - 1, c);
if (c < 53) if (c < 53)
Net_LogPrintf ("%s: ", svc_string[c]); Net_LogPrintf ("%s: ", NET_SVC_GetString (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)
@ -623,7 +559,7 @@ Parse_Server_Packet ()
Net_LogPrintf ("**QW OBSOLETE**"); Net_LogPrintf ("**QW OBSOLETE**");
break; break;
case svc_centerprint: case svc_centerprint:
Net_LogPrintf ("%s\n", MSG_ReadString (&packet)); Net_LogPrintf ("%s", MSG_ReadString (&packet));
break; break;
case svc_killedmonster: case svc_killedmonster:
break; break;
@ -794,22 +730,20 @@ 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);
if (packet.badread) { if (packet.badread) {
Net_LogPrintf ("Badread\n"); Net_LogPrintf (" Badread\n");
return; return;
} }
if (!mask1) break; if (Log_Delta(mask1))
if (mask1 & U_REMOVE) Net_LogPrintf("UREMOVE "); break;
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;
@ -839,16 +773,12 @@ 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
@ -962,7 +892,7 @@ Net_PacketLog_f (cvar_t *var)
void void
Net_PacketLog_Zap_f (void) Net_PacketLog_Zap_f (void)
{ {
if (Net_PacketLog && Net_PacketLog != _stdout) { if (Net_PacketLog) {
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);
@ -980,8 +910,6 @@ 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,6 +52,7 @@ 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"
@ -829,12 +830,15 @@ 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);
MSG_WriteString (&sv.reliable_datagram, key); NET_SVC_ServerInfo_Emit (&block, &sv.reliable_datagram);
MSG_WriteString (&sv.reliable_datagram, value);
} }
/* /*

View file

@ -42,6 +42,7 @@ 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"
@ -125,51 +126,29 @@ SV_AddNailUpdate (edict_t *ent)
void void
SV_EmitNailUpdate (sizebuf_t *msg) SV_EmitNailUpdate (sizebuf_t *msg)
{ {
byte bits[6]; // [48 bits] xyzpy 12 12 12 4 8 int i;
int i, n, p, x, y, z, yaw; net_svc_nails_t block;
edict_t *ent;
if (!numnails) if (!numnails)
return; return;
MSG_WriteByte (msg, svc_nails); block.numnails = numnails;
MSG_WriteByte (msg, numnails);
for (n = 0; n < numnails; n++) { for (i = 0; i < numnails; i++) {
ent = nails[n]; VectorCopy (SVvector (nails[i], origin), block.nails[i].origin);
x = (int) (SVvector (ent, origin)[0] + 4096) >> 1; VectorCopy (SVvector (nails[i], angles), block.nails[i].angles);
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]);
} }
MSG_WriteByte (msg, svc_nails);
NET_SVC_Nails_Emit (&block, msg);
} }
/* unsigned int
SV_WriteDelta SV_EntityState_Diff (entity_state_t *from, entity_state_t *to)
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 bits, i; int 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];
@ -203,7 +182,7 @@ SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
// 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;
@ -218,20 +197,44 @@ SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
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");
@ -240,10 +243,7 @@ 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!
i = to->number | (bits & ~511); MSG_WriteShort (msg, 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,80 +302,118 @@ SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
/* /*
SV_EmitPacketEntities SV_EmitPacketEntities
Writes a delta update of a packet_entities_t to the message. Writes an 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 newindex, oldindex, newnum, oldnum, oldmax; int index;
edict_t *ent; entity_state_t *baseline;
client_frame_t *fromframe; net_svc_packetentities_t block;
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
if (client->delta_sequence != -1) { from = &client->frames[client->delta_sequence & UPDATE_MASK].entities;
fromframe = &client->frames[client->delta_sequence & UPDATE_MASK];
from = &fromframe->entities;
oldmax = from->num_entities;
MSG_WriteByte (msg, svc_deltapacketentities); block.from = client->delta_sequence;
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);
while (newindex < to->num_entities || oldindex < oldmax) { for (newindex = 0, oldindex = 0, word = 0;
newnum = newindex < to->num_entities || oldindex < from->num_entities;
newindex >= to->num_entities ? 9999 : word++) {
to->entities[newindex].number; newnum = newindex >= to->num_entities ?
oldnum = oldindex >= oldmax ? 9999 : from->entities[oldindex].number; 9999 : to->entities[newindex].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);
SV_WriteDelta (&from->entities[oldindex], &to->entities[newindex], block.deltas[newindex] = to->entities[newindex];
msg, false, client->stdver); block.deltas[newindex].flags =
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++;
continue; } else if (newnum < oldnum) { // this is a new entity, send
} // 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);
SV_WriteDelta (ent->data, &to->entities[newindex], msg, true, block.deltas[newindex] = to->entities[newindex];
client->stdver); block.deltas[newindex].flags =
newindex++; SV_EntityState_Diff (baseline, &to->entities[newindex]);
continue;
}
if (newnum > oldnum) { // the old entity isn't present in // check if it's a client that doesn't support QSG2
// the new message if (client->stdver <= 1)
block.deltas[newindex].flags &= U_VERSION_ID;
block.words[word] = newnum | (block.deltas[newindex].flags & ~511);
newindex++;
} else 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);
MSG_WriteShort (msg, oldnum | U_REMOVE); block.words[word] = oldnum | U_REMOVE;
oldindex++; oldindex++;
continue;
} }
} }
MSG_WriteShort (msg, 0); // end of packetentities block.words[word] = 0;
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, msec, pflags; int i, j;
client_t *cl; client_t *cl;
edict_t *ent; edict_t *ent;
usercmd_t cmd; net_svc_playerinfo_t block;
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)
@ -397,82 +435,63 @@ SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs,
continue; // not visible continue; // not visible
} }
pflags = PF_MSEC | PF_COMMAND; block.flags = PF_MSEC | PF_COMMAND;
if (SVfloat (ent, modelindex) != sv_playermodel) if (SVfloat (ent, modelindex) != sv_playermodel)
pflags |= PF_MODEL; block.flags |= PF_MODEL;
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
if (SVvector (ent, velocity)[i]) if (SVvector (ent, velocity)[i])
pflags |= PF_VELOCITY1 << i; block.flags |= PF_VELOCITY1 << i;
if (SVfloat (ent, effects)) if (SVfloat (ent, effects))
pflags |= PF_EFFECTS; block.flags |= PF_EFFECTS;
if (SVfloat (ent, skin)) if (SVfloat (ent, skin))
pflags |= PF_SKINNUM; block.flags |= PF_SKINNUM;
if (SVfloat (ent, health) <= 0) if (SVfloat (ent, health) <= 0)
pflags |= PF_DEAD; block.flags |= PF_DEAD;
if (SVvector (ent, mins)[2] != -24) if (SVvector (ent, mins)[2] != -24)
pflags |= PF_GIB; block.flags |= PF_GIB;
if (cl->spectator) { // only sent origin and velocity to if (cl->spectator) { // only sent origin and velocity to
// spectators // spectators
pflags &= PF_VELOCITY1 | PF_VELOCITY2 | PF_VELOCITY3; block.flags &= 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
pflags &= ~(PF_MSEC | PF_COMMAND); block.flags &= ~(PF_MSEC | PF_COMMAND);
if (SVfloat (ent, weaponframe)) if (SVfloat (ent, weaponframe))
pflags |= PF_WEAPONFRAME; block.flags |= PF_WEAPONFRAME;
} }
if (client->spec_track && client->spec_track - 1 == j && if (client->spec_track && client->spec_track - 1 == j &&
SVfloat (ent, weaponframe)) pflags |= PF_WEAPONFRAME; SVfloat (ent, 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);
MSG_WriteByte (msg, j); NET_SVC_Playerinfo_Emit (&block, msg);
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));
} }
} }
@ -591,8 +610,10 @@ 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_EmitPacketEntities (client, pack, msg); SV_EmitDeltaPacketEntities (client, pack, msg);
else
SV_EmitPacketEntities (client, pack, msg);
// now add the specialized nail update // now add the specialized nail update
SV_EmitNailUpdate (msg); SV_EmitNailUpdate (msg);

View file

@ -46,6 +46,7 @@ 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"
@ -104,8 +105,9 @@ SV_FlushSignon (void)
void void
SV_CreateBaseline (void) SV_CreateBaseline (void)
{ {
int i, entnum; int 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);
@ -143,19 +145,15 @@ 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);
MSG_WriteShort (&sv.signon, entnum); NET_SVC_SpawnBaseline_Emit (&block, &sv.signon);
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,6 +76,7 @@ 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"
@ -260,11 +261,14 @@ 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);
MSG_WriteByte (net_message->message, PRINT_HIGH); NET_SVC_Print_Emit (&block, net_message->message);
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++)
@ -369,6 +373,7 @@ 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;
@ -393,10 +398,11 @@ 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);
MSG_WriteByte (buf, i); NET_SVC_UpdateUserInfo_Emit (&block, buf);
MSG_WriteLong (buf, client->userid);
MSG_WriteString (buf, info);
} }
/* /*
@ -2171,6 +2177,7 @@ 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';
} }
@ -2200,9 +2207,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++ = *p; *r++ = ' '; // get rid of any special chars
} else } else
*r++ = *p; *r++ = *p & 127; // get rid of bold
} }
*r = '\0'; *r = '\0';
@ -2210,6 +2217,14 @@ 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))
@ -2268,9 +2283,10 @@ SV_ExtractFromUserinfo (client_t *cl)
} }
} }
// finally, report it to all our friends // finally, report it to all our friends, but only if more
// than whitespace changed
// if (cl->state >= cs_spawned && !cl->spectator) // if (cl->state >= cs_spawned && !cl->spectator)
if (*cl->name) if (*cl->name && strcmp (cl->name, newname))
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,7 +36,6 @@ 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", 255, 1); SV_StartSound (ent, 0, "misc/h2ohit1.wav", 1, 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", 255, 1); SV_StartSound (ent, 0, "misc/h2ohit1.wav", 1, 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", 255, 1); SV_StartSound (ent, 0, "demon/dland2.wav", 1, 1);
} }
} }
// regular thinking // regular thinking

View file

@ -45,6 +45,7 @@ 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"
@ -279,17 +280,16 @@ PF_ambientsound (progs_t *pr)
{ {
const char **check; const char **check;
const char *samp; const char *samp;
float *pos; net_svc_spawnstaticsound_t block;
float vol, attenuation;
int i, soundnum;
pos = G_VECTOR (pr, OFS_PARM0); VectorCopy (G_VECTOR (pr, OFS_PARM0), block.position);
samp = G_STRING (pr, OFS_PARM1); samp = G_STRING (pr, OFS_PARM1);
vol = G_FLOAT (pr, OFS_PARM2); block.volume = G_FLOAT (pr, OFS_PARM2) * 255;
attenuation = G_FLOAT (pr, OFS_PARM3); block.attenuation = G_FLOAT (pr, OFS_PARM3) * 64;
// check to see if samp was properly precached // check to see if samp was properly precached
for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++) for (block.sound_num = 0, check = sv.sound_precache; *check;
check++, block.sound_num++)
if (!strcmp (*check, samp)) if (!strcmp (*check, samp))
break; break;
@ -300,14 +300,7 @@ 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);
for (i = 0; i < 3; i++) NET_SVC_SpawnStaticSound_Emit (&block, &sv.signon);
MSG_WriteCoord (&sv.signon, pos[i]);
MSG_WriteByte (&sv.signon, soundnum);
MSG_WriteByte (&sv.signon, vol * 255);
MSG_WriteByte (&sv.signon, attenuation * 64);
} }
/* /*
@ -327,13 +320,13 @@ PF_sound (progs_t *pr)
{ {
const char *sample; const char *sample;
edict_t *entity; edict_t *entity;
float attenuation; float volume, attenuation;
int channel, volume; int channel;
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) * 255; volume = G_FLOAT (pr, OFS_PARM3);
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);
@ -1142,25 +1135,21 @@ 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;
int i; net_svc_spawnstatic_t block;
ent = G_EDICT (pr, OFS_PARM0); ent = G_EDICT (pr, OFS_PARM0);
MSG_WriteByte (&sv.signon, svc_spawnstatic);
model = PR_GetString (pr, SVstring (ent, model));
// SV_Printf ("Model: %d %s\n", SVstring (ent, model), model); // SV_Printf ("Model: %d %s\n", SVstring (ent, model), model);
MSG_WriteByte (&sv.signon, SV_ModelIndex (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, SVfloat (ent, frame)); MSG_WriteByte (&sv.signon, svc_spawnstatic);
MSG_WriteByte (&sv.signon, SVfloat (ent, colormap)); NET_SVC_SpawnStatic_Emit (&block, &sv.signon);
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);
@ -1369,6 +1358,7 @@ 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)
@ -1382,12 +1372,11 @@ 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);
MSG_WriteByte (&sv.reliable_datagram, e1 - 1); NET_SVC_SetInfo_Emit (&block, &sv.reliable_datagram);
MSG_WriteString (&sv.reliable_datagram, key);
MSG_WriteString (&sv.reliable_datagram,
Info_ValueForKey (svs.clients[e1 - 1].userinfo,
key));
} }
} }
} }

View file

@ -49,6 +49,7 @@ 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"
@ -69,6 +70,7 @@ 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;
@ -80,10 +82,15 @@ 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);
ClientReliableWrite_Byte (host_client, PRINT_HIGH); if (host_client->num_backbuf) {
ClientReliableWrite_String (host_client, outputbuf); NET_SVC_Print_Emit (&block, &host_client->backbuf);
ClientReliable_FinishWrite (host_client);
} else
NET_SVC_Print_Emit (&block, &host_client->netchan.message);
} }
// clear it // clear it
outputbuf[0] = 0; outputbuf[0] = 0;
@ -220,6 +227,7 @@ 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) {
@ -239,9 +247,14 @@ 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);
ClientReliableWrite_Byte (cl, level); if (cl->num_backbuf) {
ClientReliableWrite_String (cl, buffer); NET_SVC_Print_Emit (&block, &cl->backbuf);
ClientReliable_FinishWrite (cl);
} else
NET_SVC_Print_Emit (&block, &cl->netchan.message);
} }
/* /*
@ -416,16 +429,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, int volume, SV_StartSound (edict_t *entity, int channel, const char *sample,
float attenuation) float volume, float attenuation)
{ {
int ent, field_mask, sound_num, i; int i, sound_num;
qboolean use_phs; qboolean use_phs;
qboolean reliable = false; qboolean reliable = false;
vec3_t origin; net_svc_sound_t block;
if (volume < 0 || volume > 255) if (volume < 0 || volume > 1)
SV_Error ("SV_StartSound: volume = %i", volume); SV_Error ("SV_StartSound: volume = %f", 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);
@ -444,7 +457,9 @@ SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
return; return;
} }
ent = NUM_FOR_EDICT (&sv_pr_state, entity); block.sound_num = sound_num;
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
{ {
@ -459,37 +474,34 @@ SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
// if (channel == CHAN_BODY || channel == CHAN_VOICE) // if (channel == CHAN_BODY || channel == CHAN_VOICE)
// reliable = true; // reliable = true;
channel = (ent << 3) | channel; block.channel = channel;
field_mask = 0; block.volume = volume;
if (volume != DEFAULT_SOUND_PACKET_VOLUME) // 4 * 64 == 256, which overflows a byte. 4 is the stated max for
channel |= SND_VOLUME; // it, and I don't want to break any progs, so I just nudge it
if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) // down instead
channel |= SND_ATTENUATION; if (attenuation == 4)
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++)
origin[i] = SVvector (entity, origin)[i] + 0.5 * block.position[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), origin); VectorCopy (SVvector (entity, origin), block.position);
} }
MSG_WriteByte (&sv.multicast, svc_sound); MSG_WriteByte (&sv.multicast, svc_sound);
MSG_WriteShort (&sv.multicast, channel); NET_SVC_Sound_Emit (&block, &sv.multicast);
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 (origin, reliable ? MULTICAST_PHS_R : MULTICAST_PHS); SV_Multicast (block.position,
reliable ? MULTICAST_PHS_R : MULTICAST_PHS);
else else
SV_Multicast (origin, reliable ? MULTICAST_ALL_R : MULTICAST_ALL); SV_Multicast (block.position,
reliable ? MULTICAST_ALL_R : MULTICAST_ALL);
} }
/* FRAME UPDATES */ /* FRAME UPDATES */
@ -522,6 +534,7 @@ 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;
@ -534,13 +547,14 @@ 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));
MSG_WriteByte (msg, svc_damage); block.armor = SVfloat (ent, dmg_save);
MSG_WriteByte (msg, SVfloat (ent, dmg_save)); block.blood = SVfloat (ent, dmg_take);
MSG_WriteByte (msg, SVfloat (ent, dmg_take));
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
MSG_WriteCoord (msg, SVvector (other, origin)[i] + 0.5 * block.from[i] = SVvector (other, origin)[i] + 0.5 *
(SVvector (other, mins)[i] + (SVvector (other, mins)[i] +
SVvector (other, maxs)[i])); SVvector (other, maxs)[i]);
MSG_WriteByte (msg, svc_damage);
NET_SVC_Damage_Emit (&block, msg);
SVfloat (ent, dmg_take) = 0; SVfloat (ent, dmg_take) = 0;
SVfloat (ent, dmg_save) = 0; SVfloat (ent, dmg_save) = 0;
@ -780,7 +794,6 @@ 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,6 +54,7 @@ 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"
@ -96,7 +97,7 @@ void
SV_New_f (void) SV_New_f (void)
{ {
const char *gamedir; const char *gamedir;
int playernum; net_svc_serverdata_t block;
if (host_client->state == cs_spawned) if (host_client->state == cs_spawned)
return; return;
@ -115,37 +116,23 @@ 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 (%d0, clearing\n", SV_Printf ("WARNING %s: [SV_New] Back buffered (%d), 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);
MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION); NET_SVC_ServerData_Emit (&block, &host_client->netchan.message);
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);
@ -165,12 +152,14 @@ void
SV_Soundlist_f (void) SV_Soundlist_f (void)
{ {
const char **s; const char **s;
unsigned n; int i, size;
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");
@ -178,34 +167,40 @@ SV_Soundlist_f (void)
return; return;
} }
n = atoi (Cmd_Argv (2)); block.startsound = atoi (Cmd_Argv (2));
if (n >= MAX_SOUNDS) { if (block.startsound >= 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
//spawns. These functions are written to not overflow // NOTE: This doesn't go through ClientReliableWrite since it's
// 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 (%d0, clearing", SV_Printf ("WARNING %s: [SV_Soundlist] Back buffered (%d), 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);
} }
MSG_WriteByte (&host_client->netchan.message, svc_soundlist); for (s = sv.sound_precache + 1 + block.startsound, i = 0, size = 0;
MSG_WriteByte (&host_client->netchan.message, n); *s; i++, s++) {
for (s = sv.sound_precache + 1 + n; if (host_client->netchan.message.cursize + size >= (MAX_MSGLEN / 2))
*s && host_client->netchan.message.cursize < (MAX_MSGLEN / 2); break;
s++, n++) MSG_WriteString (&host_client->netchan.message, *s); size += strlen (*s) + 1;
block.sounds[i] = *s;
MSG_WriteByte (&host_client->netchan.message, 0); }
block.sounds[i] = "";
// next msg // next msg
if (*s) if (*s)
MSG_WriteByte (&host_client->netchan.message, n); block.nextsound = block.startsound + i;
else else
MSG_WriteByte (&host_client->netchan.message, 0); block.nextsound = 0;
MSG_WriteByte (&host_client->netchan.message, svc_soundlist);
NET_SVC_Soundlist_Emit (&block, &host_client->netchan.message);
} }
/* /*
@ -215,12 +210,14 @@ void
SV_Modellist_f (void) SV_Modellist_f (void)
{ {
const char **s; const char **s;
unsigned n; int i, size;
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");
@ -228,33 +225,40 @@ SV_Modellist_f (void)
return; return;
} }
n = atoi (Cmd_Argv (2)); block.startmodel = atoi (Cmd_Argv (2));
if (n >= MAX_MODELS) { if (block.startmodel >= 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
//spawns. These functions are written to not overflow // NOTE: This doesn't go through ClientReliableWrite since it's
// 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 (%d0, clearing", SV_Printf ("WARNING %s: [SV_Modellist] Back buffered (%d), 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);
} }
MSG_WriteByte (&host_client->netchan.message, svc_modellist); for (s = sv.model_precache + 1 + block.startmodel, i = 0, size = 0;
MSG_WriteByte (&host_client->netchan.message, n); *s; i++, s++) {
for (s = sv.model_precache + 1 + n; if (host_client->netchan.message.cursize + size >= (MAX_MSGLEN / 2))
*s && host_client->netchan.message.cursize < (MAX_MSGLEN / 2); break;
s++, n++) MSG_WriteString (&host_client->netchan.message, *s); size += strlen (*s) + 1;
MSG_WriteByte (&host_client->netchan.message, 0); block.models[i] = *s;
}
block.models[i] = "";
// next msg // next msg
if (*s) if (*s)
MSG_WriteByte (&host_client->netchan.message, n); block.nextmodel = block.startmodel + i;
else else
MSG_WriteByte (&host_client->netchan.message, 0); block.nextmodel = 0;
MSG_WriteByte (&host_client->netchan.message, svc_modellist);
NET_SVC_Modellist_Emit (&block, &host_client->netchan.message);
} }
/* /*
@ -562,27 +566,27 @@ void
SV_NextDownload_f (void) SV_NextDownload_f (void)
{ {
byte buffer[1024]; byte buffer[1024];
int r; net_svc_download_t block;
int percent;
int size;
if (!host_client->download) if (!host_client->download)
return; return;
r = host_client->downloadsize - host_client->downloadcount; block.size = host_client->downloadsize - host_client->downloadcount;
if (r > 768) if (block.size > 768)
r = 768; block.size = 768;
r = Qread (host_client->download, buffer, r); block.size = Qread (host_client->download, buffer, block.size);
ClientReliableWrite_Begin (host_client, svc_download, 6 + r);
ClientReliableWrite_Short (host_client, r);
host_client->downloadcount += r; host_client->downloadcount += block.size;
size = host_client->downloadsize; block.percent = host_client->downloadcount * 100 /
if (!size) (host_client->downloadsize ?: 1);
size = 1;
percent = host_client->downloadcount * 100 / size; block.data = buffer;
ClientReliableWrite_Byte (host_client, percent); ClientReliableWrite_Begin (host_client, svc_download, 6 + block.size);
ClientReliableWrite_SZ (host_client, buffer, r); if (host_client->num_backbuf) {
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;
@ -691,6 +695,7 @@ 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
@ -708,9 +713,14 @@ 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);
ClientReliableWrite_Short (host_client, -1); if (host_client->num_backbuf) {
ClientReliableWrite_Byte (host_client, 0); NET_SVC_Download_Emit (&block, &host_client->backbuf);
ClientReliable_FinishWrite (host_client);
} else
NET_SVC_Download_Emit (&block, &host_client->netchan.message);
return; return;
} }
@ -746,19 +756,30 @@ 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);
ClientReliableWrite_Short (host_client, -1); if (host_client->num_backbuf) {
ClientReliableWrite_Byte (host_client, 0); NET_SVC_Download_Emit (&block, &host_client->backbuf);
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);
ClientReliableWrite_Short (host_client, -2); if (host_client->num_backbuf)
ClientReliableWrite_Byte (host_client, 0); NET_SVC_Download_Emit (&block, &host_client->backbuf);
ClientReliableWrite_String (host_client, realname); else
NET_SVC_Download_Emit (&block, &host_client->netchan.message);
ClientReliable_FinishWrite (host_client); ClientReliable_FinishWrite (host_client);
} }
@ -1115,6 +1136,8 @@ 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);
@ -1153,12 +1176,11 @@ 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);
MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); NET_SVC_SetInfo_Emit (&block, &sv.reliable_datagram);
MSG_WriteString (&sv.reliable_datagram, Cmd_Argv (1));
MSG_WriteString (&sv.reliable_datagram,
Info_ValueForKey (host_client->userinfo,
Cmd_Argv (1)));
} }
} }
@ -1817,7 +1839,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", "1", CVAR_NONE, NULL, sv_kickfake = Cvar_Get ("sv_kickfake", "0", CVAR_NONE, NULL,
"Kick users sending to send fake talk messages"); "Kick users sending to send fake talk messages");
} }