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.
25 void CL_FinishTimeDemo (void);
28 ==============================================================================
32 When a demo is playing back, all outgoing network messages are skipped, and
33 incoming messages are read from the demo file.
35 Whenever cl.time gets past the last received message, another message is
36 read from the demo file.
37 ==============================================================================
44 Called to play the next demo in the demo loop
47 void CL_NextDemo (void)
51 if (cls.demonum == -1)
52 return; // don't play demos
54 if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
57 if (!cls.demos[cls.demonum][0])
59 Con_Print("No demos listed with startdemos\n");
65 sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
66 Cbuf_InsertText (str);
74 Called when a demo file runs out, or the user starts a game
77 // LordHavoc: now called only by CL_Disconnect
78 void CL_StopPlayback (void)
80 if (!cls.demoplayback)
83 FS_Close (cls.demofile);
84 cls.demoplayback = false;
95 Dumps the current net message, prefixed by the length and view angles
98 void CL_WriteDemoMessage (void)
104 if (cls.demopaused) // LordHavoc: pausedemo
107 len = LittleLong (net_message.cursize);
108 FS_Write (cls.demofile, &len, 4);
109 for (i=0 ; i<3 ; i++)
111 f = LittleFloat (cl.viewangles[i]);
112 FS_Write (cls.demofile, &f, 4);
114 FS_Write (cls.demofile, net_message.data, net_message.cursize);
115 FS_Flush (cls.demofile);
122 Handles playback of demos
125 void CL_ReadDemoMessage(void)
130 if (!cls.demoplayback)
133 // LordHavoc: pausedemo
139 // decide if it is time to grab the next message
140 // always grab until fully connected
141 if (cls.signon == SIGNONS)
145 if (host_framecount == cls.td_lastframe)
147 // already read this frame's message
150 if (cls.td_lastframe == -1)
152 // we start counting on the second frame
153 // (after parsing connection stuff)
154 cls.td_startframe = host_framecount + 1;
156 cls.td_lastframe = host_framecount;
157 // if this is the first official frame we can now grab the real
158 // td_starttime so the bogus time on the first frame doesn't
159 // count against the final report
160 if (host_framecount == cls.td_startframe)
161 cls.td_starttime = realtime;
162 if (host_framecount > cls.td_startframe + 2)
164 cls.td_minframetime = min(cls.td_minframetime, host_realframetime);
165 cls.td_maxframetime = max(cls.td_maxframetime, host_realframetime);
168 cls.td_minframetime = cls.td_maxframetime = host_realframetime;
170 else if (cl.time <= cl.mtime[0])
172 // don't need another message yet
177 // get the next message
178 FS_Read(cls.demofile, &net_message.cursize, 4);
179 net_message.cursize = LittleLong(net_message.cursize);
180 if (net_message.cursize > net_message.maxsize)
181 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
182 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
183 for (i = 0;i < 3;i++)
185 r = FS_Read(cls.demofile, &f, 4);
186 cl.mviewangles[0][i] = LittleFloat(f);
189 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == (size_t)net_message.cursize)
192 CL_ParseServerMessage();
194 // In case the demo contains a "svc_disconnect" message
195 if (!cls.demoplayback)
211 stop recording a demo
214 void CL_Stop_f (void)
216 if (cmd_source != src_command)
219 if (!cls.demorecording)
221 Con_Print("Not recording a demo.\n");
225 // write a disconnect message to the demo file
226 SZ_Clear (&net_message);
227 MSG_WriteByte (&net_message, svc_disconnect);
228 CL_WriteDemoMessage ();
231 FS_Close (cls.demofile);
233 cls.demorecording = false;
234 Con_Print("Completed demo\n");
241 record <demoname> <map> [cd track]
244 void CL_Record_f (void)
247 char name[MAX_OSPATH];
249 if (cmd_source != src_command)
253 if (c != 2 && c != 3 && c != 4)
255 Con_Print("record <demoname> [<map> [cd track]]\n");
259 if (strstr(Cmd_Argv(1), ".."))
261 Con_Print("Relative pathnames are not allowed.\n");
265 if (c == 2 && cls.state == ca_connected)
267 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
271 // write the forced cd track number, or -1
274 track = atoi(Cmd_Argv(3));
275 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
281 strlcpy (name, Cmd_Argv(1), sizeof (name));
282 FS_DefaultExtension (name, ".dem", sizeof (name));
286 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
288 // open the demo file
289 Con_Printf("recording to %s.\n", name);
290 cls.demofile = FS_Open (name, "wb", false);
293 Con_Print("ERROR: couldn't open.\n");
297 cls.forcetrack = track;
298 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
300 cls.demorecording = true;
311 void CL_PlayDemo_f (void)
315 qboolean neg = false;
317 if (cmd_source != src_command)
322 Con_Print("play <demoname> : plays a demo\n");
326 // disconnect from server
328 Host_ShutdownServer (false);
330 // update networking ports (this is mainly just needed at startup)
331 NetConn_ClientFrame();
333 // open the demo file
334 strlcpy (name, Cmd_Argv(1), sizeof (name));
335 FS_DefaultExtension (name, ".dem", sizeof (name));
337 Con_Printf("Playing demo from %s.\n", name);
338 cls.demofile = FS_Open (name, "rb", false);
341 Con_Print("ERROR: couldn't open.\n");
342 cls.demonum = -1; // stop demo loop
346 SCR_BeginLoadingPlaque ();
348 strlcpy(cls.demoname, name, sizeof(cls.demoname));
349 cls.demoplayback = true;
350 cls.state = ca_connected;
353 while ((c = FS_Getc (cls.demofile)) != '\n')
357 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
360 cls.forcetrack = -cls.forcetrack;
369 void CL_FinishTimeDemo (void)
372 double time; // LordHavoc: changed timedemo accuracy to double
373 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
375 cls.timedemo = false;
377 // the first frame didn't count
378 frames = (host_framecount - cls.td_startframe) - 1;
379 time = realtime - cls.td_starttime;
380 fpsmin = cls.td_maxframetime > 0 ? 1.0 / cls.td_maxframetime : 0;
381 fpsavg = time > 0 ? frames / time : 0;
382 fpsmax = cls.td_minframetime > 0 ? 1.0 / cls.td_minframetime : 0;
383 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
384 Con_Printf("%i frames %5.7f seconds %5.7f fps\nmin/avg/max: %5.7f/%5.7f/%5.7f\n", frames, time, fpsavg, fpsmin, fpsavg, fpsmax);
385 Log_Printf("benchmark.log", "date %s | enginedate %s | demo %s | commandline %s | result %i frames %5.7f seconds %5.7f fps min/avg/max: %5.7f/%5.7f/%5.7f\n", Sys_TimeString("%Y-%m-%d %H:%M:%S"), buildstring, cls.demoname, cmdline.string, frames, time, fpsavg, fpsmin, fpsavg, fpsmax);
386 if (COM_CheckParm("-benchmark"))
397 void CL_TimeDemo_f (void)
399 if (cmd_source != src_command)
404 Con_Print("timedemo <demoname> : gets demo speeds\n");
410 // cls.td_starttime will be grabbed at the second frame of the demo, so
411 // all the loading time doesn't get counted
413 // instantly hide console and deactivate it
415 key_consoleactive = 0;
420 // get first message this frame
421 cls.td_lastframe = -1;