Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 <demoname> <map> [cd track]
  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 <demoname> [<map> [cd track]]\n");
  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 <demoname> : plays a demo\n");
  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 <demoname> : gets demo speeds\n");
  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. }
  367.  
  368.