added NDP server pause tracking and improved command sequence handling

This commit is contained in:
myT 2023-08-08 02:05:42 +02:00
parent db25062b05
commit 23ce3e0982
3 changed files with 34 additions and 9 deletions

View file

@ -1031,11 +1031,11 @@ qbool CL_CGNDP_IsConfigStringNeeded( int csIndex )
} }
void CL_CGNDP_AnalyzeSnapshot( int progress ) qbool CL_CGNDP_AnalyzeSnapshot( int progress )
{ {
Q_assert(cls.cgameNewDemoPlayer); Q_assert(cls.cgameNewDemoPlayer);
Q_assert(progress >= 0 && progress < 100); Q_assert(progress >= 0 && progress < 100);
VM_Call(cgvm, cls.cgvmCalls[CGVM_NDP_ANALYZE_SNAPSHOT], progress); return (qbool)VM_Call(cgvm, cls.cgvmCalls[CGVM_NDP_ANALYZE_SNAPSHOT], progress);
} }

View file

@ -104,7 +104,7 @@ There's no need to make the player more complex for such an edge case.
#define FULL_SNAPSHOT_INTERVAL_MS (8 * 1000) #define FULL_SNAPSHOT_INTERVAL_MS (8 * 1000)
#define MAX_COMMANDS ARRAY_LEN(demo.commands) #define MAX_COMMANDS 256
#define VERBOSE_DEBUGGING 0 #define VERBOSE_DEBUGGING 0
@ -155,6 +155,7 @@ struct ndpSnapshot_t {
int snapFlags; int snapFlags;
int ping; int ping;
qbool isFullSnap; qbool isFullSnap;
qbool isServerPaused;
}; };
struct parser_t { struct parser_t {
@ -198,7 +199,7 @@ struct command_t {
struct demo_t { struct demo_t {
ndpSnapshot_t snapshots[2]; // current one and next one for CGame requests ndpSnapshot_t snapshots[2]; // current one and next one for CGame requests
demoIndex_t indices[4096]; demoIndex_t indices[4096];
command_t commands[256]; command_t commands[MAX_COMMANDS];
memoryBuffer_t buffer; memoryBuffer_t buffer;
ndpSnapshot_t* currSnap; ndpSnapshot_t* currSnap;
ndpSnapshot_t* nextSnap; ndpSnapshot_t* nextSnap;
@ -213,6 +214,9 @@ struct demo_t {
struct newDemoPlayer_t { struct newDemoPlayer_t {
jmp_buf abortLoad; jmp_buf abortLoad;
qbool trackServerPause;
qbool isServerPaused;
int serverPauseDelay; // total duration in server pause since the full snapshot
}; };
@ -307,13 +311,14 @@ static void MB_Seek( memoryBuffer_t* mb, int position )
} }
static void WriteNDPSnapshot( msg_t* outMsg, const ndpSnapshot_t* prevSnap, ndpSnapshot_t* currSnap ) static void WriteNDPSnapshot( msg_t* outMsg, const ndpSnapshot_t* prevSnap, ndpSnapshot_t* currSnap, qbool isServerPaused )
{ {
const qbool isFullSnap = prevSnap == NULL; const qbool isFullSnap = prevSnap == NULL;
// header // header
MSG_WriteBits(outMsg, isFullSnap, 1); MSG_WriteBits(outMsg, isFullSnap, 1);
MSG_WriteLong(outMsg, currSnap->serverTime); MSG_WriteLong(outMsg, currSnap->serverTime);
MSG_WriteBits(outMsg, !!isServerPaused, 1);
// player state // player state
const playerState_t* const oldPS = !prevSnap ? &nullPlayerState : &prevSnap->ps; const playerState_t* const oldPS = !prevSnap ? &nullPlayerState : &prevSnap->ps;
@ -660,7 +665,7 @@ static void ParseSnapshot()
// let CGame analyze the snapshot so it can do cool stuff // let CGame analyze the snapshot so it can do cool stuff
// e.g. store events of interest for the timeline overlay // e.g. store events of interest for the timeline overlay
demo.currSnap = currNDPSnap; demo.currSnap = currNDPSnap;
CL_CGNDP_AnalyzeSnapshot(parser.progress); const qbool isServerPaused = CL_CGNDP_AnalyzeSnapshot(parser.progress);
// draw the current progress once in a while... // draw the current progress once in a while...
static int lastRefreshTime = Sys_Milliseconds(); static int lastRefreshTime = Sys_Milliseconds();
@ -676,7 +681,7 @@ static void ParseSnapshot()
MSG_Clear(&writeMsg); MSG_Clear(&writeMsg);
MSG_Bitstream(&writeMsg); MSG_Bitstream(&writeMsg);
ndpSnapshot_t* const prevNDPSnap = parser.prevSnap; ndpSnapshot_t* const prevNDPSnap = parser.prevSnap;
WriteNDPSnapshot(&writeMsg, isFullSnap ? NULL : prevNDPSnap, currNDPSnap); WriteNDPSnapshot(&writeMsg, isFullSnap ? NULL : prevNDPSnap, currNDPSnap, isServerPaused);
MB_Write(&demo.buffer, &writeMsg.cursize, 4); MB_Write(&demo.buffer, &writeMsg.cursize, 4);
MB_Write(&demo.buffer, writeMsg.data, writeMsg.cursize); MB_Write(&demo.buffer, writeMsg.data, writeMsg.cursize);
@ -835,6 +840,7 @@ static void ReadNextSnapshot()
} }
currSnap->isFullSnap = isFullSnap; currSnap->isFullSnap = isFullSnap;
currSnap->serverTime = MSG_ReadLong(&inMsg); currSnap->serverTime = MSG_ReadLong(&inMsg);
currSnap->isServerPaused = MSG_ReadBits(&inMsg, 1);
// player state // player state
MSG_ReadDeltaPlayerstate(&inMsg, prevSnap ? &prevSnap->ps : &nullPlayerState, &currSnap->ps); MSG_ReadDeltaPlayerstate(&inMsg, prevSnap ? &prevSnap->ps : &nullPlayerState, &currSnap->ps);
@ -925,6 +931,14 @@ static void ReadNextSnapshot()
} }
} }
if (ndp.trackServerPause) {
if (currSnap->isServerPaused && ndp.isServerPaused && prevSnap != NULL) {
const int delta = currSnap->serverTime - prevSnap->serverTime;
ndp.serverPauseDelay += delta;
}
ndp.isServerPaused = currSnap->isServerPaused;
}
demo.snapshotIndex++; demo.snapshotIndex++;
} }
@ -1056,7 +1070,9 @@ after_parse:
CL_CGNDP_EndAnalysis(clc.demoName, demo.firstServerTime, demo.lastServerTime, videoRestart); CL_CGNDP_EndAnalysis(clc.demoName, demo.firstServerTime, demo.lastServerTime, videoRestart);
// make sure we don't execute commands from the end of the demo when starting up // make sure we don't execute commands from the end of the demo when starting up
demo.numCommands = 0; demo.commands[0].command[0] = '\0';
demo.commands[1].command[0] = '\0';
demo.numCommands = 1;
const int duration = Sys_Milliseconds() - startTime; const int duration = Sys_Milliseconds() - startTime;
Com_Printf("New Demo Player: loaded demo in %d.%03d seconds\n", duration / 1000, duration % 1000); Com_Printf("New Demo Player: loaded demo in %d.%03d seconds\n", duration / 1000, duration % 1000);
@ -1200,6 +1216,10 @@ int CL_NDP_Seek( int serverTime )
demo.commands[i].command[0] = '\0'; demo.commands[i].command[0] = '\0';
} }
ndp.trackServerPause = qtrue;
ndp.isServerPaused = qfalse;
ndp.serverPauseDelay = 0;
SeekToIndex(index); SeekToIndex(index);
// read more snapshots until we're close to the target time for more precise jumps // read more snapshots until we're close to the target time for more precise jumps
@ -1218,6 +1238,11 @@ int CL_NDP_Seek( int serverTime )
numSnapshotsRead++; numSnapshotsRead++;
} }
if (ndp.serverPauseDelay > 0) {
AddCommand(va("server_pause_delay %d", ndp.serverPauseDelay));
}
ndp.trackServerPause = qfalse;
Com_DPrintf("New Demo Player: sought and read %d snaps in %d ms\n", Com_DPrintf("New Demo Player: sought and read %d snaps in %d ms\n",
numSnapshotsRead, Sys_Milliseconds() - seekStartTime); numSnapshotsRead, Sys_Milliseconds() - seekStartTime);

View file

@ -522,7 +522,7 @@ void CL_CGameRendering( stereoFrame_t stereo );
void CL_SetCGameTime(); void CL_SetCGameTime();
void CL_ConfigstringModified(); void CL_ConfigstringModified();
void CL_CGNDP_EndAnalysis( const char* filePath, int firstServerTime, int lastServerTime, qbool videoRestart ); void CL_CGNDP_EndAnalysis( const char* filePath, int firstServerTime, int lastServerTime, qbool videoRestart );
void CL_CGNDP_AnalyzeSnapshot( int progress ); qbool CL_CGNDP_AnalyzeSnapshot( int progress ); // qtrue when a server pause is active
void CL_CGNDP_AnalyzeCommand( int serverTime ); void CL_CGNDP_AnalyzeCommand( int serverTime );
void CL_CGNDP_GenerateCommands( const char** commands, int* numCommandBytes ); void CL_CGNDP_GenerateCommands( const char** commands, int* numCommandBytes );
qbool CL_CGNDP_IsConfigStringNeeded( int csIndex ); qbool CL_CGNDP_IsConfigStringNeeded( int csIndex );