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 void CL_NextDemo (void)
49 if (cls.demonum == -1)
50 return; // don't play demos
52 if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
55 if (!cls.demos[cls.demonum][0])
57 Con_Print("No demos listed with startdemos\n");
63 sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
64 Cbuf_InsertText (str);
72 Called when a demo file runs out, or the user starts a game
75 // LordHavoc: now called only by CL_Disconnect
76 void CL_StopPlayback (void)
78 if (!cls.demoplayback)
81 FS_Close (cls.demofile);
82 cls.demoplayback = false;
93 Dumps the current net message, prefixed by the length and view angles
96 void CL_WriteDemoMessage (void)
102 if (cls.demopaused) // LordHavoc: pausedemo
105 len = LittleLong (net_message.cursize);
106 FS_Write (cls.demofile, &len, 4);
107 for (i=0 ; i<3 ; i++)
109 f = LittleFloat (cl.viewangles[i]);
110 FS_Write (cls.demofile, &f, 4);
112 FS_Write (cls.demofile, net_message.data, net_message.cursize);
113 FS_Flush (cls.demofile);
120 Handles playback of demos
123 void CL_ReadDemoMessage(void)
128 if (!cls.demoplayback)
131 // LordHavoc: pausedemo
137 // decide if it is time to grab the next message
138 // always grab until fully connected
139 if (cls.signon == SIGNONS)
143 if (host_framecount == cls.td_lastframe)
145 // already read this frame's message
148 if (cls.td_lastframe == -1)
150 // we start counting on the second frame
151 // (after parsing connection stuff)
152 cls.td_startframe = host_framecount + 1;
154 cls.td_lastframe = host_framecount;
155 // if this is the first official frame we can now grab the real
156 // td_starttime so the bogus time on the first frame doesn't
157 // count against the final report
158 if (host_framecount == cls.td_startframe)
159 cls.td_starttime = realtime;
160 if (host_framecount > cls.td_startframe + 2)
162 cls.td_minframetime = min(cls.td_minframetime, host_realframetime);
163 cls.td_maxframetime = max(cls.td_maxframetime, host_realframetime);
166 cls.td_minframetime = cls.td_maxframetime = host_realframetime;
168 else if (cl.time <= cl.mtime[0])
170 // don't need another message yet
175 // get the next message
176 FS_Read(cls.demofile, &net_message.cursize, 4);
177 net_message.cursize = LittleLong(net_message.cursize);
178 if (net_message.cursize > net_message.maxsize)
179 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
180 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
181 for (i = 0;i < 3;i++)
183 r = FS_Read(cls.demofile, &f, 4);
184 cl.mviewangles[0][i] = LittleFloat(f);
187 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == (size_t)net_message.cursize)
190 CL_ParseServerMessage();
192 // In case the demo contains a "svc_disconnect" message
193 if (!cls.demoplayback)
209 stop recording a demo
212 void CL_Stop_f (void)
214 if (cmd_source != src_command)
217 if (!cls.demorecording)
219 Con_Print("Not recording a demo.\n");
223 // write a disconnect message to the demo file
224 SZ_Clear (&net_message);
225 MSG_WriteByte (&net_message, svc_disconnect);
226 CL_WriteDemoMessage ();
229 FS_Close (cls.demofile);
231 cls.demorecording = false;
232 Con_Print("Completed demo\n");
239 record <demoname> <map> [cd track]
242 void CL_Record_f (void)
245 char name[MAX_OSPATH];
247 if (cmd_source != src_command)
251 if (c != 2 && c != 3 && c != 4)
253 Con_Print("record <demoname> [<map> [cd track]]\n");
257 if (strstr(Cmd_Argv(1), ".."))
259 Con_Print("Relative pathnames are not allowed.\n");
263 if (c == 2 && cls.state == ca_connected)
265 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
269 // write the forced cd track number, or -1
272 track = atoi(Cmd_Argv(3));
273 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
279 strlcpy (name, Cmd_Argv(1), sizeof (name));
280 FS_DefaultExtension (name, ".dem", sizeof (name));
284 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
286 // open the demo file
287 Con_Printf("recording to %s.\n", name);
288 cls.demofile = FS_Open (name, "wb", false);
291 Con_Print("ERROR: couldn't open.\n");
295 cls.forcetrack = track;
296 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
298 cls.demorecording = true;
309 void CL_PlayDemo_f (void)
313 qboolean neg = false;
315 if (cmd_source != src_command)
320 Con_Print("play <demoname> : plays a demo\n");
324 // disconnect from server
326 Host_ShutdownServer (false);
328 // update networking ports (this is mainly just needed at startup)
329 NetConn_ClientFrame();
331 // open the demo file
332 strlcpy (name, Cmd_Argv(1), sizeof (name));
333 FS_DefaultExtension (name, ".dem", sizeof (name));
335 Con_Printf("Playing demo from %s.\n", name);
336 cls.demofile = FS_Open (name, "rb", false);
339 Con_Print("ERROR: couldn't open.\n");
340 cls.demonum = -1; // stop demo loop
344 SCR_BeginLoadingPlaque ();
346 strlcpy(cls.demoname, name, sizeof(cls.demoname));
347 cls.demoplayback = true;
348 cls.state = ca_connected;
351 while ((c = FS_Getc (cls.demofile)) != '\n')
355 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
358 cls.forcetrack = -cls.forcetrack;
367 void CL_FinishTimeDemo (void)
370 double time; // LordHavoc: changed timedemo accuracy to double
371 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
373 cls.timedemo = false;
375 // the first frame didn't count
376 frames = (host_framecount - cls.td_startframe) - 1;
377 time = realtime - cls.td_starttime;
378 fpsmin = cls.td_maxframetime > 0 ? 1.0 / cls.td_maxframetime : 0;
379 fpsavg = time > 0 ? frames / time : 0;
380 fpsmax = cls.td_minframetime > 0 ? 1.0 / cls.td_minframetime : 0;
381 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
382 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);
383 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);
384 if (COM_CheckParm("-benchmark"))
395 void CL_TimeDemo_f (void)
397 if (cmd_source != src_command)
402 Con_Print("timedemo <demoname> : gets demo speeds\n");
408 // cls.td_starttime will be grabbed at the second frame of the demo, so
409 // all the loading time doesn't get counted
411 // instantly hide console and deactivate it
413 key_consoleactive = 0;
418 // get first message this frame
419 cls.td_lastframe = -1;