mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
12c84046f3
This is an extremely extensive patch as it hits every cvar, and every usage of the cvars. Cvars no longer store the value they control, instead, they use a cexpr value object to reference the value and specify the value's type (currently, a null type is used for strings). Non-string cvars are passed through cexpr, allowing expressions in the cvars' settings. Also, cvars have returned to an enhanced version of the original (id quake) registration scheme. As a minor benefit, relevant code having direct access to the cvar-controlled variables is probably a slight optimization as it removed a pointer dereference, and the variables can be located for data locality. The static cvar descriptors are made private as an additional safety layer, though there's nothing stopping external modification via Cvar_FindVar (which is needed for adding listeners). While not used yet (partly due to working out the design), cvars can have a validation function. Registering a cvar allows a primary listener (and its data) to be specified: it will always be called first when the cvar is modified. The combination of proper listeners and direct access to the controlled variable greatly simplifies the more complex cvar interactions as much less null checking is required, and there's no need for one cvar's callback to call another's. nq-x11 is known to work at least well enough for the demos. More testing will come.
1043 lines
28 KiB
C
1043 lines
28 KiB
C
/*
|
|
net_packetlog.c
|
|
|
|
packet logging/parsing - for debugging and educational purposes
|
|
|
|
**EXPERIMENTAL**
|
|
|
|
Copyright (C) 2000 Jukka Sorjonen <jukka.sorjonen@asikkala.fi>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_IO_H
|
|
# include <io.h>
|
|
#endif
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "QF/cmd.h"
|
|
#include "QF/cvar.h"
|
|
#include "QF/msg.h"
|
|
#include "QF/quakefs.h"
|
|
#include "QF/sys.h"
|
|
#include "QF/va.h"
|
|
|
|
#include "compat.h"
|
|
|
|
#include "netchan.h"
|
|
#include "qw/protocol.h"
|
|
#include "qw/include/server.h"
|
|
|
|
int net_packetlog;
|
|
static cvar_t net_packetlog_cvar = {
|
|
.name = "net_packetlog",
|
|
.description =
|
|
"enable/disable packet logging",
|
|
.default_value = "0",
|
|
.flags = CVAR_NONE,
|
|
.value = { .type = &cexpr_int, .value = &net_packetlog },
|
|
};
|
|
int net_loglevel;
|
|
static cvar_t net_loglevel_cvar = {
|
|
.name = "net_loglevel",
|
|
.description =
|
|
"Packet logging/parsing",
|
|
.default_value = "2",
|
|
.flags = CVAR_NONE,
|
|
.value = { .type = &cexpr_int, .value = &net_loglevel },
|
|
};
|
|
|
|
// 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[] = {
|
|
"clc_bad",
|
|
"clc_nop",
|
|
"clc_disconnect",
|
|
"clc_move",
|
|
"clc_stringcmd",
|
|
"clc_delta",
|
|
"clc_tmove",
|
|
"clc_upload"
|
|
};
|
|
|
|
#ifndef svc_spawnbinary
|
|
# define svc_spawnbinary 21
|
|
#endif
|
|
|
|
// Quake1, obsolete for QW
|
|
#define svc_time 7 // [float] server time
|
|
#define svc_updatename 13 // [byte] [string]
|
|
#define svc_version 4 // [long] server version
|
|
#define svc_clientdata 15 // <shortbits + data>
|
|
#define svc_updatecolors 17 // [byte] [byte]
|
|
#define svc_particle 18 // [vec3] <variable>
|
|
#define svc_signonnum 25 // [byte] used for the signon
|
|
// sequence
|
|
static QFile *_stdout;
|
|
static QFile *Net_PacketLog;
|
|
static const char **Net_sound_precache;
|
|
static sizebuf_t _packet;
|
|
static qmsg_t packet = {0, 0, &_packet};
|
|
static int is_server = 0;
|
|
|
|
static int
|
|
Net_LogStart (const char *fname)
|
|
{
|
|
Sys_Printf ("Opening packet logfile: %s\n", fname);
|
|
Net_PacketLog = QFS_Open (fname, "at");
|
|
if (!Net_PacketLog)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
Net_LogStop (void *data)
|
|
{
|
|
if (Net_PacketLog)
|
|
Qclose (Net_PacketLog);
|
|
Net_PacketLog = NULL;
|
|
}
|
|
|
|
static void
|
|
hex_dump_buf (unsigned char *buf, int len)
|
|
{
|
|
int pos = 0, llen, i;
|
|
|
|
while (pos < len) {
|
|
llen = (len - pos < 16 ? len - pos : 16);
|
|
Net_LogPrintf ("%08x: ", pos);
|
|
for (i = 0; i < llen; i++)
|
|
Net_LogPrintf ("%02x ", buf[pos + i]);
|
|
for (i = 0; i < 16 - llen; i++)
|
|
Net_LogPrintf (" ");
|
|
Net_LogPrintf (" | ");
|
|
|
|
for (i = 0; i < llen; i++)
|
|
Net_LogPrintf ("%c", isprint (buf[pos + i]) ? buf[pos + i] : '.');
|
|
for (i = 0; i < 16 - llen; i++)
|
|
Net_LogPrintf (" ");
|
|
Net_LogPrintf ("\n");
|
|
pos += llen;
|
|
}
|
|
}
|
|
/*
|
|
static void
|
|
ascii_dump_buf (unsigned char *buf, int len)
|
|
{
|
|
int pos = 0, llen, i;
|
|
|
|
while (pos < len) {
|
|
llen = (len - pos < 60 ? len - pos : 60);
|
|
Net_LogPrintf ("%08x: ", pos);
|
|
for (i = 0; i < llen; i++)
|
|
Net_LogPrintf ("%c", isprint (buf[pos + i]) ? buf[pos + i] : '.');
|
|
Net_LogPrintf ("\n");
|
|
pos += llen;
|
|
}
|
|
}
|
|
*/
|
|
void
|
|
Log_Incoming_Packet (const byte *p, int len, int has_sequence)
|
|
{
|
|
if (!net_loglevel)
|
|
return;
|
|
|
|
if (is_server) {
|
|
Net_LogPrintf ("\n<<<<<<<<<<<<<<<<<<<<< client to server %d bytes: "
|
|
"<<<<<<<<<<<<<<<<<<<<<<<<\n", len);
|
|
if (net_loglevel != 3)
|
|
hex_dump_buf ((unsigned char *) p, len);
|
|
if (net_loglevel > 1)
|
|
Analyze_Client_Packet (p, len, has_sequence);
|
|
} else {
|
|
Net_LogPrintf ("\n>>>>>>>>>>>>>>>>>>>>> server to client %d bytes: "
|
|
">>>>>>>>>>>>>>>>>>>>>>>>\n", len);
|
|
if (net_loglevel != 3)
|
|
hex_dump_buf ((unsigned char *) p, len);
|
|
if (net_loglevel > 1)
|
|
Analyze_Server_Packet (p, len, has_sequence);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
Log_Outgoing_Packet (const byte *p, int len, int has_sequence)
|
|
{
|
|
if (!net_loglevel)
|
|
return;
|
|
|
|
if (is_server) {
|
|
Net_LogPrintf ("\n>>>>>>>>>>>>>>>>>>>>> server to client %d bytes: "
|
|
">>>>>>>>>>>>>>>>>>>>>>>>\n", len);
|
|
if (net_loglevel != 3)
|
|
hex_dump_buf ((unsigned char *) p, len);
|
|
if (net_loglevel > 1)
|
|
Analyze_Server_Packet (p, len, has_sequence);
|
|
} else {
|
|
Net_LogPrintf ("\n<<<<<<<<<<<<<<<<<<<<< client to server %d bytes: "
|
|
"<<<<<<<<<<<<<<<<<<<<<<<<\n", len);
|
|
if (net_loglevel != 3)
|
|
hex_dump_buf ((unsigned char *) p, len);
|
|
if (net_loglevel > 1)
|
|
Analyze_Client_Packet (p, len, has_sequence);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
Log_Delta (int bits)
|
|
{
|
|
entity_state_t to;
|
|
int i;
|
|
|
|
// set everything to the state we are delta'ing from
|
|
|
|
to.number = bits & 511;
|
|
to.frame = 0;
|
|
to.effects = 0;
|
|
bits &= ~511;
|
|
|
|
if (bits & U_MOREBITS) { // read in the low order bits
|
|
i = MSG_ReadByte (&packet);
|
|
bits |= i;
|
|
}
|
|
|
|
// LordHavoc: Endy neglected to mark this as being part of the QSG
|
|
// version 2 stuff...
|
|
if (bits & U_EXTEND1) {
|
|
bits |= MSG_ReadByte (&packet) << 16;
|
|
if (bits & U_EXTEND2)
|
|
bits |= MSG_ReadByte (&packet) << 24;
|
|
}
|
|
|
|
to.flags = bits;
|
|
|
|
if (bits & U_MODEL)
|
|
Net_LogPrintf (" MdlIdx: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_FRAME) {
|
|
to.frame = MSG_ReadByte (&packet);
|
|
Net_LogPrintf (" Frame: %d", to.frame);
|
|
}
|
|
if (bits & U_COLORMAP)
|
|
Net_LogPrintf (" Colormap: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_SKIN)
|
|
Net_LogPrintf (" Skinnum: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_EFFECTS) {
|
|
to.effects = MSG_ReadByte (&packet);
|
|
Net_LogPrintf (" Effects: %d", to.effects);
|
|
}
|
|
if (bits & U_ORIGIN1)
|
|
Net_LogPrintf (" X: %f", MSG_ReadCoord (&packet));
|
|
if (bits & U_ANGLE1)
|
|
Net_LogPrintf (" Pitch: %f", MSG_ReadAngle (&packet));
|
|
if (bits & U_ORIGIN2)
|
|
Net_LogPrintf (" Y: %f", MSG_ReadCoord (&packet));
|
|
if (bits & U_ANGLE2)
|
|
Net_LogPrintf (" Yaw: %f", MSG_ReadAngle (&packet));
|
|
if (bits & U_ORIGIN3)
|
|
Net_LogPrintf (" Z: %f", MSG_ReadCoord (&packet));
|
|
if (bits & U_ANGLE3)
|
|
Net_LogPrintf (" Roll: %f", MSG_ReadAngle (&packet));
|
|
|
|
// Ender (QSG - Begin)
|
|
if (bits & U_ALPHA)
|
|
Net_LogPrintf (" Alpha: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_SCALE)
|
|
Net_LogPrintf (" Scale: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_EFFECTS2)
|
|
Net_LogPrintf (" U_EFFECTS2: %d", (to.effects & 0xFF) |
|
|
(MSG_ReadByte (&packet) << 8));
|
|
if (bits & U_GLOWSIZE)
|
|
Net_LogPrintf (" GlowSize: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_GLOWCOLOR)
|
|
Net_LogPrintf (" ColorGlow: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_COLORMOD)
|
|
Net_LogPrintf (" Colormod: %d", MSG_ReadByte (&packet));
|
|
if (bits & U_FRAME2)
|
|
Net_LogPrintf (" Uframe2: %d", ((to.frame & 0xFF) |
|
|
(MSG_ReadByte (&packet) << 8)));
|
|
// Ender (QSG - End)
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
Parse_Server_Packet (int has_sequence)
|
|
{
|
|
const char *s;
|
|
int c = 0, i, ii, iii, mask1, mask2;
|
|
long seq1 = 0, seq2;
|
|
|
|
if (has_sequence) {
|
|
seq1 = MSG_ReadLong (&packet);
|
|
if (packet.badread)
|
|
return;
|
|
}
|
|
|
|
if (seq1 == -1) {
|
|
Net_LogPrintf ("Special Packet");
|
|
} else {
|
|
if (has_sequence) {
|
|
seq2 = MSG_ReadLong (&packet);
|
|
// FIXME: display seqs right when reliable
|
|
Net_LogPrintf ("\nSeq: %ld Ack: %ld ", seq1 & 0x7FFFFFFF,
|
|
seq2 & 0x7FFFFFFF);
|
|
|
|
if ((seq1 >> 31) & 0x01)
|
|
Net_LogPrintf ("SV_REL ");
|
|
if ((seq2 >> 31) & 0x01)
|
|
Net_LogPrintf ("SV_RELACK");
|
|
Net_LogPrintf ("\n");
|
|
}
|
|
|
|
while (1) {
|
|
if (packet.badread) {
|
|
Net_LogPrintf ("*** BAD READ *** %s", svc_string[c]);
|
|
break;
|
|
}
|
|
c = MSG_ReadByte (&packet);
|
|
if (c == -1)
|
|
break;
|
|
Net_LogPrintf ("<%06x> [0x%02x] ", MSG_GetReadCount (&packet), c);
|
|
|
|
if (c < 53)
|
|
Net_LogPrintf ("%s: ", svc_string[c]);
|
|
|
|
if (MSG_GetReadCount (&packet) > packet.message->cursize)
|
|
return;
|
|
|
|
switch (c) {
|
|
case svc_bad:
|
|
Net_LogPrintf (" - should not happen");
|
|
break;
|
|
case svc_nop:
|
|
Net_LogPrintf (" No operation");
|
|
break;
|
|
case svc_disconnect:
|
|
Net_LogPrintf (" <Quit>");
|
|
break;
|
|
case svc_updatestat:
|
|
i = MSG_ReadByte (&packet);
|
|
Net_LogPrintf (" index: %d value: %d", i, MSG_ReadByte
|
|
(&packet));
|
|
break;
|
|
case svc_version:
|
|
Net_LogPrintf ("**QW OBSOLETE**");
|
|
break;
|
|
case svc_setview:
|
|
Net_LogPrintf ("**QW OBSOLETE**");
|
|
break;
|
|
case svc_sound:
|
|
i = MSG_ReadShort (&packet);
|
|
Net_LogPrintf (": (%d) ", i);
|
|
if (i & SND_VOLUME)
|
|
Net_LogPrintf ("Volume %d ", MSG_ReadByte (&packet));
|
|
if (i & SND_ATTENUATION)
|
|
Net_LogPrintf ("Ann: %f",
|
|
(float) MSG_ReadByte (&packet) / 64.0);
|
|
ii = MSG_ReadByte (&packet);
|
|
|
|
Net_LogPrintf ("%d (%s) ", ii, Net_sound_precache[ii]);
|
|
Net_LogPrintf ("Pos: ");
|
|
for (ii = 0; ii < 3; ii++)
|
|
Net_LogPrintf ("%f ", MSG_ReadCoord (&packet));
|
|
Net_LogPrintf ("Ent: %d ", (i >> 3) & 1023);
|
|
Net_LogPrintf ("Channel %d ", i & 7);
|
|
break;
|
|
case svc_time:
|
|
Net_LogPrintf ("**QW OBSOLETE**\n");
|
|
break;
|
|
case svc_print:
|
|
// FIXME: i==PRINT_CHAT
|
|
Net_LogPrintf ("[%d] ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("%s", MSG_ReadString (&packet));
|
|
break;
|
|
case svc_stufftext:
|
|
Net_LogPrintf ("%s", MSG_ReadString (&packet));
|
|
break;
|
|
case svc_setangle:
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%f ", MSG_ReadAngle (&packet));
|
|
break;
|
|
case svc_serverdata:
|
|
Net_LogPrintf ("Ver: %d", MSG_ReadLong (&packet));
|
|
Net_LogPrintf (" Client ID: %d", MSG_ReadLong (&packet));
|
|
Net_LogPrintf (" Dir: %s", MSG_ReadString (&packet));
|
|
Net_LogPrintf (" User ID: %d", MSG_ReadByte (&packet));
|
|
Net_LogPrintf (" Map: %s", MSG_ReadString (&packet));
|
|
for (i = 0; i < 10; i++)
|
|
MSG_ReadFloat (&packet);
|
|
break;
|
|
|
|
case svc_lightstyle:
|
|
i = MSG_ReadByte (&packet);
|
|
if (i >= MAX_LIGHTSTYLES)
|
|
return;
|
|
Net_LogPrintf ("%d %s", i, MSG_ReadString (&packet));
|
|
break;
|
|
case svc_updatename:
|
|
Net_LogPrintf ("**QW OBSOLETE**");
|
|
break;
|
|
case svc_updatefrags:
|
|
Net_LogPrintf ("player: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("frags: %d",
|
|
(short) MSG_ReadShort (&packet));
|
|
break;
|
|
case svc_clientdata:
|
|
Net_LogPrintf ("**QW OBSOLETE**");
|
|
break;
|
|
case svc_stopsound:
|
|
Net_LogPrintf ("%d", MSG_ReadShort (&packet));
|
|
break;
|
|
|
|
case svc_updatecolors:
|
|
Net_LogPrintf ("**QW OBSOLETE**");
|
|
break;
|
|
case svc_particle:
|
|
Net_LogPrintf ("**QW OBSOLETE**");
|
|
break;
|
|
|
|
case svc_damage:
|
|
// FIXME: parse damage
|
|
Net_LogPrintf ("armor: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("health: %d from", MSG_ReadByte (&packet));
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%f%s", MSG_ReadCoord (&packet),
|
|
i < 2 ? "," : "");
|
|
break;
|
|
case svc_spawnstatic:
|
|
Net_LogPrintf ("Model: %d", MSG_ReadByte (&packet));
|
|
Net_LogPrintf (" Frame: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("Color: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("Skin: %d", MSG_ReadByte (&packet));
|
|
for (i = 0; i < 3; i++) {
|
|
Net_LogPrintf ("%d: %f ", i + 1,
|
|
MSG_ReadCoord (&packet));
|
|
Net_LogPrintf ("%f", MSG_ReadAngle (&packet));
|
|
}
|
|
break;
|
|
case svc_spawnbinary:
|
|
Net_LogPrintf ("**OBSOLETE**");
|
|
break;
|
|
case svc_spawnbaseline:
|
|
Net_LogPrintf ("%d", MSG_ReadShort (&packet));
|
|
Net_LogPrintf (" idx: %d", MSG_ReadByte (&packet));
|
|
Net_LogPrintf (" Frame: %d", MSG_ReadByte (&packet));
|
|
Net_LogPrintf (" Colormap: %d", MSG_ReadByte (&packet));
|
|
Net_LogPrintf (" Skin: %d", MSG_ReadByte (&packet));
|
|
for (i = 0; i < 3; i++) {
|
|
Net_LogPrintf (" %f", MSG_ReadCoord (&packet));
|
|
Net_LogPrintf (" %f", MSG_ReadAngle (&packet));
|
|
};
|
|
break;
|
|
case svc_temp_entity:
|
|
i = MSG_ReadByte (&packet);
|
|
Net_LogPrintf (" type %d", i);
|
|
switch (i) {
|
|
case 0:
|
|
case 1:
|
|
case 3:
|
|
case 4:
|
|
case 7:
|
|
case 8:
|
|
case 10:
|
|
case 11:
|
|
case 13:
|
|
Net_LogPrintf (" origin");
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf (" %f", MSG_ReadCoord (&packet));
|
|
break;
|
|
case 5:
|
|
case 6:
|
|
case 9:
|
|
Net_LogPrintf (" created by %d",
|
|
MSG_ReadShort (&packet));
|
|
Net_LogPrintf (" origin:");
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%c%f", i ? ',' : ' ',
|
|
MSG_ReadCoord (&packet));
|
|
Net_LogPrintf (" trace endpos:");
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%c%f", i ? ',' : ' ',
|
|
MSG_ReadCoord (&packet));
|
|
break;
|
|
case 2:
|
|
case 12:
|
|
Net_LogPrintf (" count: %d", MSG_ReadByte
|
|
(&packet));
|
|
Net_LogPrintf (" origin:");
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%c%f", i ? ',' : ' ',
|
|
MSG_ReadCoord (&packet));
|
|
break;
|
|
default:
|
|
Net_LogPrintf (" unknown value %d for tempentity",
|
|
i);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case svc_setpause:
|
|
Net_LogPrintf (" %d", MSG_ReadByte (&packet));
|
|
break;
|
|
case svc_signonnum:
|
|
Net_LogPrintf ("**QW OBSOLETE**");
|
|
break;
|
|
case svc_centerprint:
|
|
Net_LogPrintf ("%s\n", MSG_ReadString (&packet));
|
|
break;
|
|
case svc_killedmonster:
|
|
break;
|
|
case svc_foundsecret:
|
|
break;
|
|
case svc_spawnstaticsound:
|
|
Net_LogPrintf ("pos");
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%c%f", i ? ',' : ' ',
|
|
MSG_ReadCoord (&packet));
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf (" %d", MSG_ReadByte (&packet));
|
|
break;
|
|
case svc_intermission:
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%f ", MSG_ReadCoord (&packet));
|
|
Net_LogPrintf ("\n");
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%f ", MSG_ReadAngle (&packet));
|
|
break;
|
|
case svc_finale:
|
|
Net_LogPrintf ("%s", MSG_ReadString (&packet));
|
|
break;
|
|
case svc_cdtrack:
|
|
Net_LogPrintf ("%d", MSG_ReadByte (&packet));
|
|
break;
|
|
case svc_sellscreen:
|
|
break;
|
|
case svc_smallkick:
|
|
break;
|
|
case svc_bigkick:
|
|
break;
|
|
case svc_updateping:
|
|
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("Ping: %d", MSG_ReadShort (&packet));
|
|
break;
|
|
case svc_updateentertime:
|
|
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("Time: %f", MSG_ReadFloat (&packet));
|
|
break;
|
|
|
|
case svc_updatestatlong:
|
|
i = MSG_ReadByte (&packet);
|
|
Net_LogPrintf ("%d value: %d", i, MSG_ReadLong (&packet));
|
|
break;
|
|
|
|
case svc_muzzleflash:
|
|
Net_LogPrintf ("%d", MSG_ReadShort (&packet));
|
|
break;
|
|
|
|
case svc_updateuserinfo:
|
|
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("ID: %d ", MSG_ReadLong (&packet));
|
|
Net_LogPrintf ("Info: %s", MSG_ReadString (&packet));
|
|
break;
|
|
case svc_download:
|
|
ii = MSG_ReadShort (&packet);
|
|
Net_LogPrintf ("%d bytes at %d", ii, MSG_ReadByte
|
|
(&packet));
|
|
for (i = 0; i < ii; i++)
|
|
MSG_ReadByte (&packet);
|
|
break;
|
|
case svc_playerinfo:
|
|
Net_LogPrintf ("\n\tPlayer: %d", MSG_ReadByte (&packet));
|
|
mask1 = MSG_ReadShort (&packet);
|
|
Net_LogPrintf (" Mask1: %d", mask1);
|
|
#if 1
|
|
Net_LogPrintf (" Origin:");
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%c%f", i ? ',' : ' ',
|
|
MSG_ReadCoord (&packet));
|
|
#endif
|
|
Net_LogPrintf (" Frame: %d", MSG_ReadByte (&packet));
|
|
|
|
#if 1
|
|
if (mask1 & PF_MSEC)
|
|
Net_LogPrintf (" Ping: %d", MSG_ReadByte (&packet));
|
|
|
|
if (mask1 & PF_COMMAND) {
|
|
mask2 = MSG_ReadByte (&packet); // command
|
|
if (mask2 & 0x01)
|
|
Net_LogPrintf (" Pitch: %f", MSG_ReadAngle16
|
|
(&packet));
|
|
if (mask2 & 0x80)
|
|
Net_LogPrintf (" Yaw: %f", MSG_ReadAngle16
|
|
(&packet));
|
|
if (mask2 & 0x02)
|
|
Net_LogPrintf (" Roll: %f", MSG_ReadAngle16
|
|
(&packet));
|
|
if (mask2 & 0x04)
|
|
Net_LogPrintf (" Speed1: %d",
|
|
MSG_ReadShort (&packet));
|
|
if (mask2 & 0x08)
|
|
Net_LogPrintf (" Speed2: %d",
|
|
MSG_ReadShort (&packet));
|
|
if (mask2 & 0x10)
|
|
Net_LogPrintf (" Speed3: %d",
|
|
MSG_ReadShort (&packet));
|
|
if (mask2 & 0x20)
|
|
Net_LogPrintf (" Flag: %d", MSG_ReadByte
|
|
(&packet));
|
|
if (mask2 & 0x40)
|
|
Net_LogPrintf (" Impulse: %d", MSG_ReadByte
|
|
(&packet));
|
|
Net_LogPrintf (" Msec: %d", MSG_ReadByte (&packet));
|
|
}
|
|
if (mask1 & PF_VELOCITY1)
|
|
Net_LogPrintf (" Xspd: %f", MSG_ReadCoord (&packet));
|
|
if (mask1 & PF_VELOCITY2)
|
|
Net_LogPrintf (" Yspd: %f", MSG_ReadCoord (&packet));
|
|
if (mask1 & PF_VELOCITY3)
|
|
Net_LogPrintf (" ZSpd: %f", MSG_ReadCoord (&packet));
|
|
if (mask1 & PF_MODEL)
|
|
Net_LogPrintf (" Model: %d", MSG_ReadByte (&packet));
|
|
if (mask1 & PF_SKINNUM)
|
|
Net_LogPrintf (" Skin: %d", MSG_ReadByte (&packet));
|
|
if (mask1 & PF_EFFECTS)
|
|
Net_LogPrintf (" Effects: %d", MSG_ReadByte (&packet));
|
|
|
|
if (mask1 & PF_WEAPONFRAME)
|
|
Net_LogPrintf (" Weapon frame: %d", MSG_ReadByte
|
|
(&packet));
|
|
|
|
#else
|
|
if (mask1 & (DF_ORIGIN | (DF_ORIGIN << 1)
|
|
| (DF_ORIGIN << 2))) {
|
|
Net_LogPrintf (" Origin:");
|
|
for (i = 0; i < 3; i++)
|
|
if (mask1 & (DF_ORIGIN << i))
|
|
Net_LogPrintf ("%c%f", i ? ',' : ' ',
|
|
MSG_ReadCoord (&packet));
|
|
else
|
|
Net_LogPrintf ("%c", i ? ',' : ' ');
|
|
}
|
|
if (mask1 & (DF_ANGLES | (DF_ANGLES << 1)
|
|
| (DF_ANGLES << 2))) {
|
|
Net_LogPrintf (" Angles:");
|
|
for (i = 0; i < 3; i++)
|
|
if (mask1 & (DF_ANGLES << i))
|
|
Net_LogPrintf ("%c%f", i ? ',' : ' ',
|
|
MSG_ReadAngle16 (&packet));
|
|
else
|
|
Net_LogPrintf ("%c", i ? ',' : ' ');
|
|
}
|
|
if (mask1 & DF_MODEL)
|
|
Net_LogPrintf (" Model: %d", MSG_ReadByte (&packet));
|
|
if (mask1 & DF_SKINNUM)
|
|
Net_LogPrintf (" Skin: %d", MSG_ReadByte (&packet));
|
|
if (mask1 & DF_EFFECTS)
|
|
Net_LogPrintf (" Effects: %d", MSG_ReadByte (&packet));
|
|
|
|
if (mask1 & DF_WEAPONFRAME)
|
|
Net_LogPrintf (" Weapon frame: %d", MSG_ReadByte
|
|
(&packet));
|
|
#endif
|
|
break;
|
|
case svc_nails:
|
|
ii = MSG_ReadByte (&packet);
|
|
Net_LogPrintf (" %d (bits not parsed)", ii);
|
|
for (i = 0; i < ii; i++) {
|
|
for (iii = 0; iii < 6; iii++)
|
|
MSG_ReadByte (&packet);
|
|
}
|
|
break;
|
|
case svc_chokecount:
|
|
Net_LogPrintf ("%d", MSG_ReadByte (&packet));
|
|
break;
|
|
case svc_modellist:
|
|
ii = MSG_ReadByte (&packet);
|
|
Net_LogPrintf ("start %d", ii);
|
|
for (i = ii; i < 256; i++) {
|
|
s = MSG_ReadString (&packet);
|
|
if (packet.badread)
|
|
break;
|
|
if (!s)
|
|
break;
|
|
if (strlen (s) == 0)
|
|
break;
|
|
Net_LogPrintf ("\n\tModel %d: %s", i, s);
|
|
}
|
|
i = MSG_ReadByte (&packet);
|
|
if (i)
|
|
Net_LogPrintf ("\n\tnext at %d", i);
|
|
else
|
|
Net_LogPrintf ("\n\t*End of modellist*");
|
|
break;
|
|
case svc_soundlist:
|
|
ii = MSG_ReadByte (&packet);
|
|
Net_LogPrintf ("start %d", ii);
|
|
for (i = ii; i < 256; i++) {
|
|
s = MSG_ReadString (&packet);
|
|
if (packet.badread)
|
|
break;
|
|
if (!s)
|
|
break;
|
|
if (strlen (s) == 0)
|
|
break;
|
|
Net_LogPrintf ("\n\tSound %d: %s", i, s);
|
|
}
|
|
i = MSG_ReadByte (&packet);
|
|
|
|
if (i)
|
|
Net_LogPrintf ("\n\tnext at %d", i);
|
|
else
|
|
Net_LogPrintf ("\n\t*End of sound list*");
|
|
break;
|
|
case svc_packetentities:
|
|
packetentities:
|
|
while (1) {
|
|
mask1 = MSG_ReadShort (&packet);
|
|
if (packet.badread) {
|
|
Net_LogPrintf ("Badread\n");
|
|
return;
|
|
}
|
|
if (!mask1)
|
|
break;
|
|
Net_LogPrintf ("%d", mask1 & 511);
|
|
if (mask1 & U_REMOVE)
|
|
Net_LogPrintf (" UREMOVE");
|
|
Log_Delta (mask1);
|
|
Net_LogPrintf ("\n");
|
|
}
|
|
break;
|
|
case svc_deltapacketentities:
|
|
Net_LogPrintf ("idx: %d\n", MSG_ReadByte (&packet));
|
|
goto packetentities;
|
|
break;
|
|
case svc_maxspeed:
|
|
Net_LogPrintf ("%f", MSG_ReadFloat (&packet));
|
|
break;
|
|
case svc_entgravity:
|
|
Net_LogPrintf ("%f", MSG_ReadFloat (&packet));
|
|
break;
|
|
case svc_setinfo:
|
|
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("Keyname: %s ", MSG_ReadString (&packet));
|
|
Net_LogPrintf ("Value: %s", MSG_ReadString (&packet));
|
|
break;
|
|
case svc_serverinfo:
|
|
Net_LogPrintf ("Name: %s ", MSG_ReadString (&packet));
|
|
Net_LogPrintf ("Value: %s", MSG_ReadString (&packet));
|
|
break;
|
|
case svc_updatepl:
|
|
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("Ploss: %d", MSG_ReadByte (&packet));
|
|
break;
|
|
default:
|
|
Net_LogPrintf ("**UNKNOWN**: [%d]", c);
|
|
break;
|
|
}
|
|
Net_LogPrintf ("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Analyze_Server_Packet (const byte * data, int len, int has_sequence)
|
|
{
|
|
if (!Net_PacketLog)
|
|
Net_PacketLog = _stdout;
|
|
packet.message->data = (byte*)data;
|
|
packet.message->cursize = len;
|
|
MSG_BeginReading (&packet);
|
|
Parse_Server_Packet (has_sequence);
|
|
if (Net_PacketLog == _stdout)
|
|
Net_PacketLog = NULL;
|
|
}
|
|
|
|
static void
|
|
Parse_Client_Packet (int has_sequence)
|
|
{
|
|
int mask, i, c, ii;
|
|
long seq1 = 0, seq2;
|
|
|
|
if (has_sequence)
|
|
seq1 = MSG_ReadLong (&packet);
|
|
if (seq1 == -1) {
|
|
Net_LogPrintf ("Special: %s\n", MSG_ReadString (&packet));
|
|
return;
|
|
} else {
|
|
if (has_sequence) {
|
|
// FIXME: display seqs right when reliable
|
|
seq2 = MSG_ReadLong (&packet);
|
|
|
|
Net_LogPrintf ("\nSeq: %ld Ack: %ld ", seq1 & 0x7FFFFFFF,
|
|
seq2 & 0x7FFFFFFF);
|
|
|
|
Net_LogPrintf ("QP: %u\n", MSG_ReadShort (&packet) & 0xFFFF);
|
|
}
|
|
|
|
while (1) {
|
|
if (packet.badread)
|
|
break;
|
|
c = MSG_ReadByte (&packet);
|
|
if (c == -1)
|
|
break;
|
|
Net_LogPrintf ("\n<%06x> [0x%02x] ", MSG_GetReadCount (&packet),
|
|
c);
|
|
if (c < 8)
|
|
Net_LogPrintf ("%s: ", clc_string[c]);
|
|
|
|
switch (c) {
|
|
case clc_nop:
|
|
break;
|
|
case clc_delta:
|
|
Net_LogPrintf ("%d", MSG_ReadByte (&packet));
|
|
break;
|
|
case clc_move:
|
|
Net_LogPrintf ("checksum = %02x ", MSG_ReadByte (&packet));
|
|
Net_LogPrintf ("PacketLoss: %d", MSG_ReadByte (&packet));
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
mask = MSG_ReadByte (&packet);
|
|
Net_LogPrintf ("\n\t(%d) mask = %02x", i, mask);
|
|
if (mask & 0x01)
|
|
Net_LogPrintf (" Tilt: %f", MSG_ReadAngle16
|
|
(&packet));
|
|
if (mask & 0x80)
|
|
Net_LogPrintf (" Yaw: %f", MSG_ReadAngle16
|
|
(&packet));
|
|
if (mask & 0x02)
|
|
Net_LogPrintf (" Roll: %f", MSG_ReadAngle16
|
|
(&packet));
|
|
if (mask & 0x04)
|
|
Net_LogPrintf (" Fwd: %d",
|
|
MSG_ReadShort (&packet));
|
|
if (mask & 0x08)
|
|
Net_LogPrintf (" Right: %d",
|
|
MSG_ReadShort (&packet));
|
|
if (mask & 0x10)
|
|
Net_LogPrintf (" Up: %d",
|
|
MSG_ReadShort (&packet));
|
|
if (mask & 0x20)
|
|
Net_LogPrintf (" Flags: %d", MSG_ReadByte
|
|
(&packet));
|
|
if (mask & 0x40)
|
|
Net_LogPrintf (" Impulse: %d", MSG_ReadByte
|
|
(&packet));
|
|
Net_LogPrintf (" Msec: %d", MSG_ReadByte (&packet));
|
|
}
|
|
break;
|
|
case clc_stringcmd:
|
|
Net_LogPrintf ("%s", MSG_ReadString (&packet));
|
|
break;
|
|
case clc_tmove:
|
|
for (i = 0; i < 3; i++)
|
|
Net_LogPrintf ("%f ", MSG_ReadCoord (&packet));
|
|
break;
|
|
case clc_upload:
|
|
ii = MSG_ReadShort (&packet);
|
|
Net_LogPrintf ("%d bytes at %d", ii, MSG_ReadByte
|
|
(&packet));
|
|
for (i = 0; i < ii; i++)
|
|
MSG_ReadByte (&packet);
|
|
break;
|
|
default:
|
|
Net_LogPrintf ("**UNKNOWN**: [%d]", c);
|
|
break;
|
|
}
|
|
Net_LogPrintf ("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Analyze_Client_Packet (const byte * data, int len, int has_sequence)
|
|
{
|
|
if (!Net_PacketLog)
|
|
Net_PacketLog = _stdout;
|
|
packet.message->data = (byte*)data;
|
|
packet.message->cursize = len;
|
|
MSG_BeginReading (&packet);
|
|
Parse_Client_Packet (has_sequence);
|
|
if (Net_PacketLog == _stdout)
|
|
Net_PacketLog = NULL;
|
|
}
|
|
|
|
static void
|
|
net_packet_log_f (int length, const void *data, netadr_t to)
|
|
{
|
|
Log_Outgoing_Packet (data, length, 1);
|
|
}
|
|
|
|
static void
|
|
Net_PacketLog_f (void *data, const cvar_t *cvar)
|
|
{
|
|
if (net_packetlog) {
|
|
Net_LogStart ("qfpacket.log");
|
|
net_log_packet = net_packet_log_f;
|
|
} else {
|
|
Net_LogStop (0);
|
|
net_log_packet = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
Net_PacketLog_Zap_f (void)
|
|
{
|
|
if (Net_PacketLog && Net_PacketLog != _stdout) {
|
|
Sys_Printf ("truncating packet logfile: %s\n", "qfpacket.log");
|
|
Qseek (Net_PacketLog, 0, 0);
|
|
Qwrite (Net_PacketLog, 0, 0);
|
|
} else {
|
|
Sys_Printf ("Deleting packet logfile: %s\n", "qfpacket.log");
|
|
QFS_Remove ("qfpacket.log");
|
|
}
|
|
}
|
|
|
|
int
|
|
Net_Log_Init (const char **sound_precache, int server)
|
|
{
|
|
is_server = server;
|
|
Net_sound_precache = sound_precache;
|
|
|
|
_stdout = Qdopen (1, "wt"); // create a QFile of stdout
|
|
|
|
Cvar_Register (&net_packetlog_cvar, Net_PacketLog_f, 0);
|
|
|
|
// 0 = no logging
|
|
// 1 = hex dump only
|
|
// 2 = parse/hexdump
|
|
// 3 = just parse
|
|
// 4 = parse/hexdump, skip movement/empty messages
|
|
|
|
Cvar_Register (&net_loglevel_cvar, 0, 0);
|
|
|
|
Cmd_AddCommand ("net_packetlog_zap", Net_PacketLog_Zap_f,
|
|
"clear the packet log file");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
NET_LogPrintf
|
|
|
|
Prints packet to logfile, adds time stamp etc.
|
|
*/
|
|
void
|
|
Net_LogPrintf (const char *fmt, ...)
|
|
{
|
|
char text[2048];
|
|
va_list argptr;
|
|
|
|
va_start (argptr, fmt);
|
|
vsnprintf (text, sizeof (text), fmt, argptr);
|
|
va_end (argptr);
|
|
if (!Net_PacketLog)
|
|
return;
|
|
|
|
Qprintf (Net_PacketLog, "%s", text);
|
|
Qflush (Net_PacketLog);
|
|
}
|