Merge branch 'fix-demo-ghost-buffer-overrun' into 'master'

Large replay crash mitigation, replay buffer size option, debug command

Closes #656

See merge request KartKrew/Kart!1885
This commit is contained in:
Oni 2024-02-01 03:00:26 +00:00
commit 8aeeae24c3
8 changed files with 71 additions and 9 deletions

View file

@ -538,6 +538,7 @@ consvar_t cv_maxping = Server("maxdelay", "20").values(CV_Unsigned);
consvar_t cv_menujam = Server("menujam", "menu").values({{0, "menu"}, {1, "menu2"}, {2, "menu3"}});
consvar_t cv_menujam_update = Server("menujam_update", "Off").on_off();
consvar_t cv_netdemosyncquality = Server("netdemo_syncquality", "1").min_max(1, 35);
consvar_t cv_netdemosize = Server("netdemo_size", "6").values(CV_Natural);
void NetTimeout_OnChange(void);
consvar_t cv_nettimeout = Server("nettimeout", "210").min_max(TICRATE/7, 60*TICRATE).onchange(NetTimeout_OnChange);

View file

@ -548,6 +548,7 @@ typedef enum
DBG_SETUP = 0x00000400,
DBG_LUA = 0x00000800,
DBG_RNG = 0x00001000,
DBG_DEMO = 0x00002000,
} debugFlags_t;
struct debugFlagNames_s

View file

@ -734,6 +734,7 @@ void G_GhostAddHit(INT32 playernum, mobj_t *victim)
void G_WriteAllGhostTics(void)
{
boolean toobig = false;
INT32 i, counter = leveltime;
for (i = 0; i < MAXPLAYERS; i++)
{
@ -750,12 +751,18 @@ void G_WriteAllGhostTics(void)
WRITEUINT8(demobuf.p, i);
G_WriteGhostTic(players[i].mo, i);
// attention here for the ticcmd size!
// latest demos with mouse aiming byte in ticcmd
if (demobuf.p >= demobuf.end - (13 + 9 + 9))
{
toobig = true;
break;
}
}
WRITEUINT8(demobuf.p, 0xFF);
// attention here for the ticcmd size!
// latest demos with mouse aiming byte in ticcmd
if (demobuf.p >= demobuf.end - (13 + 9 + 9))
if (toobig)
{
G_CheckDemoStatus(); // no more space
return;
@ -2088,16 +2095,13 @@ void G_WriteMetalTic(mobj_t *metal)
//
void G_RecordDemo(const char *name)
{
extern consvar_t cv_netdemosize;
INT32 maxsize;
strcpy(demoname, name);
strcat(demoname, ".lmp");
//@TODO make a maxdemosize cvar
// NOPE. We are kicking this can HELLA down the road. -Tyron 2024-01-20
maxsize = 1024*1024*4;
if (M_CheckParm("-maxdemo") && M_IsNextParm())
maxsize = atoi(M_GetNextParm()) * 1024;
maxsize = 1024 * 1024 * cv_netdemosize.value;
// if (demobuf.buffer)
// Z_Free(demobuf.buffer);
@ -2109,6 +2113,21 @@ void G_RecordDemo(const char *name)
demobuf.p = NULL;
demo.recording = true;
demo.buffer = &demobuf;
/* FIXME: This whole file is in a wretched state. Take a
look at G_WriteAllGhostTics and G_WriteDemoTiccmd, they
write a lot of data. It's not realistic to refactor that
code in order to know exactly HOW MANY bytes it can write
out. So here's the deal. Reserve a decent block of memory
at the end of the buffer and never use it. Those bastard
functions will check if they overran the buffer, but it
should be safe enough because they'll think there's less
memory than there actually is and stop early. */
const size_t deadspace = 1024;
I_Assert(demobuf.size > deadspace);
demobuf.size -= deadspace;
demobuf.end -= deadspace;
}
void G_RecordMetal(void)
@ -3246,6 +3265,7 @@ void G_DoPlayDemo(const char *defdemoname)
// read demo header
gameaction = ga_nothing;
demo.playback = true;
demo.buffer = &demobuf;
if (memcmp(demobuf.p, DEMOHEADER, 12))
{
snprintf(msg, 1024, M_GetText("%s is not a Ring Racers replay file.\n"), pdemoname);

View file

@ -65,6 +65,8 @@ struct demovars_s {
UINT8 numskins;
democharlist_t *skinlist;
UINT8 currentskinid[MAXPLAYERS];
const savebuffer_t *buffer; // debug, valid only if recording or playback
};
extern struct demovars_s demo;

View file

@ -342,6 +342,7 @@ typedef enum
dopt_replay,
dopt_rprecord,
dopt_rpsync,
dopt_rpsize,
#ifdef HAVE_DISCORDRPC
dopt_discord,
dopt_drp,

View file

@ -605,6 +605,8 @@ struct debugFlagNames_s const debug_flag_names[] =
{"Music", DBG_MUSIC},
{"PwrLv", DBG_PWRLV},
{"PowerLevel", DBG_PWRLV}, // alt name
{"Demo", DBG_DEMO},
{"Replay", DBG_DEMO}, // alt name
{NULL, 0}
};

View file

@ -4,6 +4,8 @@
#include "../k_menu.h"
#include "../discord.h" // discord rpc cvars
extern consvar_t cv_netdemosize;
// data options menu -- see dopt_e
menuitem_t OPTIONS_Data[] =
{
@ -26,6 +28,9 @@ menuitem_t OPTIONS_Data[] =
{IT_STRING | IT_CVAR, "Net Consistency Quality", "For filesize, how often do we write position data in online replays?",
NULL, {.cvar = &cv_netdemosyncquality}, 0, 0},
{IT_STRING | IT_CVAR, "Buffer Size (MB)", "Lets replays last longer with more players. Uses more RAM.",
NULL, {.cvar = &cv_netdemosize}, 0, 0},
#ifdef HAVE_DISCORDRPC
{IT_HEADER, "Discord Rich Presence...", NULL,
NULL, {NULL}, 0, 0},

View file

@ -448,6 +448,31 @@ static void ST_drawRenderDebug(INT32 *height)
ST_pushDebugString(height, va("Skybox Portals: %4s", sizeu1(i->skybox_portals)));
}
static void ST_drawDemoDebug(INT32 *height)
{
if (!demo.recording && !demo.playback)
return;
size_t needle = demo.buffer->p - demo.buffer->buffer;
size_t size = demo.buffer->size;
double percent = (double)needle / size * 100.0;
double avg = (double)needle / leveltime;
ST_pushDebugString(height, va("%s/%s bytes", sizeu1(needle), sizeu2(size)));
ST_pushDebugString(height, va(
"%.2f/%.2f MB %5.2f%%",
needle / (1024.0 * 1024.0),
size / (1024.0 * 1024.0),
percent
));
ST_pushDebugString(height, va(
"%.2f KB/s (ETA %.2f minutes)",
avg * TICRATE / 1024.0,
(size - needle) / (avg * TICRATE * 60.0)
));
ST_pushDebugString(height, va("Demo (%s)", demo.recording ? "recording" : "playback"));
}
void ST_drawDebugInfo(void)
{
INT32 height = 192;
@ -547,6 +572,11 @@ void ST_drawDebugInfo(void)
ST_drawRenderDebug(&height);
}
if (cht_debug & DBG_DEMO)
{
ST_drawDemoDebug(&height);
}
if (cht_debug & DBG_MEMORY)
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10)));
}