void SVCL_Record_f( void ) { char *s; client_t *cl; s = 0; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() < 2 || Cmd_Argc() > 3) { Com_Printf ("record <clientnumber> [<demoname>]\n"); return; } cl = SV_GetPlayerByNum(); if ( !cl ) { // error message was printed by SV_GetPlayerByNum return; } if ( Cmd_Argc() == 3 ) { s = Cmd_Argv(2); // Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", s, PROTOCOL_VERSION ); CL_Record(cl,s); } else { CL_Record(cl,0); } }
void CL_Record_f(void) { char name[MAX_OSPATH]; char *s; if (Cmd_Argc() > 2) { Com_FuncPrinf("record <demoname>\n"); return; } if (clc.demorecording) { Com_FuncPrinf("Already recording.\n"); return; } if (cls.state != CA_ACTIVE) { Com_FuncPrinf("You must be in a level to record.\n"); return; } if (Cmd_Argc() == 2) { s = Cmd_Argv(1); Q_strncpyz(demoName, s, sizeof(demoName)); Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, PROTOCOL_VERSION); } else { int number, len; // scan for a free demo name for (number = 0; number <= 9999; number++) { CL_DemoFilename(number, demoName); Com_sprintf(name, sizeof(name), "demos/%s.%s%d", demoName, DEMOEXT, PROTOCOL_VERSION); len = FS_ReadFile(name, NULL); if (len <= 0) { break; // file doesn't exist } } } CL_Record(name); }
/* ==================== CL_Record_f record <demoname> ==================== */ void CL_Record_f (void) { int c; char name[MAX_OSPATH]; c = Cmd_Argc(); if (c != 2) { Com_Printf ("record <demoname>\n"); return; } if (cls.state != ca_active && cls.state != ca_disconnected) { Com_Printf ("Cannot record while connecting.\n"); return; } if (cls.demorecording) CL_Stop_f(); Q_snprintfz (name, sizeof(name), "%s/%s", cls.gamedir, Cmd_Argv(1)); // // open the demo file // COM_ForceExtension (name, ".qwd"); cls.demofile = fopen (name, "wb"); if (!cls.demofile) { Com_Printf ("ERROR: couldn't open.\n"); return; } Com_Printf ("recording to %s.\n", name); if (cls.state == ca_active) CL_Record (); else cls.demorecording = true; }
/* ================ CL_ParseSnapshot If the snapshot is parsed properly, it will be copied to cl.snap and saved in cl.snapshots[]. If the snapshot is invalid for any reason, no changes to the state will be made at all. ================ */ void CL_ParseSnapshot( msg_t *msg ) { int len; clSnapshot_t *old; clSnapshot_t newSnap; int deltaNum; int oldMessageNum; int i, packetNum; // get the reliable sequence acknowledge number // NOTE: now sent with all server to client messages //clc.reliableAcknowledge = MSG_ReadLong( msg ); // read in the new snapshot to a temporary buffer // we will only copy to cl.snap if it is valid Com_Memset( &newSnap, 0, sizeof( newSnap ) ); // we will have read any new server commands in this // message before we got to svc_snapshot newSnap.serverCommandNum = clc.serverCommandSequence; newSnap.serverTime = MSG_ReadLong( msg ); // if we were just unpaused, we can only *now* really let the // change come into effect or the client hangs. cl_paused->modified = 0; newSnap.messageNum = clc.serverMessageSequence; deltaNum = MSG_ReadByte( msg ); if ( !deltaNum ) { newSnap.deltaNum = -1; } else { newSnap.deltaNum = newSnap.messageNum - deltaNum; } newSnap.snapFlags = MSG_ReadByte( msg ); // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of // the frame, but not use it, then ask for a non-compressed // message if ( newSnap.deltaNum <= 0 ) { newSnap.valid = qtrue; // uncompressed frame old = NULL; if ( clc.demorecording ) { clc.demowaiting = qfalse; // we can start recording now // if(cl_autorecord->integer) { // Cvar_Set( "g_synchronousClients", "0" ); // } } else { if ( cl_autorecord->integer /*&& Cvar_VariableValue( "g_synchronousClients") */ ) { char name[ 256 ]; char mapname[ MAX_QPATH ]; char *period; qtime_t time; Com_RealTime( &time ); Q_strncpyz( mapname, cl.mapname, MAX_QPATH ); for ( period = mapname; *period; period++ ) { if ( *period == '.' ) { *period = '\0'; break; } } for ( period = mapname; *period; period++ ) { if ( *period == '/' ) { break; } } if ( *period ) { period++; } Com_sprintf( name, sizeof( name ), "demos/%s_%04i-%02i-%02i_%02i%02i%02i.dm_%d", period, 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, PROTOCOL_VERSION ); CL_Record( name ); } } } else { old = &cl.snapshots[ newSnap.deltaNum & PACKET_MASK ]; if ( !old->valid ) { // should never happen Com_Printf( "Delta from invalid frame (not supposed to happen!).\n" ); } else if ( old->messageNum != newSnap.deltaNum ) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. Com_DPrintf( "Delta frame too old.\n" ); } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - 128 ) { Com_DPrintf( "Delta parseEntitiesNum too old.\n" ); } else { newSnap.valid = qtrue; // valid delta parse } } // read areamask len = MSG_ReadByte( msg ); if ( len > sizeof( newSnap.areamask ) ) { Com_Error( ERR_DROP, "CL_ParseSnapshot: Invalid size %d for areamask.", len ); } MSG_ReadData( msg, &newSnap.areamask, len ); // read playerinfo SHOWNET( msg, "playerstate" ); if ( old ) { MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps ); } else { MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps ); } // read packet entities SHOWNET( msg, "packet entities" ); CL_ParsePacketEntities( msg, old, &newSnap ); // if not valid, dump the entire thing now that it has // been properly read if ( !newSnap.valid ) { return; } // clear the valid flags of any snapshots between the last // received and this one, so if there was a dropped packet // it won't look like something valid to delta from next // time we wrap around in the buffer oldMessageNum = cl.snap.messageNum + 1; if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) { oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 ); } for ( ; oldMessageNum < newSnap.messageNum; oldMessageNum++ ) { cl.snapshots[ oldMessageNum & PACKET_MASK ].valid = qfalse; } // copy to the current good spot cl.snap = newSnap; cl.snap.ping = 999; // calculate ping time for ( i = 0; i < PACKET_BACKUP; i++ ) { packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK; if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) { cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime; break; } } // save the frame off in the backup array for later delta comparisons cl.snapshots[ cl.snap.messageNum & PACKET_MASK ] = cl.snap; if ( cl_shownet->integer == 3 ) { Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum, cl.snap.deltaNum, cl.snap.ping ); } cl.newSnapshots = qtrue; }
/* ==================== CL_EasyRecord_f easyrecord [demoname] ==================== */ void CL_EasyRecord_f (void) { int c; char name[1024]; char name2[MAX_OSPATH*2]; int i; char *p; FILE *f; c = Cmd_Argc(); if (c > 2) { Com_Printf ("easyrecord <demoname>\n"); return; } if (cls.state != ca_active) { Com_Printf ("You must be connected to record.\n"); return; } if (cls.demorecording) CL_Stop_f(); /// FIXME: check buffer sizes!!! if (c == 2) Q_snprintfz (name, sizeof(name), "%s", Cmd_Argv(1)); else if (cl.spectator) { // FIXME: if tracking a player, use his name Q_snprintfz (name, sizeof(name), "spec_%s_%s", TP_PlayerName(), TP_MapName()); } else { // guess game type and write demo name i = TP_CountPlayers(); if (cl.teamplay && i >= 3) { // Teamplay Q_snprintfz (name, sizeof(name), "%s_%s_vs_%s_%s", TP_PlayerName(), TP_PlayerTeam(), TP_EnemyTeam(), TP_MapName()); } else { if (i == 2) { // Duel Q_snprintfz (name, sizeof(name), "%s_vs_%s_%s", TP_PlayerName(), TP_EnemyName(), TP_MapName()); } else if (i > 2) { // FFA Q_snprintfz (name, sizeof(name), "%s_ffa_%s", TP_PlayerName(), TP_MapName()); } else { // one player Q_snprintfz (name, sizeof(name), "%s_%s", TP_PlayerName(), TP_MapName()); } } } // Make sure the filename doesn't contain illegal characters for (p = name; *p; p++) { char c; *p &= 0x7F; // strip high bit c = *p; if (c <= ' ' || c == '?' || c == '*' || c == '\\' || c == '/' || c == ':' || c == '<' || c == '>' || c == '"') *p = '_'; } strlcpy (name, va("%s/%s", cls.gamedir, name), MAX_OSPATH); // find a filename that doesn't exist yet strcpy (name2, name); COM_ForceExtension (name2, ".qwd"); f = fopen (name2, "rb"); if (f) { i = 0; do { fclose (f); strcpy (name2, va("%s_%02i", name, i)); COM_ForceExtension (name2, ".qwd"); f = fopen (name2, "rb"); i++; } while (f); } // // open the demo file // cls.demofile = fopen (name2, "wb"); if (!cls.demofile) { Com_Printf ("ERROR: couldn't open.\n"); return; } Com_Printf ("recording to %s.\n", name2); CL_Record (); }