added a new demo player with fast seeking support

added cl_demoPlayer and cl_escapeAbortsDemo
This commit is contained in:
myT 2022-11-04 05:00:39 +01:00
parent 9f90a6ee8b
commit f401f742ee
24 changed files with 1530 additions and 54 deletions

View File

@ -4,6 +4,13 @@ See the end of this file for known issues.
DD Mmm 20 - 1.53
add: cl_demoPlayer <0|1> (default: 1) selects the demo playback system to use
cl_demoPlayer 0 = always uses the original demo player
cl_demoPlayer 1 = uses the new demo player with time rewind support when the mod supports it
add: cl_escapeAbortsDemo <0|1> (default: 1) decides whether the escape key can abort demo playback
reminder: you can always use /disconnect to stop demo playback
add: r_depthClamp <0|1> (default: 0) disables vertex clipping against the near and far clip planes
enabling this feature will raise the maximum allowed FoV value of CPMA 1.53
it turns the view frustum into a pyramid and prevents any vertex between the near clip plane

View File

@ -648,7 +648,7 @@ static qbool CloseAVI( closeMode_t closeMode )
Z_Free( afd.eBuffer );
FS_FCloseFile( afd.f );
Com_Printf( "Wrote %d:%d frames to %s\n", afd.numVideoFrames, afd.numAudioFrames, afd.fileName );
Com_Printf( "Wrote %d:%d V:A frames to %s\n", afd.numVideoFrames, afd.numAudioFrames, afd.fileName );
if ( closeMode == CM_SEQUENCE_COMPLETE )
S_StopAllSounds();

View File

@ -94,6 +94,11 @@ static int CL_GetCurrentCmdNumber()
static void CL_GetCurrentSnapshotNumber( int* snapshotNumber, int* serverTime )
{
if ( clc.newDemoPlayer ) {
CL_NDP_GetCurrentSnapshotNumber( snapshotNumber, serverTime );
return;
}
*snapshotNumber = cl.snap.messageNum;
*serverTime = cl.snap.serverTime;
}
@ -101,6 +106,10 @@ static void CL_GetCurrentSnapshotNumber( int* snapshotNumber, int* serverTime )
static qbool CL_GetSnapshot( int snapshotNumber, snapshot_t* snapshot )
{
if ( clc.newDemoPlayer ) {
return CL_NDP_GetSnapshot( snapshotNumber, snapshot );
}
int i, count;
if ( snapshotNumber > cl.snap.messageNum ) {
@ -154,7 +163,7 @@ static void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale )
}
static void CL_ConfigstringModified()
void CL_ConfigstringModified()
{
int index = atoi( Cmd_Argv(1) );
if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
@ -209,6 +218,10 @@ static void CL_ConfigstringModified()
static qbool CL_GetServerCommand( int serverCommandNumber )
{
if ( clc.newDemoPlayer ) {
return CL_NDP_GetServerCommand( serverCommandNumber );
}
static char bigConfigString[BIG_INFO_STRING];
// if we have irretrievably lost a reliable command, drop the connection
@ -306,6 +319,7 @@ static void CL_CM_LoadMap( const char* mapname )
void CL_ShutdownCGame()
{
Com_Memset( cls.cgvmCalls, 0, sizeof(cls.cgvmCalls) );
cls.keyCatchers &= ~KEYCATCH_CGAME;
cls.cgameStarted = qfalse;
cls.cgameForwardInput = 0;
@ -336,6 +350,12 @@ static qbool CL_CG_GetValue( char* value, int valueSize, const char* key )
{ "trap_MatchAlertEvent", CG_EXT_MATCHALERTEVENT },
{ "trap_Error2", CG_EXT_ERROR2 },
{ "trap_IsRecordingDemo", CG_EXT_ISRECORDINGDEMO },
{ "trap_CNQ3_NDP_Enable", CG_EXT_NDP_ENABLE },
{ "trap_CNQ3_NDP_Seek", CG_EXT_NDP_SEEK },
{ "trap_CNQ3_NDP_ReadUntil", CG_EXT_NDP_READUNTIL },
{ "trap_CNQ3_NDP_StartVideo", CG_EXT_NDP_STARTVIDEO },
{ "trap_CNQ3_NDP_StopVideo", CG_EXT_NDP_STOPVIDEO },
{ "trap_CNQ3_R_RenderScene", CG_EXT_R_RENDERSCENE },
// commands
{ "screenshotnc", 1 },
{ "screenshotncJPEG", 1 },
@ -514,7 +534,7 @@ static intptr_t CL_CgameSystemCalls( intptr_t *args )
re.AddLightToScene( VMA(1), VMF(2), VMF(3), VMF(4), VMF(5) );
return 0;
case CG_R_RENDERSCENE:
re.RenderScene( VMA(1) );
re.RenderScene( VMA(1), 0 );
return 0;
case CG_R_SETCOLOR:
re.SetColor( VMA(1) );
@ -656,6 +676,38 @@ static intptr_t CL_CgameSystemCalls( intptr_t *args )
case CG_EXT_ISRECORDINGDEMO:
return clc.demorecording;
case CG_EXT_NDP_ENABLE:
if( clc.demoplaying && cl_demoPlayer->integer ) {
cls.cgameNewDemoPlayer = qtrue;
cls.cgvmCalls[CGVM_NDP_ANALYZE_COMMAND] = args[1];
cls.cgvmCalls[CGVM_NDP_GENERATE_COMMANDS] = args[2];
cls.cgvmCalls[CGVM_NDP_IS_CS_NEEDED] = args[3];
cls.cgvmCalls[CGVM_NDP_ANALYZE_SNAPSHOT] = args[4];
cls.cgvmCalls[CGVM_NDP_END_ANALYSIS] = args[5];
return qtrue;
} else {
return qfalse;
}
case CG_EXT_NDP_SEEK:
return CL_NDP_Seek( args[1] );
case CG_EXT_NDP_READUNTIL:
CL_NDP_ReadUntil( args[1] );
return 0;
case CG_EXT_NDP_STARTVIDEO:
Cvar_Set( cl_aviFrameRate->name, va( "%d", (int)args[2] ) );
return CL_OpenAVIForWriting( va( "videos/%s", (const char*)VMA(1) ), qfalse );
case CG_EXT_NDP_STOPVIDEO:
CL_CloseAVI();
return 0;
case CG_EXT_R_RENDERSCENE:
re.RenderScene( VMA(1), args[2] );
return 0;
default:
Com_Error( ERR_DROP, "Bad cgame system trap: %i", args[0] );
}
@ -691,6 +743,7 @@ void CL_InitCGame()
int t = Sys_Milliseconds();
cls.cgameForwardInput = 0;
cls.cgameNewDemoPlayer = qfalse;
// put away the console
Con_Close();
@ -846,6 +899,11 @@ static void CL_FirstSnapshot()
void CL_SetCGameTime()
{
if ( clc.newDemoPlayer ) {
CL_NDP_SetCGameTime();
return;
}
// getting a valid frame message ends the connection process
if ( cls.state != CA_ACTIVE ) {
if ( cls.state != CA_PRIMED ) {
@ -946,3 +1004,45 @@ void CL_SetCGameTime()
}
void CL_CGNDP_AnalyzeCommand( int serverTime )
{
Q_assert(cls.cgameNewDemoPlayer);
VM_Call(cgvm, cls.cgvmCalls[CGVM_NDP_ANALYZE_COMMAND], serverTime);
}
void CL_CGNDP_GenerateCommands( const char** commands, int* numCommandBytes )
{
Q_assert(cls.cgameNewDemoPlayer);
Q_assert(commands);
Q_assert(numCommandBytes);
VM_Call(cgvm, cls.cgvmCalls[CGVM_NDP_GENERATE_COMMANDS]);
*numCommandBytes = *(int*)interopBufferIn;
*commands = (const char*)interopBufferIn + 4;
}
qbool CL_CGNDP_IsConfigStringNeeded( int csIndex )
{
Q_assert(cls.cgameNewDemoPlayer);
Q_assert(csIndex >= 0 && csIndex < MAX_CONFIGSTRINGS);
return (qbool)VM_Call(cgvm, cls.cgvmCalls[CGVM_NDP_IS_CS_NEEDED], csIndex);
}
void CL_CGNDP_AnalyzeSnapshot( int progress )
{
Q_assert(cls.cgameNewDemoPlayer);
Q_assert(progress >= 0 && progress < 100);
VM_Call(cgvm, cls.cgvmCalls[CGVM_NDP_ANALYZE_SNAPSHOT], progress);
}
void CL_CGNDP_EndAnalysis( const char* filePath, int firstServerTime, int lastServerTime, qbool videoRestart )
{
Q_assert(cls.cgameNewDemoPlayer);
Q_assert(lastServerTime > firstServerTime);
Q_strncpyz((char*)interopBufferOut, filePath, interopBufferOutSize);
VM_Call(cgvm, cls.cgvmCalls[CGVM_NDP_END_ANALYSIS], firstServerTime, lastServerTime, videoRestart);
}

1232
code/client/cl_demo.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1118,7 +1118,7 @@ void CL_KeyEvent( int key, qbool down, unsigned time )
if ( cls.state == CA_ACTIVE && !clc.demoplaying ) {
VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME );
}
else {
else if ( !clc.demoplaying || cl_escapeAbortsDemo->integer ) {
CL_Disconnect_f();
S_StopAllSounds();
VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );

View File

@ -46,6 +46,9 @@ cvar_t *cl_allowDownload;
cvar_t *cl_inGameVideo;
cvar_t *cl_matchAlerts;
cvar_t *cl_demoPlayer;
cvar_t *cl_escapeAbortsDemo;
cvar_t *net_proxy;
cvar_t *r_khr_debug;
@ -89,7 +92,9 @@ not have future usercmd_t executed before it is executed
======================
*/
void CL_AddReliableCommand( const char *cmd ) {
int index;
if ( clc.demoplaying ) {
return;
}
// if we would be losing an old command that hasn't been acknowledged,
// we must drop the connection
@ -97,7 +102,7 @@ void CL_AddReliableCommand( const char *cmd ) {
Com_Error( ERR_DROP, "Client command overflow" );
}
clc.reliableSequence++;
index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
const int index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
Q_strncpyz( clc.reliableCommands[ index ], cmd, sizeof( clc.reliableCommands[ index ] ) );
}
@ -364,7 +369,7 @@ static void CL_WalkDemoExt( const char* path, fileHandle_t* fh )
}
void CL_PlayDemo_f()
static void CL_PlayDemo( qbool videoRestart )
{
if (Cmd_Argc() != 2) {
Com_Printf( "demo <demoname>\n" );
@ -395,6 +400,14 @@ void CL_PlayDemo_f()
clc.demoplaying = qtrue;
Q_strncpyz( cls.servername, shortPath, sizeof( cls.servername ) );
if ( cl_demoPlayer->integer ) {
while ( CL_MapDownload_Active() ) {
Sys_Sleep( 50 );
}
CL_NDP_PlayDemo( videoRestart );
return;
}
// read demo messages until connected
while ( cls.state >= CA_CONNECTED && cls.state < CA_PRIMED && !CL_MapDownload_Active() ) {
CL_ReadDemoMessage();
@ -730,6 +743,7 @@ void CL_Disconnect( qbool showMainMenu ) {
FS_FCloseFile( clc.demofile );
clc.demofile = 0;
}
clc.demoplaying = qfalse;
if ( uivm && showMainMenu ) {
VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NONE );
@ -1874,8 +1888,14 @@ static void CL_Vid_Restart_f()
// startup all the client stuff
CL_StartHunkUsers();
// we don't really technically need to run everything again,
// but trying to optimize parts out is very likely to lead to nasty bugs
if ( clc.demoplaying && clc.newDemoPlayer ) {
Cmd_TokenizeString( va("demo %s", clc.demoName) );
CL_PlayDemo( qtrue );
}
// start the cgame if connected
if ( cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) {
else if ( cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) {
cls.cgameStarted = qtrue;
CL_InitCGame();
// send pure checksums
@ -1903,30 +1923,42 @@ static void CL_Video_f()
{
char s[ MAX_OSPATH ];
if( !clc.demoplaying )
if( !clc.demoplaying || clc.newDemoPlayer )
{
Com_Printf( "ERROR: ^7/video is only enabled during demo playback\n" );
Com_Printf( "^3ERROR: ^7/%s is only enabled in the old demo player\n", Cmd_Argv( 0 ) );
return;
}
if( Cmd_Argc( ) == 2 )
{
Com_sprintf( s, MAX_OSPATH, "videos/%s", Cmd_Argv( 1 ) );
Q_strncpyz( s, Cmd_Argv( 1 ), sizeof( s ) );
}
else
{
qtime_t t;
Com_RealTime( &t );
Com_sprintf( s, sizeof(s), "videos/%d_%02d_%02d-%02d_%02d_%02d",
Com_sprintf( s, sizeof( s ), "%d_%02d_%02d-%02d_%02d_%02d",
1900+t.tm_year, 1+t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec );
}
CL_OpenAVIForWriting( s, qfalse );
CL_OpenAVIForWriting( va( "videos/%s", s ), qfalse );
}
static void CL_StopVideo_f()
{
if( !clc.demoplaying || clc.newDemoPlayer )
{
Com_Printf( "^3ERROR: ^7/%s is only enabled in the old demo player\n", Cmd_Argv( 0 ) );
return;
}
if( !CL_VideoRecording() )
{
Com_Printf( "No video is being recorded\n" );
return;
}
CL_CloseAVI();
}
@ -2083,6 +2115,12 @@ static void CL_CancelDownload_f()
}
static void CL_PlayDemo_f()
{
CL_PlayDemo( qfalse );
}
static const cvarTableItem_t cl_cvars[] =
{
{ &cl_timeout, "cl_timeout", "200", 0, CVART_INTEGER, "30", "300", "connection time-out, in seconds" },
@ -2107,7 +2145,9 @@ static const cvarTableItem_t cl_cvars[] =
{ NULL, "password", "", CVAR_USERINFO, CVART_STRING, NULL, NULL, "used by /" S_COLOR_CMD "connect" },
{ &cl_matchAlerts, "cl_matchAlerts", "7", CVAR_ARCHIVE, CVART_BITMASK, "0", XSTRING(MAF_MAX), help_cl_matchAlerts },
{ &net_proxy, "net_proxy", "", CVAR_TEMP, CVART_STRING, NULL, NULL, help_net_proxy },
{ &r_khr_debug, "r_khr_debug", "2", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_r_khr_debug }
{ &r_khr_debug, "r_khr_debug", "2", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_r_khr_debug },
{ &cl_demoPlayer, "cl_demoPlayer", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_cl_demoPlayer },
{ &cl_escapeAbortsDemo, "cl_escapeAbortsDemo", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "pressing escape aborts demo playback" },
};

View File

@ -894,7 +894,7 @@ static intptr_t CL_UISystemCalls( intptr_t* args )
return 0;
case UI_R_RENDERSCENE:
re.RenderScene( VMA(1) );
re.RenderScene( VMA(1), 0 );
return 0;
case UI_R_SETCOLOR:
@ -1144,7 +1144,7 @@ static intptr_t CL_UISystemCalls( intptr_t* args )
return 0;
case UI_EXT_ENABLEERRORCALLBACK:
cls.uiErrorCallbackVMCall = (int)args[1];
cls.uivmCalls[UIVM_ERROR_CALLBACK] = (int)args[1];
return 0;
default:
@ -1157,7 +1157,7 @@ static intptr_t CL_UISystemCalls( intptr_t* args )
void CL_ShutdownUI()
{
cls.uiErrorCallbackVMCall = 0;
Com_Memset( cls.uivmCalls, 0, sizeof(cls.uivmCalls) );
cls.keyCatchers &= ~KEYCATCH_UI;
cls.uiStarted = qfalse;
if ( !uivm )
@ -1187,18 +1187,17 @@ void CL_InitUI()
}
// init for this gamestate
cls.uiErrorCallbackVMCall = 0;
VM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE) );
}
void CL_ForwardUIError( int level, int module, const char* error )
{
if ( uivm == NULL || cls.uiErrorCallbackVMCall == 0 )
if ( uivm == NULL || cls.uivmCalls[UIVM_ERROR_CALLBACK] == 0 )
return;
Q_strncpyz( (char*)interopBufferOut, error, interopBufferOutSize );
VM_Call( uivm, cls.uiErrorCallbackVMCall, level, module );
VM_Call( uivm, cls.uivmCalls[UIVM_ERROR_CALLBACK], level, module );
}

View File

@ -173,7 +173,7 @@ typedef struct {
int serverMessageSequence;
// reliable messages received from server
int serverCommandSequence;
int serverCommandSequence; // the number of the latest available command
int lastExecutedServerCommand; // last server command grabbed or executed with CL_GetServerCommand
char serverCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
qbool serverCommandsBad[MAX_RELIABLE_COMMANDS]; // non-zero means the command shouldn't be fed to cgame
@ -196,6 +196,7 @@ typedef struct {
qbool demoplaying;
qbool demowaiting; // don't record until a non-delta message is received
qbool firstDemoFrameSkipped;
qbool newDemoPlayer; // running the new player with rewind support
fileHandle_t demofile;
int timeDemoFrames; // counter of rendered frames
@ -245,6 +246,22 @@ typedef struct {
unsigned short port;
} serverAddress_t;
// CGame VM calls that are extensions
enum {
CGVM_NDP_END_ANALYSIS,
CGVM_NDP_ANALYZE_SNAPSHOT,
CGVM_NDP_ANALYZE_COMMAND,
CGVM_NDP_GENERATE_COMMANDS, // generate synchronization commands
CGVM_NDP_IS_CS_NEEDED, // does this config string need to be re-submitted?
CGVM_COUNT
};
// UI VM calls that are extensions
enum {
UIVM_ERROR_CALLBACK, // forward errors to UI?
UIVM_COUNT
};
typedef struct {
connstate_t state; // connection status
int keyCatchers; // bit flags
@ -261,12 +278,17 @@ typedef struct {
qbool uiStarted;
qbool cgameStarted;
// extensions VM calls indices
// 0 when not available
int cgvmCalls[CGVM_COUNT];
int uivmCalls[UIVM_COUNT];
// extension: new demo player supported by the mod
qbool cgameNewDemoPlayer;
// extension: forward input to cgame regardless of keycatcher state?
int cgameForwardInput; // 1=mouse, 2=keys (note: we don't forward the escape key)
// extension: forward errors to ui?
int uiErrorCallbackVMCall; // 0 when not available
int framecount;
int frametime; // msec since last frame
@ -354,6 +376,8 @@ extern cvar_t *cl_allowDownload; // 0=off, 1=CNQ3, -1=id
extern cvar_t *cl_inGameVideo;
extern cvar_t *cl_matchAlerts; // bit mask, see the MAF_* constants
extern cvar_t *cl_demoPlayer;
extern cvar_t *cl_escapeAbortsDemo;
extern cvar_t *r_khr_debug;
@ -496,6 +520,12 @@ void CL_InitCGame();
void CL_ShutdownCGame();
void CL_CGameRendering( stereoFrame_t stereo );
void CL_SetCGameTime();
void CL_ConfigstringModified();
void CL_CGNDP_EndAnalysis( const char* filePath, int firstServerTime, int lastServerTime, qbool videoRestart );
void CL_CGNDP_AnalyzeSnapshot( int progress );
void CL_CGNDP_AnalyzeCommand( int serverTime );
void CL_CGNDP_GenerateCommands( const char** commands, int* numCommandBytes );
qbool CL_CGNDP_IsConfigStringNeeded( int csIndex );
//
// cl_ui.c
@ -546,6 +576,18 @@ void CL_MapDownload_CrashCleanUp();
qbool CL_GL_WantDebug(); // do we want a debug context from the platform layer?
void CL_GL_Init(); // enables debug output if needed
//
// cl_demo.cpp
//
void CL_NDP_PlayDemo( qbool videoRestart );
void CL_NDP_SetCGameTime();
void CL_NDP_GetCurrentSnapshotNumber( int* snapshotNumber, int* serverTime );
qbool CL_NDP_GetSnapshot( int snapshotNumber, snapshot_t* snapshot );
qbool CL_NDP_GetServerCommand( int serverCommandNumber );
int CL_NDP_Seek( int serverTime );
void CL_NDP_ReadUntil( int serverTime );
void CL_NDP_HandleError();
//
// OS-specific
//

View File

@ -146,3 +146,8 @@ S_COLOR_VAL " 2 " S_COLOR_HELP "= On in debug builds only"
"Example: init lines starting with 'init'\n" \
"Example: *init lines containing 'init'\n" \
"Example: >*net lines starting with '>' AND containing 'net'"
#define help_cl_demoPlayer \
"1 enables demo rewind\n" \
S_COLOR_VAL " 0 " S_COLOR_HELP "= Uses the original demo player\n" \
S_COLOR_VAL " 1 " S_COLOR_HELP "= Uses the new demo player when the mod supports it"

View File

@ -233,6 +233,13 @@ static sfxHandle_t S_Base_RegisterSound( const char* name )
return 0;
}
if ( name[0] == '\0' ) {
if ( !cls.cgameNewDemoPlayer ) {
Com_Printf( "Sound name is empty\n" );
}
return 0;
}
if ( strlen( name ) >= MAX_QPATH ) {
Com_Printf( "Sound name exceeds MAX_QPATH\n" );
return 0;

View File

@ -196,7 +196,13 @@ typedef enum {
CG_EXT_CMD_SETHELP,
CG_EXT_MATCHALERTEVENT,
CG_EXT_ERROR2,
CG_EXT_ISRECORDINGDEMO
CG_EXT_ISRECORDINGDEMO,
CG_EXT_NDP_ENABLE,
CG_EXT_NDP_SEEK,
CG_EXT_NDP_READUNTIL,
CG_EXT_NDP_STARTVIDEO,
CG_EXT_NDP_STOPVIDEO,
CG_EXT_R_RENDERSCENE
} cgameImport_t;
@ -427,6 +433,7 @@ typedef enum {
CG_MOUSE_EVENT,
// void (*CG_MouseEvent)( int dx, int dy );
CG_EVENT_HANDLING
// void (*CG_EventHandling)(int type);
} cgameExport_t;

View File

@ -250,6 +250,14 @@ void QDECL Com_ErrorExt( int code, int module, qbool realError, const char *fmt,
static int lastErrorTime;
static int errorCount;
if ( code == ERR_DROP_NDP ) {
#if !defined(DEDICATED)
void CL_NDP_HandleError();
CL_NDP_HandleError();
#endif
code = ERR_DROP;
}
// make sure we can get at our local stuff
FS_PureServerSetLoadedPaks( "" );
@ -3593,3 +3601,19 @@ static const char* Com_GetCompilerInfo()
return "Unknown compiler";
#endif
}
const char* Com_FormatBytes( int numBytes )
{
const char* units[] = { "bytes", "KB", "MB", "GB" };
const float dividers[] = { 1.0f, float(1 << 10), float(1 << 20), float(1 << 30) };
int unit = 0;
for ( int vi = numBytes; vi >= 1024; vi >>= 10 ) {
unit++;
}
const float vf = (float)numBytes / dividers[unit];
return va( "%.3f %s", vf, units[unit] );
}

View File

@ -1294,6 +1294,16 @@ int FS_Seek( fileHandle_t f, long offset, int origin )
}
qbool FS_IsZipFile( fileHandle_t f )
{
if ( f < 0 || f >= MAX_FILE_HANDLES ) {
Com_Error( ERR_DROP, "FS_IsZipFile: out of range" );
}
return fsh[f].zipFile;
}
/*
======================================================================================

View File

@ -180,7 +180,7 @@ int MSG_ReadBits( msg_t *msg, int bits ) {
msg->readcount += 4;
msg->bit += 32;
} else {
Com_Error(ERR_DROP, "can't read %d bits\n", bits);
Com_Error(ERR_DROP_NDP, "can't read %d bits\n", bits);
}
} else {
nbits = 0;
@ -741,7 +741,7 @@ void MSG_ReadDeltaEntity( msg_t* msg, const entityState_t* from, entityState_t*
int startBit, endBit;
if ( number < 0 || number >= MAX_GENTITIES ) {
Com_Error( ERR_DROP, "Bad delta entity number: %i", number );
Com_Error( ERR_DROP_NDP, "Bad delta entity number: %i", number );
}
if ( msg->bit == 0 ) {
@ -771,7 +771,7 @@ void MSG_ReadDeltaEntity( msg_t* msg, const entityState_t* from, entityState_t*
lc = MSG_ReadByte(msg);
if ( lc < 0 || lc > ARRAY_LEN(entityStateFields) ) {
Com_Error( ERR_DROP, "invalid entityState_t field count %d (max: %d)\n", lc, ARRAY_LEN(entityStateFields) );
Com_Error( ERR_DROP_NDP, "invalid entityState_t field count %d (max: %d)\n", lc, ARRAY_LEN(entityStateFields) );
}
// shownet 2/3 will interleave with other printed info, -1 will
@ -1095,7 +1095,7 @@ void MSG_ReadDeltaPlayerstate( msg_t* msg, const playerState_t* from, playerStat
lc = MSG_ReadByte(msg);
if ( lc < 0 || lc > ARRAY_LEN(playerStateFields) ) {
Com_Error( ERR_DROP, "invalid playerState_t field count %d (max: %d)\n", lc, ARRAY_LEN(playerStateFields) );
Com_Error( ERR_DROP_NDP, "invalid playerState_t field count %d (max: %d)\n", lc, ARRAY_LEN(playerStateFields) );
}
const netField_t* field;

View File

@ -672,9 +672,9 @@ FIXME: make this buffer size safe someday
*/
const char* QDECL va( const char* format, ... )
{
static char string[2][32000]; // in case va is called by nested functions
static char string[4][32000]; // in case va is called by nested functions
static int index = 0;
char* buf = string[index++ & 1];
char* buf = string[index++ & 3];
va_list argptr;
va_start( argptr, format );

View File

@ -215,6 +215,7 @@ typedef int clipHandle_t;
typedef enum {
ERR_FATAL, // exit the entire game with a popup window
ERR_DROP, // print to console and disconnect from game
ERR_DROP_NDP, // same but the NDP can run its own handler when active
ERR_SERVERDISCONNECT, // don't kill server
ERR_DISCONNECT, // client disconnected from the server
ERR_NEED_CD // pop up the need-cd dialog

View File

@ -710,6 +710,9 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode );
int FS_Seek( fileHandle_t f, long offset, int origin );
// seek on a file (doesn't work for zip files!!!!!!!!)
qbool FS_IsZipFile( fileHandle_t f );
// tells us whether we opened a zip file
qbool FS_FilenameCompare( const char *s1, const char *s2 );
const char *FS_LoadedPakChecksums( void );
@ -851,6 +854,7 @@ int Com_Filter( const char* filter, const char* name );
int Com_FilterPath( const char* filter, const char* name );
int Com_RealTime(qtime_t *qtime);
qbool Com_SafeMode();
const char *Com_FormatBytes( int numBytes );
void Com_StartupVariable( const char *match );
// checks for and removes command line "+set var arg" constructs

View File

@ -623,24 +623,11 @@ struct srfTriangles_t {
// trRefdef_t holds everything that comes in refdef_t,
// as well as the locally generated scene information
typedef struct {
int x, y, width, height;
float fov_x, fov_y;
vec3_t vieworg;
vec3_t viewaxis[3]; // transformation matrix
int time; // time in milliseconds for shader effects and other time dependent rendering issues
int rdflags; // RDF_NOWORLDMODEL, etc
// 1 bits will prevent the associated area from rendering at all
byte areamask[MAX_MAP_AREA_BYTES];
struct trRefdef_t : public refdef_t {
qbool areamaskModified; // qtrue if areamask changed since last scene
int microSeconds; // [0;999] micro-seconds to add to the timestamp
double floatTime; // tr.refdef.time / 1000.0
// text messages for deform text shaders
char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
int num_entities;
trRefEntity_t *entities;
@ -655,8 +642,7 @@ typedef struct {
int numLitSurfs;
litSurf_t* litSurfs;
} trRefdef_t;
};
/*
@ -1399,7 +1385,7 @@ void RE_ClearScene();
void RE_AddRefEntityToScene( const refEntity_t *ent, qbool intShaderTime );
void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
void RE_AddLightToScene( const vec3_t org, float radius, float r, float g, float b );
void RE_RenderScene( const refdef_t *fd );
void RE_RenderScene( const refdef_t *fd, int us );
/*

View File

@ -131,7 +131,7 @@ typedef struct {
void (*AddPolyToScene)( qhandle_t hShader, int numVerts, const polyVert_t *verts, int num );
qbool (*LightForPoint)( const vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
void (*AddLightToScene)( const vec3_t org, float radius, float r, float g, float b );
void (*RenderScene)( const refdef_t *fd );
void (*RenderScene)( const refdef_t *fd, int us );
void (*SetColor)( const float* rgba ); // NULL = 1,1,1,1
void (*DrawStretchPic)( float x, float y, float w, float h,

View File

@ -197,7 +197,7 @@ void RE_AddLightToScene( const vec3_t org, float radius, float r, float g, float
// draw a 3D view into a part of the window, then return to 2D drawing
// rendering a scene may require multiple views to be rendered to handle mirrors
void RE_RenderScene( const refdef_t* fd )
void RE_RenderScene( const refdef_t* fd, int us )
{
if ( !tr.registered ) {
return;
@ -228,6 +228,7 @@ void RE_RenderScene( const refdef_t* fd )
VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
tr.refdef.time = fd->time;
tr.refdef.microSeconds = us;
tr.refdef.rdflags = fd->rdflags;
// copy the areamask data over and note if it has changed, which
@ -248,7 +249,9 @@ void RE_RenderScene( const refdef_t* fd )
// derived info
tr.refdef.floatTime = (double)tr.refdef.time / 1000.0;
tr.refdef.floatTime =
(double)tr.refdef.time / 1000.0 +
(double)tr.refdef.microSeconds / 1000000.0;
tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
tr.refdef.drawSurfs = backEndData->drawSurfs;

View File

@ -78,6 +78,7 @@ OBJECTS := \
$(OBJDIR)/cl_cgame.o \
$(OBJDIR)/cl_cin.o \
$(OBJDIR)/cl_console.o \
$(OBJDIR)/cl_demo.o \
$(OBJDIR)/cl_download.o \
$(OBJDIR)/cl_gl.o \
$(OBJDIR)/cl_input.o \
@ -205,6 +206,9 @@ $(OBJDIR)/cl_cin.o: ../../code/client/cl_cin.cpp
$(OBJDIR)/cl_console.o: ../../code/client/cl_console.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/cl_demo.o: ../../code/client/cl_demo.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/cl_download.o: ../../code/client/cl_download.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"

View File

@ -369,6 +369,7 @@ local function ApplyExeProjectSettings(exeName, server)
"client/cl_cgame.cpp",
"client/cl_cin.cpp",
"client/cl_console.cpp",
"client/cl_demo.cpp",
"client/cl_download.cpp",
"client/cl_gl.cpp",
"client/cl_input.cpp",

View File

@ -314,6 +314,7 @@ copy "..\..\.bin\release_x32\cnq3-x86.pdb" "$(QUAKE3DIR)"</Command>
<ClCompile Include="..\..\code\client\cl_cgame.cpp" />
<ClCompile Include="..\..\code\client\cl_cin.cpp" />
<ClCompile Include="..\..\code\client\cl_console.cpp" />
<ClCompile Include="..\..\code\client\cl_demo.cpp" />
<ClCompile Include="..\..\code\client\cl_download.cpp" />
<ClCompile Include="..\..\code\client\cl_gl.cpp" />
<ClCompile Include="..\..\code\client\cl_input.cpp" />

View File

@ -248,6 +248,9 @@
<ClCompile Include="..\..\code\client\cl_console.cpp">
<Filter>client</Filter>
</ClCompile>
<ClCompile Include="..\..\code\client\cl_demo.cpp">
<Filter>client</Filter>
</ClCompile>
<ClCompile Include="..\..\code\client\cl_download.cpp">
<Filter>client</Filter>
</ClCompile>