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_Printf ("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();
205 stop recording a demo
208 void CL_Stop_f (void)
210 if (cmd_source != src_command)
213 if (!cls.demorecording)
215 Con_Printf ("Not recording a demo.\n");
219 // write a disconnect message to the demo file
220 SZ_Clear (&net_message);
221 MSG_WriteByte (&net_message, svc_disconnect);
222 CL_WriteDemoMessage ();
225 FS_Close (cls.demofile);
227 cls.demorecording = false;
228 Con_Printf ("Completed demo\n");
235 record <demoname> <map> [cd track]
238 void CL_Record_f (void)
241 char name[MAX_OSPATH];
243 if (cmd_source != src_command)
247 if (c != 2 && c != 3 && c != 4)
249 Con_Printf ("record <demoname> [<map> [cd track]]\n");
253 if (strstr(Cmd_Argv(1), ".."))
255 Con_Printf ("Relative pathnames are not allowed.\n");
259 if (c == 2 && cls.state == ca_connected)
261 Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
265 // write the forced cd track number, or -1
268 track = atoi(Cmd_Argv(3));
269 Con_Printf ("Forcing CD track to %i\n", cls.forcetrack);
275 strlcpy (name, Cmd_Argv(1), sizeof (name));
276 FS_DefaultExtension (name, ".dem", sizeof (name));
280 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
282 // open the demo file
283 Con_Printf ("recording to %s.\n", name);
284 cls.demofile = FS_Open (name, "wb", false);
287 Con_Printf ("ERROR: couldn't open.\n");
291 cls.forcetrack = track;
292 FS_Printf (cls.demofile, "%i\n", cls.forcetrack);
294 cls.demorecording = true;
305 void CL_PlayDemo_f (void)
309 qboolean neg = false;
311 if (cmd_source != src_command)
316 Con_Printf ("play <demoname> : plays a demo\n");
320 // disconnect from server
323 // update networking ports (this is mainly just needed at startup)
324 NetConn_ClientFrame();
326 // open the demo file
327 strlcpy (name, Cmd_Argv(1), sizeof (name));
328 FS_DefaultExtension (name, ".dem", sizeof (name));
330 Con_Printf ("Playing demo from %s.\n", name);
331 cls.demofile = FS_Open (name, "rb", false);
334 Con_Printf ("ERROR: couldn't open.\n");
335 cls.demonum = -1; // stop demo loop
339 SCR_BeginLoadingPlaque ();
341 cls.demoplayback = true;
342 cls.state = ca_connected;
345 while ((c = FS_Getc (cls.demofile)) != '\n')
349 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
352 cls.forcetrack = -cls.forcetrack;
361 void CL_FinishTimeDemo (void)
364 double time; // LordHavoc: changed timedemo accuracy to double
365 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
367 cls.timedemo = false;
369 // the first frame didn't count
370 frames = (host_framecount - cls.td_startframe) - 1;
371 time = realtime - cls.td_starttime;
372 fpsmin = cls.td_maxframetime > 0 ? 1.0 / cls.td_maxframetime : 0;
373 fpsavg = time > 0 ? frames / time : 0;
374 fpsmax = cls.td_minframetime > 0 ? 1.0 / cls.td_minframetime : 0;
375 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
376 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);
386 void CL_TimeDemo_f (void)
388 if (cmd_source != src_command)
393 Con_Printf ("timedemo <demoname> : gets demo speeds\n");
399 // cls.td_starttime will be grabbed at the second frame of the demo, so
400 // all the loading time doesn't get counted
402 // instantly hide console and deactivate it
404 key_consoleactive = 0;
409 // get first message this frame
410 cls.td_lastframe = -1;