git-svn-id: http://bladebattles.com/kurok/SVN@11 20cd92bb-ff49-0410-b73e-96a06e42c3b9
[kurok.git] / cl_demo.c
blobb82147f841fb4237ef87fd43ce8ca49af168327d
1 /*
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.
21 #include "quakedef.h"
23 void CL_FinishTimeDemo (void);
26 ==============================================================================
28 DEMO CODE
30 When a demo is playing back, all NET_SendMessages are skipped, and
31 NET_GetMessages 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 ==============================================================================
39 ==============
40 CL_StopPlayback
42 Called when a demo file runs out, or the user starts a game
43 ==============
45 void CL_StopPlayback (void)
47 if (!cls.demoplayback)
48 return;
50 Sys_FileClose(cls.demofile);
51 cls.demoplayback = false;
52 cls.demofile = -1;
53 cls.state = ca_disconnected;
55 if (cls.timedemo)
56 CL_FinishTimeDemo ();
60 ====================
61 CL_WriteDemoMessage
63 Dumps the current net message, prefixed by the length and view angles
64 ====================
66 void CL_WriteDemoMessage (void)
68 int len;
69 int i;
70 float f;
72 len = LittleLong (net_message.cursize);
73 Sys_FileWrite(cls.demofile, &len, 4);
74 for (i=0 ; i<3 ; i++)
76 f = LittleFloat (cl.viewangles[i]);
77 Sys_FileWrite(cls.demofile, &f, 4);
79 Sys_FileWrite(cls.demofile, net_message.data, net_message.cursize);
83 ====================
84 CL_GetMessage
86 Handles recording and playback of demos, on top of NET_ code
87 ====================
89 int CL_GetMessage (void)
91 int r, i;
92 float f;
94 if (cls.demoplayback)
96 // decide if it is time to grab the next message
97 if (cls.signon == SIGNONS) // allways grab until fully connected
99 if (cls.timedemo)
101 if (host_framecount == cls.td_lastframe)
102 return 0; // allready read this frame's message
103 cls.td_lastframe = host_framecount;
104 // if this is the second frame, grab the real td_starttime
105 // so the bogus time on the first frame doesn't count
106 if (host_framecount == cls.td_startframe + 1)
107 cls.td_starttime = realtime;
109 else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0])
111 return 0; // don't need another message yet
115 // get the next message
116 Sys_FileRead(cls.demofile, &net_message.cursize, 4);
117 VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);
118 for (i=0 ; i<3 ; i++)
120 r = Sys_FileRead(cls.demofile, &f, 4) / 4;
121 cl.mviewangles[0][i] = LittleFloat (f);
124 net_message.cursize = LittleLong (net_message.cursize);
125 if (net_message.cursize > MAX_MSGLEN)
126 Sys_Error ("Demo message (0x%08x) > MAX_MSGLEN (%d)", net_message.cursize, MAX_MSGLEN);
127 r = Sys_FileRead(cls.demofile, net_message.data, net_message.cursize) / net_message.cursize;
128 if (r != 1)
130 CL_StopPlayback ();
131 return 0;
134 return 1;
137 while (1)
139 r = NET_GetMessage (cls.netcon);
141 if (r != 1 && r != 2)
142 return r;
144 // discard nop keepalive message
145 if (net_message.cursize == 1 && net_message.data[0] == svc_nop)
146 Con_Printf ("<-- server to client keepalive\n");
147 else
148 break;
151 if (cls.demorecording)
152 CL_WriteDemoMessage ();
154 return r;
159 ====================
160 CL_Stop_f
162 stop recording a demo
163 ====================
165 void CL_Stop_f (void)
167 if (cmd_source != src_command)
168 return;
170 if (!cls.demorecording)
172 Con_Printf ("Not recording a demo.\n");
173 return;
176 // write a disconnect message to the demo file
177 SZ_Clear (&net_message);
178 MSG_WriteByte (&net_message, svc_disconnect);
179 CL_WriteDemoMessage ();
181 // finish up
182 Sys_FileClose(cls.demofile);
183 cls.demofile = -1;
184 cls.demorecording = false;
185 Con_Printf ("Completed demo\n");
189 ====================
190 CL_Record_f
192 record <demoname> <map> [cd track]
193 ====================
195 void CL_Record_f (void)
197 int c;
198 char name[MAX_OSPATH];
199 int track;
200 char forcetrack[16];
202 if (cmd_source != src_command)
203 return;
205 c = Cmd_Argc();
206 if (c != 2 && c != 3 && c != 4)
208 Con_Printf ("record <demoname> [<map> [cd track]]\n");
209 return;
212 if (strstr(Cmd_Argv(1), ".."))
214 Con_Printf ("Relative pathnames are not allowed.\n");
215 return;
218 if (c == 2 && cls.state == ca_connected)
220 Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
221 return;
224 // write the forced cd track number, or -1
225 if (c == 4)
227 track = atoi(Cmd_Argv(3));
228 Con_Printf ("Forcing CD track to %i\n", cls.forcetrack);
230 else
231 track = -1;
233 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
236 // start the map up
238 if (c > 2)
239 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
242 // open the demo file
244 COM_DefaultExtension (name, ".dem");
246 Con_Printf ("recording to %s.\n", name);
247 cls.demofile = Sys_FileOpenWrite(name);
248 if (cls.demofile < 0)
250 Con_Printf ("ERROR: couldn't open demo for writing.\n");
251 return;
254 cls.forcetrack = track;
255 sprintf(forcetrack, "%i\n", cls.forcetrack);
256 Sys_FileWrite(cls.demofile, forcetrack, strlen(forcetrack));
258 cls.demorecording = true;
263 ====================
264 CL_PlayDemo_f
266 play [demoname]
267 ====================
269 static int CL_FileGetChar(int handle)
271 char c;
273 if (Sys_FileRead(handle, &c, 1) != 1)
275 return EOF;
278 return c;
281 void CL_PlayDemo_f (void)
283 char name[256];
284 int c;
285 qboolean neg = false;
287 if (cmd_source != src_command)
288 return;
290 if (Cmd_Argc() != 2)
292 Con_Printf ("play <demoname> : plays a demo\n");
293 return;
297 // disconnect from server
299 CL_Disconnect ();
302 // open the demo file
304 strcpy (name, Cmd_Argv(1));
305 COM_DefaultExtension (name, ".dem");
307 Con_Printf ("Playing demo from %s.\n", name);
308 COM_FOpenFile (name, &cls.demofile);
309 if (cls.demofile < 0)
311 Con_Printf ("ERROR: couldn't open demo for reading.\n");
312 cls.demonum = -1; // stop demo loop
313 return;
316 cls.demoplayback = true;
317 cls.state = ca_connected;
318 cls.forcetrack = 0;
320 while ((c = CL_FileGetChar(cls.demofile)) != '\n')
321 if (c == '-')
322 neg = true;
323 else
324 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
326 if (neg)
327 cls.forcetrack = -cls.forcetrack;
328 // ZOID, fscanf is evil
329 // fscanf (cls.demofile, "%i\n", &cls.forcetrack);
333 ====================
334 CL_FinishTimeDemo
336 ====================
338 void CL_FinishTimeDemo (void)
340 int frames;
341 double time;
343 cls.timedemo = false;
345 // the first frame didn't count
346 frames = (host_framecount - cls.td_startframe) - 1;
347 time = realtime - cls.td_starttime;
348 if (time < 1)
349 time = 1;
350 Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time);
354 ====================
355 CL_TimeDemo_f
357 timedemo [demoname]
358 ====================
360 void CL_TimeDemo_f (void)
362 if (cmd_source != src_command)
363 return;
365 if (Cmd_Argc() != 2)
367 Con_Printf ("timedemo <demoname> : gets demo speeds\n");
368 return;
371 CL_PlayDemo_f ();
373 // cls.td_starttime will be grabbed at the second frame of the demo, so
374 // all the loading time doesn't get counted
376 cls.timedemo = true;
377 cls.td_startframe = host_framecount;
378 cls.td_lastframe = -1; // get a new message this frame