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");
59 // put up menu instead of staring at console
60 if (key_dest != key_menu)
66 sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
67 Cbuf_InsertText (str);
75 Called when a demo file runs out, or the user starts a game
78 // LordHavoc: now called only by CL_Disconnect
79 void CL_StopPlayback (void)
81 if (!cls.demoplayback)
84 FS_Close (cls.demofile);
85 cls.demoplayback = false;
96 Dumps the current net message, prefixed by the length and view angles
99 void CL_WriteDemoMessage (void)
105 if (cls.demopaused) // LordHavoc: pausedemo
108 len = LittleLong (net_message.cursize);
109 FS_Write (cls.demofile, &len, 4);
110 for (i=0 ; i<3 ; i++)
112 f = LittleFloat (cl.viewangles[i]);
113 FS_Write (cls.demofile, &f, 4);
115 FS_Write (cls.demofile, net_message.data, net_message.cursize);
116 FS_Flush (cls.demofile);
123 Handles playback of demos
126 void CL_ReadDemoMessage(void)
131 if (!cls.demoplayback)
134 // LordHavoc: pausedemo
140 // decide if it is time to grab the next message
141 // always grab until fully connected
142 if (cls.signon == SIGNONS)
146 if (host_framecount == cls.td_lastframe)
148 // already read this frame's message
151 if (cls.td_lastframe == -1)
153 // we start counting on the second frame
154 // (after parsing connection stuff)
155 cls.td_startframe = host_framecount + 1;
157 cls.td_lastframe = host_framecount;
158 // if this is the first official frame we can now grab the real
159 // td_starttime so the bogus time on the first frame doesn't
160 // count against the final report
161 if (host_framecount == cls.td_startframe)
162 cls.td_starttime = realtime;
163 if (host_framecount > cls.td_startframe + 2)
165 cls.td_minframetime = min(cls.td_minframetime, host_realframetime);
166 cls.td_maxframetime = max(cls.td_maxframetime, host_realframetime);
169 cls.td_minframetime = cls.td_maxframetime = host_realframetime;
171 else if (cl.time <= cl.mtime[0])
173 // don't need another message yet
178 // get the next message
179 FS_Read(cls.demofile, &net_message.cursize, 4);
180 net_message.cursize = LittleLong(net_message.cursize);
181 if (net_message.cursize > net_message.maxsize)
182 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
183 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
184 for (i = 0;i < 3;i++)
186 r = FS_Read(cls.demofile, &f, 4);
187 cl.mviewangles[0][i] = LittleFloat(f);
190 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == (size_t)net_message.cursize)
193 CL_ParseServerMessage();
195 // In case the demo contains a "svc_disconnect" message
196 if (!cls.demoplayback)
212 stop recording a demo
215 void CL_Stop_f (void)
217 if (cmd_source != src_command)
220 if (!cls.demorecording)
222 Con_Print("Not recording a demo.\n");
226 // write a disconnect message to the demo file
227 SZ_Clear (&net_message);
228 MSG_WriteByte (&net_message, svc_disconnect);
229 CL_WriteDemoMessage ();
232 FS_Close (cls.demofile);
234 cls.demorecording = false;
235 Con_Print("Completed demo\n");
242 record <demoname> <map> [cd track]
245 void CL_Record_f (void)
248 char name[MAX_OSPATH];
250 if (cmd_source != src_command)
254 if (c != 2 && c != 3 && c != 4)
256 Con_Print("record <demoname> [<map> [cd track]]\n");
260 if (strstr(Cmd_Argv(1), ".."))
262 Con_Print("Relative pathnames are not allowed.\n");
266 if (c == 2 && cls.state == ca_connected)
268 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
272 // write the forced cd track number, or -1
275 track = atoi(Cmd_Argv(3));
276 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
282 strlcpy (name, Cmd_Argv(1), sizeof (name));
283 FS_DefaultExtension (name, ".dem", sizeof (name));
287 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
289 // open the demo file
290 Con_Printf("recording to %s.\n", name);
291 cls.demofile = FS_Open (name, "wb", false);
294 Con_Print("ERROR: couldn't open.\n");
298 cls.forcetrack = track;
299 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
301 cls.demorecording = true;
312 void CL_PlayDemo_f (void)
316 qboolean neg = false;
318 if (cmd_source != src_command)
323 Con_Print("play <demoname> : plays a demo\n");
327 // disconnect from server
329 Host_ShutdownServer (false);
331 // update networking ports (this is mainly just needed at startup)
332 NetConn_ClientFrame();
334 // open the demo file
335 strlcpy (name, Cmd_Argv(1), sizeof (name));
336 FS_DefaultExtension (name, ".dem", sizeof (name));
338 Con_Printf("Playing demo from %s.\n", name);
339 cls.demofile = FS_Open (name, "rb", false);
342 Con_Print("ERROR: couldn't open.\n");
343 cls.demonum = -1; // stop demo loop
347 SCR_BeginLoadingPlaque ();
349 strlcpy(cls.demoname, name, sizeof(cls.demoname));
350 cls.demoplayback = true;
351 cls.state = ca_connected;
354 while ((c = FS_Getc (cls.demofile)) != '\n')
358 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
361 cls.forcetrack = -cls.forcetrack;
370 void CL_FinishTimeDemo (void)
373 double time; // LordHavoc: changed timedemo accuracy to double
374 double fpsmin, fpsavg, fpsmax; // report min/avg/max fps
376 cls.timedemo = false;
378 // the first frame didn't count
379 frames = (host_framecount - cls.td_startframe) - 1;
380 time = realtime - cls.td_starttime;
381 fpsmin = cls.td_maxframetime > 0 ? 1.0 / cls.td_maxframetime : 0;
382 fpsavg = time > 0 ? frames / time : 0;
383 fpsmax = cls.td_minframetime > 0 ? 1.0 / cls.td_minframetime : 0;
384 // LordHavoc: timedemo now prints out 7 digits of fraction, and min/avg/max
385 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 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);
387 if (COM_CheckParm("-benchmark"))
398 void CL_TimeDemo_f (void)
400 if (cmd_source != src_command)
405 Con_Print("timedemo <demoname> : gets demo speeds\n");
411 // cls.td_starttime will be grabbed at the second frame of the demo, so
412 // all the loading time doesn't get counted
414 // instantly hide console and deactivate it
416 key_consoleactive = 0;
421 // get first message this frame
422 cls.td_lastframe = -1;