Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 1 | /* |
2 | Copyright (C) 1996-1997 Id Software, Inc. |
||
3 | |||
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. |
||
8 | |||
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. |
||
12 | |||
13 | See the GNU General Public License for more details. |
||
14 | |||
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. |
||
18 | |||
19 | */ |
||
20 | |||
21 | #include "quakedef.h" |
||
22 | |||
23 | void CL_FinishTimeDemo (void); |
||
24 | |||
25 | /* |
||
26 | ============================================================================== |
||
27 | |||
28 | DEMO CODE |
||
29 | |||
30 | When a demo is playing back, all NET_SendMessages are skipped, and |
||
31 | NET_GetMessages are read from the demo file. |
||
32 | |||
33 | Whenever cl.time gets past the last received message, another message is |
||
34 | read from the demo file. |
||
35 | ============================================================================== |
||
36 | */ |
||
37 | |||
38 | /* |
||
39 | ============== |
||
40 | CL_StopPlayback |
||
41 | |||
42 | Called when a demo file runs out, or the user starts a game |
||
43 | ============== |
||
44 | */ |
||
45 | void CL_StopPlayback (void) |
||
46 | { |
||
47 | if (!cls.demoplayback) |
||
48 | return; |
||
49 | |||
50 | fclose (cls.demofile); |
||
51 | cls.demoplayback = false; |
||
52 | cls.demofile = NULL; |
||
53 | cls.state = ca_disconnected; |
||
54 | |||
55 | if (cls.timedemo) |
||
56 | CL_FinishTimeDemo (); |
||
57 | } |
||
58 | |||
59 | /* |
||
60 | ==================== |
||
61 | CL_WriteDemoMessage |
||
62 | |||
63 | Dumps the current net message, prefixed by the length and view angles |
||
64 | ==================== |
||
65 | */ |
||
66 | void CL_WriteDemoMessage (void) |
||
67 | { |
||
68 | int len; |
||
69 | int i; |
||
70 | float f; |
||
71 | |||
72 | len = LittleLong (net_message.cursize); |
||
73 | fwrite (&len, 4, 1, cls.demofile); |
||
74 | for (i=0 ; i<3 ; i++) |
||
75 | { |
||
76 | f = LittleFloat (cl.viewangles[i]); |
||
77 | fwrite (&f, 4, 1, cls.demofile); |
||
78 | } |
||
79 | fwrite (net_message.data, net_message.cursize, 1, cls.demofile); |
||
80 | fflush (cls.demofile); |
||
81 | } |
||
82 | |||
83 | /* |
||
84 | ==================== |
||
85 | CL_GetMessage |
||
86 | |||
87 | Handles recording and playback of demos, on top of NET_ code |
||
88 | ==================== |
||
89 | */ |
||
90 | int CL_GetMessage (void) |
||
91 | { |
||
92 | int r, i; |
||
93 | float f; |
||
94 | |||
95 | if (cls.demoplayback) |
||
96 | { |
||
97 | // decide if it is time to grab the next message |
||
98 | if (cls.signon == SIGNONS) // allways grab until fully connected |
||
99 | { |
||
100 | if (cls.timedemo) |
||
101 | { |
||
102 | if (host_framecount == cls.td_lastframe) |
||
103 | return 0; // allready read this frame's message |
||
104 | cls.td_lastframe = host_framecount; |
||
105 | // if this is the second frame, grab the real td_starttime |
||
106 | // so the bogus time on the first frame doesn't count |
||
107 | if (host_framecount == cls.td_startframe + 1) |
||
108 | cls.td_starttime = realtime; |
||
109 | } |
||
110 | else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0]) |
||
111 | { |
||
112 | return 0; // don't need another message yet |
||
113 | } |
||
114 | } |
||
115 | |||
116 | // get the next message |
||
117 | fread (&net_message.cursize, 4, 1, cls.demofile); |
||
118 | VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); |
||
119 | for (i=0 ; i<3 ; i++) |
||
120 | { |
||
121 | r = fread (&f, 4, 1, cls.demofile); |
||
122 | cl.mviewangles[0][i] = LittleFloat (f); |
||
123 | } |
||
124 | |||
125 | net_message.cursize = LittleLong (net_message.cursize); |
||
126 | if (net_message.cursize > MAX_MSGLEN) |
||
127 | Sys_Error ("Demo message > MAX_MSGLEN"); |
||
128 | r = fread (net_message.data, net_message.cursize, 1, cls.demofile); |
||
129 | if (r != 1) |
||
130 | { |
||
131 | CL_StopPlayback (); |
||
132 | return 0; |
||
133 | } |
||
134 | |||
135 | return 1; |
||
136 | } |
||
137 | |||
138 | while (1) |
||
139 | { |
||
140 | r = NET_GetMessage (cls.netcon); |
||
141 | |||
142 | if (r != 1 && r != 2) |
||
143 | return r; |
||
144 | |||
145 | // discard nop keepalive message |
||
146 | if (net_message.cursize == 1 && net_message.data[0] == svc_nop) |
||
147 | Con_Printf ("<-- server to client keepalive\n"); |
||
148 | else |
||
149 | break; |
||
150 | } |
||
151 | |||
152 | if (cls.demorecording) |
||
153 | CL_WriteDemoMessage (); |
||
154 | |||
155 | return r; |
||
156 | } |
||
157 | |||
158 | |||
159 | /* |
||
160 | ==================== |
||
161 | CL_Stop_f |
||
162 | |||
163 | stop recording a demo |
||
164 | ==================== |
||
165 | */ |
||
166 | void CL_Stop_f (void) |
||
167 | { |
||
168 | if (cmd_source != src_command) |
||
169 | return; |
||
170 | |||
171 | if (!cls.demorecording) |
||
172 | { |
||
173 | Con_Printf ("Not recording a demo.\n"); |
||
174 | return; |
||
175 | } |
||
176 | |||
177 | // write a disconnect message to the demo file |
||
178 | SZ_Clear (&net_message); |
||
179 | MSG_WriteByte (&net_message, svc_disconnect); |
||
180 | CL_WriteDemoMessage (); |
||
181 | |||
182 | // finish up |
||
183 | fclose (cls.demofile); |
||
184 | cls.demofile = NULL; |
||
185 | cls.demorecording = false; |
||
186 | Con_Printf ("Completed demo\n"); |
||
187 | } |
||
188 | |||
189 | /* |
||
190 | ==================== |
||
191 | CL_Record_f |
||
192 | |||
193 | record |
||
194 | ==================== |
||
195 | */ |
||
196 | void CL_Record_f (void) |
||
197 | { |
||
198 | int c; |
||
199 | char name[MAX_OSPATH]; |
||
200 | int track; |
||
201 | |||
202 | if (cmd_source != src_command) |
||
203 | return; |
||
204 | |||
205 | c = Cmd_Argc(); |
||
206 | if (c != 2 && c != 3 && c != 4) |
||
207 | { |
||
208 | Con_Printf ("record |
||
209 | return; |
||
210 | } |
||
211 | |||
212 | if (strstr(Cmd_Argv(1), "..")) |
||
213 | { |
||
214 | Con_Printf ("Relative pathnames are not allowed.\n"); |
||
215 | return; |
||
216 | } |
||
217 | |||
218 | if (c == 2 && cls.state == ca_connected) |
||
219 | { |
||
220 | Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); |
||
221 | return; |
||
222 | } |
||
223 | |||
224 | // write the forced cd track number, or -1 |
||
225 | if (c == 4) |
||
226 | { |
||
227 | track = atoi(Cmd_Argv(3)); |
||
228 | Con_Printf ("Forcing CD track to %i\n", cls.forcetrack); |
||
229 | } |
||
230 | else |
||
231 | track = -1; |
||
232 | |||
233 | sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); |
||
234 | |||
235 | // |
||
236 | // start the map up |
||
237 | // |
||
238 | if (c > 2) |
||
239 | Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command); |
||
240 | |||
241 | // |
||
242 | // open the demo file |
||
243 | // |
||
244 | COM_DefaultExtension (name, ".dem"); |
||
245 | |||
246 | Con_Printf ("recording to %s.\n", name); |
||
247 | cls.demofile = fopen (name, "wb"); |
||
248 | if (!cls.demofile) |
||
249 | { |
||
250 | Con_Printf ("ERROR: couldn't open.\n"); |
||
251 | return; |
||
252 | } |
||
253 | |||
254 | cls.forcetrack = track; |
||
255 | fprintf (cls.demofile, "%i\n", cls.forcetrack); |
||
256 | |||
257 | cls.demorecording = true; |
||
258 | } |
||
259 | |||
260 | |||
261 | /* |
||
262 | ==================== |
||
263 | CL_PlayDemo_f |
||
264 | |||
265 | play [demoname] |
||
266 | ==================== |
||
267 | */ |
||
268 | void CL_PlayDemo_f (void) |
||
269 | { |
||
270 | char name[256]; |
||
271 | int c; |
||
272 | qboolean neg = false; |
||
273 | |||
274 | if (cmd_source != src_command) |
||
275 | return; |
||
276 | |||
277 | if (Cmd_Argc() != 2) |
||
278 | { |
||
279 | Con_Printf ("play |
||
280 | return; |
||
281 | } |
||
282 | |||
283 | // |
||
284 | // disconnect from server |
||
285 | // |
||
286 | CL_Disconnect (); |
||
287 | |||
288 | // |
||
289 | // open the demo file |
||
290 | // |
||
291 | strcpy (name, Cmd_Argv(1)); |
||
292 | COM_DefaultExtension (name, ".dem"); |
||
293 | |||
294 | Con_Printf ("Playing demo from %s.\n", name); |
||
295 | COM_FOpenFile (name, &cls.demofile); |
||
296 | if (!cls.demofile) |
||
297 | { |
||
298 | Con_Printf ("ERROR: couldn't open.\n"); |
||
299 | cls.demonum = -1; // stop demo loop |
||
300 | return; |
||
301 | } |
||
302 | |||
303 | cls.demoplayback = true; |
||
304 | cls.state = ca_connected; |
||
305 | cls.forcetrack = 0; |
||
306 | |||
307 | while ((c = getc(cls.demofile)) != '\n') |
||
308 | if (c == '-') |
||
309 | neg = true; |
||
310 | else |
||
311 | cls.forcetrack = cls.forcetrack * 10 + (c - '0'); |
||
312 | |||
313 | if (neg) |
||
314 | cls.forcetrack = -cls.forcetrack; |
||
315 | // ZOID, fscanf is evil |
||
316 | // fscanf (cls.demofile, "%i\n", &cls.forcetrack); |
||
317 | } |
||
318 | |||
319 | /* |
||
320 | ==================== |
||
321 | CL_FinishTimeDemo |
||
322 | |||
323 | ==================== |
||
324 | */ |
||
325 | void CL_FinishTimeDemo (void) |
||
326 | { |
||
327 | int frames; |
||
328 | float time; |
||
329 | |||
330 | cls.timedemo = false; |
||
331 | |||
332 | // the first frame didn't count |
||
333 | frames = (host_framecount - cls.td_startframe) - 1; |
||
334 | time = realtime - cls.td_starttime; |
||
335 | if (!time) |
||
336 | time = 1; |
||
337 | Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time); |
||
338 | } |
||
339 | |||
340 | /* |
||
341 | ==================== |
||
342 | CL_TimeDemo_f |
||
343 | |||
344 | timedemo [demoname] |
||
345 | ==================== |
||
346 | */ |
||
347 | void CL_TimeDemo_f (void) |
||
348 | { |
||
349 | if (cmd_source != src_command) |
||
350 | return; |
||
351 | |||
352 | if (Cmd_Argc() != 2) |
||
353 | { |
||
354 | Con_Printf ("timedemo |
||
355 | return; |
||
356 | } |
||
357 | |||
358 | CL_PlayDemo_f (); |
||
359 | |||
360 | // cls.td_starttime will be grabbed at the second frame of the demo, so |
||
361 | // all the loading time doesn't get counted |
||
362 | |||
363 | cls.timedemo = true; |
||
364 | cls.td_startframe = host_framecount; |
||
365 | cls.td_lastframe = -1; // get a new message this frame |
||
366 | }-->3>=>3> |
||
367 |