242 lines
5.1 KiB
242 lines
5.1 KiB
/* |
|
cl_debug.c - server message debugging |
|
Copyright (C) 2018 Uncle Mike |
|
|
|
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 3 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. |
|
*/ |
|
|
|
#include "common.h" |
|
#include "client.h" |
|
#include "net_encode.h" |
|
#include "particledef.h" |
|
#include "cl_tent.h" |
|
#include "shake.h" |
|
#include "hltv.h" |
|
#include "input.h" |
|
|
|
#define MSG_COUNT 32 // last 32 messages parsed |
|
#define MSG_MASK (MSG_COUNT - 1) |
|
|
|
const char *svc_strings[svc_lastmsg+1] = |
|
{ |
|
"svc_bad", |
|
"svc_nop", |
|
"svc_disconnect", |
|
"svc_event", |
|
"svc_changing", |
|
"svc_setview", |
|
"svc_sound", |
|
"svc_time", |
|
"svc_print", |
|
"svc_stufftext", |
|
"svc_setangle", |
|
"svc_serverdata", |
|
"svc_lightstyle", |
|
"svc_updateuserinfo", |
|
"svc_deltatable", |
|
"svc_clientdata", |
|
"svc_resource", |
|
"svc_pings", |
|
"svc_particle", |
|
"svc_restoresound", |
|
"svc_spawnstatic", |
|
"svc_event_reliable", |
|
"svc_spawnbaseline", |
|
"svc_temp_entity", |
|
"svc_setpause", |
|
"svc_signonnum", |
|
"svc_centerprint", |
|
"svc_unused27", |
|
"svc_unused28", |
|
"svc_unused29", |
|
"svc_intermission", |
|
"svc_finale", |
|
"svc_cdtrack", |
|
"svc_restore", |
|
"svc_cutscene", |
|
"svc_weaponanim", |
|
"svc_bspdecal", |
|
"svc_roomtype", |
|
"svc_addangle", |
|
"svc_usermessage", |
|
"svc_packetentities", |
|
"svc_deltapacketentities", |
|
"svc_choke", |
|
"svc_resourcelist", |
|
"svc_deltamovevars", |
|
"svc_resourcerequest", |
|
"svc_customization", |
|
"svc_crosshairangle", |
|
"svc_soundfade", |
|
"svc_filetxferfailed", |
|
"svc_hltv", |
|
"svc_director", |
|
"svc_voiceinit", |
|
"svc_voicedata", |
|
"svc_deltapacketbones", |
|
"svc_unused55", |
|
"svc_resourcelocation", |
|
"svc_querycvarvalue", |
|
"svc_querycvarvalue2", |
|
"svc_exec", |
|
}; |
|
|
|
typedef struct |
|
{ |
|
int command; |
|
int starting_offset; |
|
int frame_number; |
|
} oldcmd_t; |
|
|
|
typedef struct |
|
{ |
|
oldcmd_t oldcmd[MSG_COUNT]; |
|
int currentcmd; |
|
qboolean parsing; |
|
} msg_debug_t; |
|
|
|
static msg_debug_t cls_message_debug; |
|
|
|
const char *CL_MsgInfo( int cmd ) |
|
{ |
|
static string sz; |
|
|
|
Q_strcpy( sz, "???" ); |
|
|
|
if( cmd >= 0 && cmd <= svc_lastmsg ) |
|
{ |
|
// get engine message name |
|
Q_strncpy( sz, svc_strings[cmd], sizeof( sz )); |
|
} |
|
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES )) |
|
{ |
|
int i; |
|
|
|
for( i = 0; i < MAX_USER_MESSAGES; i++ ) |
|
{ |
|
if( clgame.msg[i].number == cmd ) |
|
{ |
|
Q_strncpy( sz, clgame.msg[i].name, sizeof( sz )); |
|
break; |
|
} |
|
} |
|
} |
|
return sz; |
|
} |
|
|
|
/* |
|
===================== |
|
CL_Parse_Debug |
|
|
|
enable message debugging |
|
===================== |
|
*/ |
|
void CL_Parse_Debug( qboolean enable ) |
|
{ |
|
cls_message_debug.parsing = enable; |
|
} |
|
|
|
/* |
|
===================== |
|
CL_Parse_RecordCommand |
|
|
|
record new message params into debug buffer |
|
===================== |
|
*/ |
|
void CL_Parse_RecordCommand( int cmd, int startoffset ) |
|
{ |
|
int slot; |
|
|
|
if( cmd == svc_nop ) return; |
|
|
|
slot = ( cls_message_debug.currentcmd++ & MSG_MASK ); |
|
cls_message_debug.oldcmd[slot].command = cmd; |
|
cls_message_debug.oldcmd[slot].starting_offset = startoffset; |
|
cls_message_debug.oldcmd[slot].frame_number = host.framecount; |
|
} |
|
|
|
/* |
|
===================== |
|
CL_ResetFrame |
|
===================== |
|
*/ |
|
void CL_ResetFrame( frame_t *frame ) |
|
{ |
|
memset( &frame->graphdata, 0, sizeof( netbandwidthgraph_t )); |
|
frame->receivedtime = host.realtime; |
|
frame->valid = true; |
|
frame->choked = false; |
|
frame->latency = 0.0; |
|
frame->time = cl.mtime[0]; |
|
} |
|
|
|
/* |
|
===================== |
|
CL_WriteErrorMessage |
|
|
|
write net_message into buffer.dat for debugging |
|
===================== |
|
*/ |
|
static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg ) |
|
{ |
|
const char *buffer_file = "buffer.dat"; |
|
file_t *fp; |
|
|
|
fp = FS_Open( buffer_file, "wb", false ); |
|
if( !fp ) return; |
|
|
|
FS_Write( fp, &cls.starting_count, sizeof( int )); |
|
FS_Write( fp, ¤t_count, sizeof( int )); |
|
FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg )); |
|
FS_Close( fp ); |
|
|
|
Con_Printf( "Wrote erroneous message to %s\n", buffer_file ); |
|
} |
|
|
|
/* |
|
===================== |
|
CL_WriteMessageHistory |
|
|
|
list last 32 messages for debugging net troubleshooting |
|
===================== |
|
*/ |
|
void CL_WriteMessageHistory( void ) |
|
{ |
|
oldcmd_t *old, *failcommand; |
|
sizebuf_t *msg = &net_message; |
|
int i, thecmd; |
|
|
|
if( !cls.initialized || cls.state == ca_disconnected ) |
|
return; |
|
|
|
if( !cls_message_debug.parsing ) |
|
return; |
|
|
|
Con_Printf( "Last %i messages parsed.\n", MSG_COUNT ); |
|
|
|
// finish here |
|
thecmd = cls_message_debug.currentcmd - 1; |
|
thecmd -= ( MSG_COUNT - 1 ); // back up to here |
|
|
|
for( i = 0; i < MSG_COUNT - 1; i++ ) |
|
{ |
|
thecmd &= MSG_MASK; |
|
old = &cls_message_debug.oldcmd[thecmd]; |
|
Con_Printf( "%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command )); |
|
thecmd++; |
|
} |
|
|
|
failcommand = &cls_message_debug.oldcmd[thecmd]; |
|
Con_Printf( "BAD: %3i:%s\n", MSG_GetNumBytesRead( msg ) - 1, CL_MsgInfo( failcommand->command )); |
|
if( host_developer.value >= DEV_EXTENDED ) |
|
CL_WriteErrorMessage( MSG_GetNumBytesRead( msg ) - 1, msg ); |
|
cls_message_debug.parsing = false; |
|
}
|
|
|