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 void CL_FinishTimeDemo (void);
26 ==============================================================================
30 When a demo is playing back, all outgoing network messages are skipped, and
31 incoming messages are read from the demo file.
33 Whenever cl.time gets past the last received message, another message is
34 read from the demo file.
35 ==============================================================================
42 Called to play the next demo in the demo loop
45 extern void Call_MR_ToggleMenu_f (void);
46 void CL_NextDemo (void)
50 if (cls.demonum == -1)
51 return; // don't play demos
53 if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
56 if (!cls.demos[cls.demonum][0])
58 Con_Print("No demos listed with startdemos\n");
60 // put up menu instead of staring at console
61 if (key_dest != key_menu)
62 Call_MR_ToggleMenu_f();
67 sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
68 Cbuf_InsertText (str);
76 Called when a demo file runs out, or the user starts a game
79 // LordHavoc: now called only by CL_Disconnect
80 void CL_StopPlayback (void)
82 if (!cls.demoplayback)
85 FS_Close (cls.demofile);
86 cls.demoplayback = false;
97 Dumps the current net message, prefixed by the length and view angles
100 void CL_WriteDemoMessage (void)
106 if (cls.demopaused) // LordHavoc: pausedemo
109 len = LittleLong (net_message.cursize);
110 FS_Write (cls.demofile, &len, 4);
111 for (i=0 ; i<3 ; i++)
113 f = LittleFloat (cl.viewangles[i]);
114 FS_Write (cls.demofile, &f, 4);
116 FS_Write (cls.demofile, net_message.data, net_message.cursize);
117 FS_Flush (cls.demofile);
124 Handles playback of demos
127 void CL_ReadDemoMessage(void)
132 if (!cls.demoplayback)
135 // LordHavoc: pausedemo
141 // decide if it is time to grab the next message
142 // always grab until fully connected
143 if (cls.signon == SIGNONS)
147 if (host_framecount == cls.td_lastframe)
149 // already read this frame's message
152 if (cls.td_lastframe == -1)
154 // we start counting on the second frame
155 // (after parsing connection stuff)
156 cls.td_startframe = host_framecount + 1;
158 cls.td_lastframe = host_framecount;
159 // if this is the first official frame we can now grab the real
160 // td_starttime so the bogus time on the first frame doesn't
161 // count against the final report
162 if (host_framecount == cls.td_startframe)
163 cls.td_starttime = realtime;
164 if (host_framecount > cls.td_startframe + 2)
166 cls.td_minframetime = min(cls.td_minframetime, host_realframetime);
167 cls.td_maxframetime = max(cls.td_maxframetime, host_realframetime);
170 cls.td_minframetime = cls.td_maxframetime = host_realframetime;
172 else if (cl.time <= cl.mtime[0])
174 // don't need another message yet
179 // get the next message
180 FS_Read(cls.demofile, &net_message.cursize, 4);
181 net_message.cursize = LittleLong(net_message.cursize);
182 if (net_message.cursize > net_message.maxsize)
183 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
184 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
185 for (i = 0;i < 3;i++)
187 r = FS_Read(cls.demofile, &f, 4);
188 cl.mviewangles[0][i] = LittleFloat(f);
191 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == (size_t)net_message.cursize)
194 CL_ParseServerMessage();
196 // In case the demo contains a "svc_disconnect" message
197 if (!cls.demoplayback)
213 stop recording a demo
216 void CL_Stop_f (void)
218 if (cmd_source != src_command)
221 if (!cls.demorecording)
223 Con_Print("Not recording a demo.\n");
227 // write a disconnect message to the demo file
228 SZ_Clear (&net_message);
229 MSG_WriteByte (&net_message, svc_disconnect);
230 CL_WriteDemoMessage ();
233 FS_Close (cls.demofile);
235 cls.demorecording = false;
236 Con_Print("Completed demo\n");
243 record <demoname> <map> [cd track]
246 void CL_Record_f (void)
249 char name[MAX_OSPATH];
251 if (cmd_source != src_command)
255 if (c != 2 && c != 3 && c != 4)
257 Con_Print("record <demoname> [<map> [cd track]]\n");
261 if (strstr(Cmd_Argv(1), ".."))
263 Con_Print("Relative pathnames are not allowed.\n");
267 if (c == 2 && cls.state == ca_connected)
269 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
273 // write the forced cd track number, or -1
276 track = atoi(Cmd_Argv(3));
277 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
283 strlcpy (name, Cmd_Argv(1), sizeof (name));
284 FS_DefaultExtension (name, ".dem", sizeof (name));
288 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
290 // open the demo file
291 Con_Printf("recording to %s.\n", name);
292 cls.demofile = FS_Open (name, "wb", false);
295 Con_Print("ERROR: couldn't open.\n");
299 cls.forcetrack = track;
300 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
302 cls.demorecording = true;
313 void CL_PlayDemo_f (void)
317 qboolean neg = false;
319 if (cmd_source != src_command)
324 Con_Print("play <demoname> : plays a demo\n");
328 // disconnect from server
330 Host_ShutdownServer (false);
332 // update networking ports (this is mainly just needed at startup)
333 NetConn_ClientFrame();
335 // open the demo file
336 strlcpy (name, Cmd_Argv(1), sizeof (name));
337 FS_DefaultExtension (name, ".dem", sizeof (name));
339 Con_Printf("Playing demo from %s.\n", name);
340 cls.demofile = FS_Open (name, "rb", false);
343 Con_Print("ERROR: couldn't open.\n");
344 cls.demonum = -1; // stop demo loop
348 SCR_BeginLoadingPlaque ();
350 strlcpy(cls.demoname, name, sizeof(cls.demoname));
351 cls.demoplayback = true;
352 cls.state = ca_connected;
355 while ((c = FS_Getc (cls.demofile)) != '\n')
359 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
362 cls.forcetrack = -cls.forcetrack;
371 void CL_FinishTimeDemo (void)
374 double time; // LordHavoc: changed timedemo accuracy to double
375 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
377 cls.timedemo = false;
379 // the first frame didn't count
380 frames = (host_framecount - cls.td_startframe) - 1;
381 time = realtime - cls.td_starttime;
382 fpsmin = cls.td_maxframetime > 0 ? 1.0 / cls.td_maxframetime : 0;
383 fpsavg = time > 0 ? frames / time : 0;
384 fpsmax = cls.td_minframetime > 0 ? 1.0 / cls.td_minframetime : 0;
385 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
386 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);
387 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);
388 if (COM_CheckParm("-benchmark"))
399 void CL_TimeDemo_f (void)
401 if (cmd_source != src_command)
406 Con_Print("timedemo <demoname> : gets demo speeds\n");
412 // cls.td_starttime will be grabbed at the second frame of the demo, so
413 // all the loading time doesn't get counted
415 // instantly hide console and deactivate it
417 key_consoleactive = 0;
422 // get first message this frame
423 cls.td_lastframe = -1;