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 // skip over demo packet
192 FS_Seek(cls.demofile, 12 + (net_message.cursize & (~DEMOMSG_CLIENT_TO_SERVER)), SEEK_CUR);
195 if (net_message.cursize > net_message.maxsize)
196 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
197 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
198 for (i = 0;i < 3;i++)
200 r = (int)FS_Read(cls.demofile, &f, 4);
201 cl.mviewangles[0][i] = LittleFloat(f);
204 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == net_message.cursize)
207 CL_ParseServerMessage();
209 // In case the demo contains a "svc_disconnect" message
210 if (!cls.demoplayback)
229 stop recording a demo
232 void CL_Stop_f (void)
235 unsigned char bufdata[64];
237 if (!cls.demorecording)
239 Con_Print("Not recording a demo.\n");
243 // write a disconnect message to the demo file
244 // LordHavoc: don't replace the net_message when doing this
246 buf.maxsize = sizeof(bufdata);
248 MSG_WriteByte(&buf, svc_disconnect);
249 CL_WriteDemoMessage(&buf);
252 FS_Close (cls.demofile);
254 cls.demorecording = false;
255 Con_Print("Completed demo\n");
262 record <demoname> <map> [cd track]
265 void CL_Record_f (void)
268 char name[MAX_OSPATH];
271 if (c != 2 && c != 3 && c != 4)
273 Con_Print("record <demoname> [<map> [cd track]]\n");
277 if (strstr(Cmd_Argv(1), ".."))
279 Con_Print("Relative pathnames are not allowed.\n");
283 if (c == 2 && cls.state == ca_connected)
285 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
289 if (cls.state == ca_connected)
292 // write the forced cd track number, or -1
295 track = atoi(Cmd_Argv(3));
296 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
302 strlcpy (name, Cmd_Argv(1), sizeof (name));
303 FS_DefaultExtension (name, ".dem", sizeof (name));
307 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
309 // open the demo file
310 Con_Printf("recording to %s.\n", name);
311 cls.demofile = FS_Open (name, "wb", false, false);
314 Con_Print("ERROR: couldn't open.\n");
318 cls.forcetrack = track;
319 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
321 cls.demorecording = true;
332 void CL_PlayDemo_f (void)
334 char name[MAX_QPATH];
336 qboolean neg = false;
340 Con_Print("play <demoname> : plays a demo\n");
344 // disconnect from server
346 Host_ShutdownServer ();
348 // update networking ports (this is mainly just needed at startup)
349 NetConn_UpdateSockets();
351 // open the demo file
352 strlcpy (name, Cmd_Argv(1), sizeof (name));
353 FS_DefaultExtension (name, ".dem", sizeof (name));
354 cls.protocol = PROTOCOL_QUAKE;
356 Con_Printf("Playing demo %s.\n", name);
357 cls.demofile = FS_Open (name, "rb", false, false);
360 Con_Print("ERROR: couldn't open.\n");
361 cls.demonum = -1; // stop demo loop
365 strlcpy(cls.demoname, name, sizeof(cls.demoname));
366 cls.demoplayback = true;
367 cls.state = ca_connected;
370 while ((c = FS_Getc (cls.demofile)) != '\n')
374 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
377 cls.forcetrack = -cls.forcetrack;
386 void CL_FinishTimeDemo (void)
389 double time, totalfpsavg;
390 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
392 cls.timedemo = false;
394 frames = cls.td_frames;
395 time = realtime - cls.td_starttime;
396 totalfpsavg = time > 0 ? frames / time : 0;
397 fpsmin = cls.td_onesecondminframes;
398 fpsavg = cls.td_onesecondavgcount ? cls.td_onesecondavgframes / cls.td_onesecondavgcount : 0;
399 fpsmax = cls.td_onesecondmaxframes;
400 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
401 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);
402 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);
403 if (COM_CheckParm("-benchmark"))
414 void CL_TimeDemo_f (void)
418 Con_Print("timedemo <demoname> : gets demo speeds\n");
422 srand(0); // predictable random sequence for benchmarking
426 // cls.td_starttime will be grabbed at the second frame of the demo, so
427 // all the loading time doesn't get counted
429 // instantly hide console and deactivate it
431 key_consoleactive = 0;
435 cls.td_frames = -2; // skip the first frame
436 cls.demonum = -1; // stop demo loop
437 cls.demonum = -1; // stop demo loop