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)
49 char str[MAX_INPUTLINE];
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;
90 if (COM_CheckParm("-demo") || COM_CheckParm("-demolooponly"))
99 Dumps the current net message, prefixed by the length and view angles
102 void CL_WriteDemoMessage (void)
108 if (cls.demopaused) // LordHavoc: pausedemo
111 len = LittleLong (net_message.cursize);
112 FS_Write (cls.demofile, &len, 4);
113 for (i=0 ; i<3 ; i++)
115 f = LittleFloat (cl.viewangles[i]);
116 FS_Write (cls.demofile, &f, 4);
118 FS_Write (cls.demofile, net_message.data, net_message.cursize);
125 Handles playback of demos
128 void CL_ReadDemoMessage(void)
133 if (!cls.demoplayback)
136 // LordHavoc: pausedemo
142 // decide if it is time to grab the next message
143 // always grab until fully connected
144 if (cls.signon == SIGNONS)
148 if (host_framecount == cls.td_lastframe)
150 // already read this frame's message
153 if (cls.td_lastframe == -1)
155 // we start counting on the second frame
156 // (after parsing connection stuff)
157 cls.td_startframe = host_framecount + 1;
159 cls.td_lastframe = host_framecount;
160 // if this is the first official frame we can now grab the real
161 // td_starttime so the bogus time on the first frame doesn't
162 // count against the final report
163 if (host_framecount == cls.td_startframe)
164 cls.td_starttime = realtime;
165 if (host_framecount > cls.td_startframe + 2)
167 cls.td_minframetime = min(cls.td_minframetime, host_realframetime);
168 cls.td_maxframetime = max(cls.td_maxframetime, host_realframetime);
171 cls.td_minframetime = cls.td_maxframetime = host_realframetime;
173 else if (cl.time <= cl.mtime[0])
175 // don't need another message yet
180 // get the next message
181 FS_Read(cls.demofile, &net_message.cursize, 4);
182 net_message.cursize = LittleLong(net_message.cursize);
183 if (net_message.cursize > net_message.maxsize)
184 Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
185 VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
186 for (i = 0;i < 3;i++)
188 r = (int)FS_Read(cls.demofile, &f, 4);
189 cl.mviewangles[0][i] = LittleFloat(f);
192 if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == net_message.cursize)
195 CL_ParseServerMessage();
197 // In case the demo contains a "svc_disconnect" message
198 if (!cls.demoplayback)
214 stop recording a demo
217 void CL_Stop_f (void)
219 if (cmd_source != src_command)
222 if (!cls.demorecording)
224 Con_Print("Not recording a demo.\n");
228 // write a disconnect message to the demo file
229 SZ_Clear (&net_message);
230 MSG_WriteByte (&net_message, svc_disconnect);
231 CL_WriteDemoMessage ();
234 FS_Close (cls.demofile);
236 cls.demorecording = false;
237 Con_Print("Completed demo\n");
244 record <demoname> <map> [cd track]
247 void CL_Record_f (void)
250 char name[MAX_OSPATH];
252 if (cmd_source != src_command)
256 if (c != 2 && c != 3 && c != 4)
258 Con_Print("record <demoname> [<map> [cd track]]\n");
262 if (strstr(Cmd_Argv(1), ".."))
264 Con_Print("Relative pathnames are not allowed.\n");
268 if (c == 2 && cls.state == ca_connected)
270 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
274 // write the forced cd track number, or -1
277 track = atoi(Cmd_Argv(3));
278 Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
284 strlcpy (name, Cmd_Argv(1), sizeof (name));
285 FS_DefaultExtension (name, ".dem", sizeof (name));
289 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
291 // open the demo file
292 Con_Printf("recording to %s.\n", name);
293 cls.demofile = FS_Open (name, "wb", false, false);
296 Con_Print("ERROR: couldn't open.\n");
300 cls.forcetrack = track;
301 FS_Printf(cls.demofile, "%i\n", cls.forcetrack);
303 cls.demorecording = true;
314 void CL_PlayDemo_f (void)
316 char name[MAX_QPATH];
318 qboolean neg = false;
320 if (cmd_source != src_command)
325 Con_Print("play <demoname> : plays a demo\n");
329 // disconnect from server
331 Host_ShutdownServer (false);
333 // update networking ports (this is mainly just needed at startup)
334 NetConn_ClientFrame();
336 // open the demo file
337 strlcpy (name, Cmd_Argv(1), sizeof (name));
338 FS_DefaultExtension (name, ".dem", sizeof (name));
340 Con_Printf("Playing demo from %s.\n", name);
341 cls.demofile = FS_Open (name, "rb", false, false);
344 Con_Print("ERROR: couldn't open.\n");
345 cls.demonum = -1; // stop demo loop
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;
420 // get first message this frame
421 cls.td_lastframe = -1;