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 & DEMOMSG_CLIENT_TO_SERVER) // This is a client->server message! Ignore for now!
191 if (net_message.cursize > net_message.maxsize)
192 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
193 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
194 for (i = 0;i < 3;i++)
196 r = (int)FS_Read(cls.demofile, &f, 4);
197 cl.mviewangles[0][i] = LittleFloat(f);
200 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == net_message.cursize)
203 CL_ParseServerMessage();
205 // In case the demo contains a "svc_disconnect" message
206 if (!cls.demoplayback)
225 stop recording a demo
228 void CL_Stop_f (void)
231 unsigned char bufdata[64];
233 if (!cls.demorecording)
235 Con_Print("Not recording a demo.\n");
239 // write a disconnect message to the demo file
240 // LordHavoc: don't replace the net_message when doing this
242 buf.maxsize = sizeof(bufdata);
244 MSG_WriteByte(&buf, svc_disconnect);
245 CL_WriteDemoMessage(&buf);
248 FS_Close (cls.demofile);
250 cls.demorecording = false;
251 Con_Print("Completed demo\n");
258 record <demoname> <map> [cd track]
261 void CL_Record_f (void)
264 char name[MAX_OSPATH];
267 if (c != 2 && c != 3 && c != 4)
269 Con_Print("record <demoname> [<map> [cd track]]\n");
273 if (strstr(Cmd_Argv(1), ".."))
275 Con_Print("Relative pathnames are not allowed.\n");
279 if (c == 2 && cls.state == ca_connected)
281 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
285 if (cls.state == ca_connected)
288 // write the forced cd track number, or -1
291 track = atoi(Cmd_Argv(3));
292 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
298 strlcpy (name, Cmd_Argv(1), sizeof (name));
299 FS_DefaultExtension (name, ".dem", sizeof (name));
303 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
305 // open the demo file
306 Con_Printf("recording to %s.\n", name);
307 cls.demofile = FS_Open (name, "wb", false, false);
310 Con_Print("ERROR: couldn't open.\n");
314 cls.forcetrack = track;
315 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
317 cls.demorecording = true;
328 void CL_PlayDemo_f (void)
330 char name[MAX_QPATH];
332 qboolean neg = false;
336 Con_Print("play <demoname> : plays a demo\n");
340 // disconnect from server
342 Host_ShutdownServer ();
344 // update networking ports (this is mainly just needed at startup)
345 NetConn_UpdateSockets();
347 // open the demo file
348 strlcpy (name, Cmd_Argv(1), sizeof (name));
349 FS_DefaultExtension (name, ".dem", sizeof (name));
350 cls.protocol = PROTOCOL_QUAKE;
352 Con_Printf("Playing demo from %s.\n", name);
353 cls.demofile = FS_Open (name, "rb", false, false);
356 Con_Print("ERROR: couldn't open.\n");
357 cls.demonum = -1; // stop demo loop
361 strlcpy(cls.demoname, name, sizeof(cls.demoname));
362 cls.demoplayback = true;
363 cls.state = ca_connected;
366 while ((c = FS_Getc (cls.demofile)) != '\n')
370 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
373 cls.forcetrack = -cls.forcetrack;
382 void CL_FinishTimeDemo (void)
385 double time, totalfpsavg;
386 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
388 cls.timedemo = false;
390 frames = cls.td_frames;
391 time = realtime - cls.td_starttime;
392 totalfpsavg = time > 0 ? frames / time : 0;
393 fpsmin = cls.td_onesecondminframes;
394 fpsavg = cls.td_onesecondavgcount ? cls.td_onesecondavgframes / cls.td_onesecondavgcount : 0;
395 fpsmax = cls.td_onesecondmaxframes;
396 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
397 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);
398 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);
399 if (COM_CheckParm("-benchmark"))
410 void CL_TimeDemo_f (void)
414 Con_Print("timedemo <demoname> : gets demo speeds\n");
418 srand(0); // predictable random sequence for benchmarking
422 // cls.td_starttime will be grabbed at the second frame of the demo, so
423 // all the loading time doesn't get counted
425 // instantly hide console and deactivate it
427 key_consoleactive = 0;
431 cls.td_frames = -2; // skip the first frame
432 cls.demonum = -1; // stop demo loop
433 cls.demonum = -1; // stop demo loop