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);
121 Handles playback of demos
124 void CL_ReadDemoMessage(void)
129 if (!cls.demoplayback)
132 // LordHavoc: pausedemo
138 // decide if it is time to grab the next message
139 // always grab until fully connected
140 if (cls.signon == SIGNONS)
144 if (host_framecount == cls.td_lastframe)
146 // already read this frame's message
149 if (cls.td_lastframe == -1)
151 // we start counting on the second frame
152 // (after parsing connection stuff)
153 cls.td_startframe = host_framecount + 1;
155 cls.td_lastframe = host_framecount;
156 // if this is the first official frame we can now grab the real
157 // td_starttime so the bogus time on the first frame doesn't
158 // count against the final report
159 if (host_framecount == cls.td_startframe)
160 cls.td_starttime = realtime;
161 if (host_framecount > cls.td_startframe + 2)
163 cls.td_minframetime = min(cls.td_minframetime, host_realframetime);
164 cls.td_maxframetime = max(cls.td_maxframetime, host_realframetime);
167 cls.td_minframetime = cls.td_maxframetime = host_realframetime;
169 else if (cl.time <= cl.mtime[0])
171 // don't need another message yet
176 // get the next message
177 FS_Read(cls.demofile, &net_message.cursize, 4);
178 net_message.cursize = LittleLong(net_message.cursize);
179 if (net_message.cursize > net_message.maxsize)
180 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
181 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
182 for (i = 0;i < 3;i++)
184 r = FS_Read(cls.demofile, &f, 4);
185 cl.mviewangles[0][i] = LittleFloat(f);
188 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == (size_t)net_message.cursize)
191 CL_ParseServerMessage();
193 // In case the demo contains a "svc_disconnect" message
194 if (!cls.demoplayback)
210 stop recording a demo
213 void CL_Stop_f (void)
215 if (cmd_source != src_command)
218 if (!cls.demorecording)
220 Con_Print("Not recording a demo.\n");
224 // write a disconnect message to the demo file
225 SZ_Clear (&net_message);
226 MSG_WriteByte (&net_message, svc_disconnect);
227 CL_WriteDemoMessage ();
230 FS_Close (cls.demofile);
232 cls.demorecording = false;
233 Con_Print("Completed demo\n");
240 record <demoname> <map> [cd track]
243 void CL_Record_f (void)
246 char name[MAX_OSPATH];
248 if (cmd_source != src_command)
252 if (c != 2 && c != 3 && c != 4)
254 Con_Print("record <demoname> [<map> [cd track]]\n");
258 if (strstr(Cmd_Argv(1), ".."))
260 Con_Print("Relative pathnames are not allowed.\n");
264 if (c == 2 && cls.state == ca_connected)
266 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
270 // write the forced cd track number, or -1
273 track = atoi(Cmd_Argv(3));
274 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
280 strlcpy (name, Cmd_Argv(1), sizeof (name));
281 FS_DefaultExtension (name, ".dem", sizeof (name));
285 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
287 // open the demo file
288 Con_Printf("recording to %s.\n", name);
289 cls.demofile = FS_Open (name, "wb", false, false);
292 Con_Print("ERROR: couldn't open.\n");
296 cls.forcetrack = track;
297 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
299 cls.demorecording = true;
310 void CL_PlayDemo_f (void)
314 qboolean neg = false;
316 if (cmd_source != src_command)
321 Con_Print("play <demoname> : plays a demo\n");
325 // disconnect from server
327 Host_ShutdownServer (false);
329 // update networking ports (this is mainly just needed at startup)
330 NetConn_ClientFrame();
332 // open the demo file
333 strlcpy (name, Cmd_Argv(1), sizeof (name));
334 FS_DefaultExtension (name, ".dem", sizeof (name));
336 Con_Printf("Playing demo from %s.\n", name);
337 cls.demofile = FS_Open (name, "rb", false, false);
340 Con_Print("ERROR: couldn't open.\n");
341 cls.demonum = -1; // stop demo loop
345 strlcpy(cls.demoname, name, sizeof(cls.demoname));
346 cls.demoplayback = true;
347 cls.state = ca_connected;
350 while ((c = FS_Getc (cls.demofile)) != '\n')
354 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
357 cls.forcetrack = -cls.forcetrack;
366 void CL_FinishTimeDemo (void)
369 double time; // LordHavoc: changed timedemo accuracy to double
370 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
372 cls.timedemo = false;
374 // the first frame didn't count
375 frames = (host_framecount - cls.td_startframe) - 1;
376 time = realtime - cls.td_starttime;
377 fpsmin = cls.td_maxframetime > 0 ? 1.0 / cls.td_maxframetime : 0;
378 fpsavg = time > 0 ? frames / time : 0;
379 fpsmax = cls.td_minframetime > 0 ? 1.0 / cls.td_minframetime : 0;
380 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
381 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);
382 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);
383 if (COM_CheckParm("-benchmark"))
394 void CL_TimeDemo_f (void)
396 if (cmd_source != src_command)
401 Con_Print("timedemo <demoname> : gets demo speeds\n");
407 // cls.td_starttime will be grabbed at the second frame of the demo, so
408 // all the loading time doesn't get counted
410 // instantly hide console and deactivate it
412 key_consoleactive = 0;
416 // get first message this frame
417 cls.td_lastframe = -1;