2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 extern cvar_t cl_capturevideo;
26 void CL_FinishTimeDemo (void);
29 ==============================================================================
33 When a demo is playing back, all outgoing network messages are skipped, and
34 incoming messages are read from the demo file.
36 Whenever cl.time gets past the last received message, another message is
37 read from the demo file.
38 ==============================================================================
45 Called to play the next demo in the demo loop
48 void CL_NextDemo (void)
50 char str[MAX_INPUTLINE];
52 if (cls.demonum == -1)
53 return; // don't play demos
55 if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
58 if (!cls.demos[cls.demonum][0])
60 Con_Print("No demos listed with startdemos\n");
66 sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
67 Cbuf_InsertText (str);
75 Called when a demo file runs out, or the user starts a game
78 // LordHavoc: now called only by CL_Disconnect
79 void CL_StopPlayback (void)
81 if (!cls.demoplayback)
84 FS_Close (cls.demofile);
85 cls.demoplayback = false;
91 if (COM_CheckParm("-demo") || COM_CheckParm("-capturedemo"))
100 Dumps the current net message, prefixed by the length and view angles
103 void CL_WriteDemoMessage (sizebuf_t *message)
109 if (cls.demopaused) // LordHavoc: pausedemo
112 len = LittleLong (message->cursize);
113 FS_Write (cls.demofile, &len, 4);
114 for (i=0 ; i<3 ; i++)
116 f = LittleFloat (cl.viewangles[i]);
117 FS_Write (cls.demofile, &f, 4);
119 FS_Write (cls.demofile, message->data, message->cursize);
126 Handles playback of demos
129 void CL_ReadDemoMessage(void)
134 if (!cls.demoplayback)
137 // LordHavoc: pausedemo
143 // decide if it is time to grab the next message
144 // always grab until fully connected
145 if (cls.signon == SIGNONS)
150 cls.td_onesecondframes++;
151 // if this is the first official frame we can now grab the real
152 // td_starttime so the bogus time on the first frame doesn't
153 // count against the final report
154 if (cls.td_frames == 0)
156 cls.td_starttime = realtime;
157 cls.td_onesecondnexttime = cl.time + 1;
158 cls.td_onesecondframes = 0;
159 cls.td_onesecondminframes = 0;
160 cls.td_onesecondmaxframes = 0;
161 cls.td_onesecondavgframes = 0;
162 cls.td_onesecondavgcount = 0;
164 if (cl.time >= cls.td_onesecondnexttime)
166 if (cls.td_onesecondavgcount == 0)
168 cls.td_onesecondminframes = cls.td_onesecondframes;
169 cls.td_onesecondmaxframes = cls.td_onesecondframes;
171 cls.td_onesecondminframes = min(cls.td_onesecondminframes, cls.td_onesecondframes);
172 cls.td_onesecondmaxframes = max(cls.td_onesecondmaxframes, cls.td_onesecondframes);
173 cls.td_onesecondavgframes += cls.td_onesecondframes;
174 cls.td_onesecondavgcount++;
175 cls.td_onesecondframes = 0;
176 cls.td_onesecondnexttime++;
179 else if (cl.time <= cl.mtime[0])
181 // don't need another message yet
186 // get the next message
187 FS_Read(cls.demofile, &net_message.cursize, 4);
188 net_message.cursize = LittleLong(net_message.cursize);
189 if (net_message.cursize > net_message.maxsize)
190 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
191 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
192 for (i = 0;i < 3;i++)
194 r = (int)FS_Read(cls.demofile, &f, 4);
195 cl.mviewangles[0][i] = LittleFloat(f);
198 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == net_message.cursize)
201 CL_ParseServerMessage();
203 // In case the demo contains a "svc_disconnect" message
204 if (!cls.demoplayback)
223 stop recording a demo
226 void CL_Stop_f (void)
229 unsigned char bufdata[64];
231 if (!cls.demorecording)
233 Con_Print("Not recording a demo.\n");
237 // write a disconnect message to the demo file
238 // LordHavoc: don't replace the net_message when doing this
240 buf.maxsize = sizeof(bufdata);
242 MSG_WriteByte(&buf, svc_disconnect);
243 CL_WriteDemoMessage(&buf);
246 FS_Close (cls.demofile);
248 cls.demorecording = false;
249 Con_Print("Completed demo\n");
256 record <demoname> <map> [cd track]
259 void CL_Record_f (void)
262 char name[MAX_OSPATH];
265 if (c != 2 && c != 3 && c != 4)
267 Con_Print("record <demoname> [<map> [cd track]]\n");
271 if (strstr(Cmd_Argv(1), ".."))
273 Con_Print("Relative pathnames are not allowed.\n");
277 if (c == 2 && cls.state == ca_connected)
279 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
283 if (cls.state == ca_connected)
286 // write the forced cd track number, or -1
289 track = atoi(Cmd_Argv(3));
290 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
296 strlcpy (name, Cmd_Argv(1), sizeof (name));
297 FS_DefaultExtension (name, ".dem", sizeof (name));
301 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
303 // open the demo file
304 Con_Printf("recording to %s.\n", name);
305 cls.demofile = FS_Open (name, "wb", false, false);
308 Con_Print("ERROR: couldn't open.\n");
312 cls.forcetrack = track;
313 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
315 cls.demorecording = true;
326 void CL_PlayDemo_f (void)
328 char name[MAX_QPATH];
330 qboolean neg = false;
334 Con_Print("play <demoname> : plays a demo\n");
338 // disconnect from server
340 Host_ShutdownServer ();
342 // update networking ports (this is mainly just needed at startup)
343 NetConn_UpdateSockets();
345 // open the demo file
346 strlcpy (name, Cmd_Argv(1), sizeof (name));
347 FS_DefaultExtension (name, ".dem", sizeof (name));
348 cls.protocol = PROTOCOL_QUAKE;
350 Con_Printf("Playing demo from %s.\n", name);
351 cls.demofile = FS_Open (name, "rb", false, false);
354 Con_Print("ERROR: couldn't open.\n");
355 cls.demonum = -1; // stop demo loop
359 strlcpy(cls.demoname, name, sizeof(cls.demoname));
360 cls.demoplayback = true;
361 cls.state = ca_connected;
364 while ((c = FS_Getc (cls.demofile)) != '\n')
368 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
371 cls.forcetrack = -cls.forcetrack;
380 void CL_FinishTimeDemo (void)
383 double time, totalfpsavg;
384 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
386 cls.timedemo = false;
388 frames = cls.td_frames;
389 time = realtime - cls.td_starttime;
390 totalfpsavg = time > 0 ? frames / time : 0;
391 fpsmin = cls.td_onesecondminframes;
392 fpsavg = cls.td_onesecondavgcount ? cls.td_onesecondavgframes / cls.td_onesecondavgcount : 0;
393 fpsmax = cls.td_onesecondmaxframes;
394 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
395 Con_Printf("%i frames %5.7f seconds %5.7f fps, one-second min/avg/max: %.0f %.0f %.0f\n", frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax);
396 Log_Printf("benchmark.log", "date %s | enginedate %s | demo %s | commandline %s | result %i frames %5.7f seconds %5.7f fps, one-second min/avg/max: %.0f %.0f %.0f\n", Sys_TimeString("%Y-%m-%d %H:%M:%S"), buildstring, cls.demoname, cmdline.string, frames, time, totalfpsavg, fpsmin, fpsavg, fpsmax);
397 if (COM_CheckParm("-benchmark"))
408 void CL_TimeDemo_f (void)
412 Con_Print("timedemo <demoname> : gets demo speeds\n");
416 srand(0); // predictable random sequence for benchmarking
420 // cls.td_starttime will be grabbed at the second frame of the demo, so
421 // all the loading time doesn't get counted
423 // instantly hide console and deactivate it
425 key_consoleactive = 0;
429 cls.td_frames = -2; // skip the first frame
430 cls.demonum = -1; // stop demo loop
431 cls.demonum = -1; // stop demo loop