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