UsercmdGen.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #ifndef __USERCMDGEN_H__
  21. #define __USERCMDGEN_H__
  22. #include "../sys/sys_session.h"
  23. /*
  24. ===============================================================================
  25. Samples a set of user commands from player input.
  26. ===============================================================================
  27. */
  28. // usercmd_t->button bits
  29. const int BUTTON_ATTACK = BIT(0);
  30. const int BUTTON_RUN = BIT(1);
  31. const int BUTTON_ZOOM = BIT(2);
  32. const int BUTTON_SCORES = BIT(3);
  33. const int BUTTON_USE = BIT(4);
  34. const int BUTTON_JUMP = BIT(5);
  35. const int BUTTON_CROUCH = BIT(6);
  36. const int BUTTON_CHATTING = BIT(7);
  37. // usercmd_t->impulse commands
  38. const int IMPULSE_0 = 0; // weap 0
  39. const int IMPULSE_1 = 1; // weap 1
  40. const int IMPULSE_2 = 2; // weap 2
  41. const int IMPULSE_3 = 3; // weap 3
  42. const int IMPULSE_4 = 4; // weap 4
  43. const int IMPULSE_5 = 5; // weap 5
  44. const int IMPULSE_6 = 6; // weap 6
  45. const int IMPULSE_7 = 7; // weap 7
  46. const int IMPULSE_8 = 8; // weap 8
  47. const int IMPULSE_9 = 9; // weap 9
  48. const int IMPULSE_10 = 10; // weap 10
  49. const int IMPULSE_11 = 11; // weap 11
  50. const int IMPULSE_12 = 12; // weap 12
  51. const int IMPULSE_13 = 13; // weap reload
  52. const int IMPULSE_14 = 14; // weap next
  53. const int IMPULSE_15 = 15; // weap prev
  54. const int IMPULSE_16 = 16; // toggle flashlight on/off
  55. const int IMPULSE_18 = 18; // center view
  56. const int IMPULSE_19 = 19; // show PDA/SCORES
  57. const int IMPULSE_22 = 22; // spectate
  58. const int IMPULSE_25 = 25; // Envirosuit light
  59. const int IMPULSE_27 = 27; // Chainsaw
  60. const int IMPULSE_28 = 28; // quick 0
  61. const int IMPULSE_29 = 29; // quick 1
  62. const int IMPULSE_30 = 30; // quick 2
  63. const int IMPULSE_31 = 31; // quick 3
  64. class usercmd_t {
  65. public:
  66. usercmd_t() :
  67. forwardmove(),
  68. rightmove(),
  69. buttons(),
  70. clientGameMilliseconds( 0 ),
  71. serverGameMilliseconds( 0 ),
  72. fireCount( 0 ),
  73. mx(),
  74. my(),
  75. impulse(),
  76. impulseSequence(),
  77. pos( 0.0f, 0.0f, 0.0f ),
  78. speedSquared( 0.0f )
  79. {
  80. angles[0] = 0;
  81. angles[1] = 0;
  82. angles[2] = 0;
  83. }
  84. // Syncronized
  85. short angles[3]; // view angles
  86. signed char forwardmove; // forward/backward movement
  87. signed char rightmove; // left/right movement
  88. byte buttons; // buttons
  89. int clientGameMilliseconds; // time this usercmd was sent from the client
  90. int serverGameMilliseconds; // interpolated server time this was applied on
  91. uint16 fireCount; // number of times we've fired
  92. // Not syncronized
  93. byte impulse; // impulse command
  94. byte impulseSequence; // incremented every time there's a new impulse
  95. short mx; // mouse delta x
  96. short my; // mouse delta y
  97. // Clients are authoritative on their positions
  98. idVec3 pos;
  99. float speedSquared;
  100. public:
  101. void Serialize( class idSerializer & s, const usercmd_t & base );
  102. void ByteSwap(); // on big endian systems, byte swap the shorts and ints
  103. bool operator==( const usercmd_t &rhs ) const;
  104. };
  105. typedef enum {
  106. INHIBIT_SESSION = 0,
  107. INHIBIT_ASYNC
  108. } inhibit_t;
  109. typedef enum {
  110. UB_NONE,
  111. UB_MOVEUP,
  112. UB_MOVEDOWN,
  113. UB_LOOKLEFT,
  114. UB_LOOKRIGHT,
  115. UB_MOVEFORWARD,
  116. UB_MOVEBACK,
  117. UB_LOOKUP,
  118. UB_LOOKDOWN,
  119. UB_MOVELEFT,
  120. UB_MOVERIGHT,
  121. UB_ATTACK,
  122. UB_SPEED,
  123. UB_ZOOM,
  124. UB_SHOWSCORES,
  125. UB_USE,
  126. UB_IMPULSE0,
  127. UB_IMPULSE1,
  128. UB_IMPULSE2,
  129. UB_IMPULSE3,
  130. UB_IMPULSE4,
  131. UB_IMPULSE5,
  132. UB_IMPULSE6,
  133. UB_IMPULSE7,
  134. UB_IMPULSE8,
  135. UB_IMPULSE9,
  136. UB_IMPULSE10,
  137. UB_IMPULSE11,
  138. UB_IMPULSE12,
  139. UB_IMPULSE13,
  140. UB_IMPULSE14,
  141. UB_IMPULSE15,
  142. UB_IMPULSE16,
  143. UB_IMPULSE17,
  144. UB_IMPULSE18,
  145. UB_IMPULSE19,
  146. UB_IMPULSE20,
  147. UB_IMPULSE21,
  148. UB_IMPULSE22,
  149. UB_IMPULSE23,
  150. UB_IMPULSE24,
  151. UB_IMPULSE25,
  152. UB_IMPULSE26,
  153. UB_IMPULSE27,
  154. UB_IMPULSE28,
  155. UB_IMPULSE29,
  156. UB_IMPULSE30,
  157. UB_IMPULSE31,
  158. UB_MAX_BUTTONS
  159. } usercmdButton_t;
  160. typedef struct {
  161. const char *string;
  162. usercmdButton_t button;
  163. } userCmdString_t;
  164. class idUsercmdGen {
  165. public:
  166. virtual ~idUsercmdGen() {}
  167. // Sets up all the cvars and console commands.
  168. virtual void Init() = 0;
  169. // Prepares for a new map.
  170. virtual void InitForNewMap() = 0;
  171. // Shut down.
  172. virtual void Shutdown() = 0;
  173. // Clears all key states and face straight.
  174. virtual void Clear() = 0;
  175. // Clears view angles.
  176. virtual void ClearAngles() = 0;
  177. // When the console is down or the menu is up, only emit default usercmd, so the player isn't moving around.
  178. // Each subsystem (session and game) may want an inhibit will OR the requests.
  179. virtual void InhibitUsercmd( inhibit_t subsystem, bool inhibit ) = 0;
  180. // Set a value that can safely be referenced by UsercmdInterrupt() for each key binding.
  181. virtual int CommandStringUsercmdData( const char *cmdString ) = 0;
  182. // Continuously modified, never reset. For full screen guis.
  183. virtual void MouseState( int *x, int *y, int *button, bool *down ) = 0;
  184. // Directly sample a button.
  185. virtual int ButtonState( int key ) = 0;
  186. // Directly sample a keystate.
  187. virtual int KeyState( int key ) = 0;
  188. // called at vsync time
  189. virtual void BuildCurrentUsercmd( int deviceNum ) = 0;
  190. // return the current usercmd
  191. virtual usercmd_t GetCurrentUsercmd() = 0;
  192. };
  193. extern idUsercmdGen *usercmdGen;
  194. extern userCmdString_t userCmdStrings[];
  195. /*
  196. ================================================
  197. idUserCmdMgr
  198. ================================================
  199. */
  200. class idUserCmdMgr {
  201. public:
  202. idUserCmdMgr() {
  203. SetDefaults();
  204. }
  205. void SetDefaults() {
  206. for ( int i = 0; i < cmdBuffer.Num(); ++i ) {
  207. cmdBuffer[i].Zero();
  208. }
  209. writeFrame.Zero();
  210. readFrame.Memset( -1 );
  211. }
  212. // Set to 128 for now
  213. // Temp fix for usercmds overflowing Correct fix is to process usercmds as they come in (like q3), rather then buffer them up.
  214. static const int USERCMD_BUFFER_SIZE = 128;
  215. //usercmd_t cmdBuffer[ USERCMD_BUFFER_SIZE ][ MAX_PLAYERS ];
  216. id2DArray< usercmd_t, USERCMD_BUFFER_SIZE, MAX_PLAYERS >::type cmdBuffer;
  217. idArray< int, MAX_PLAYERS > writeFrame; //"where we write to next"
  218. idArray< int, MAX_PLAYERS > readFrame; //"the last frame we read"
  219. void PutUserCmdForPlayer( int playerIndex, const usercmd_t & cmd ) {
  220. cmdBuffer[ writeFrame[ playerIndex ] % USERCMD_BUFFER_SIZE ][ playerIndex ] = cmd;
  221. if ( writeFrame[ playerIndex ] - readFrame[ playerIndex ] + 1 > USERCMD_BUFFER_SIZE ) {
  222. readFrame[ playerIndex ] = writeFrame[ playerIndex ] - USERCMD_BUFFER_SIZE / 2; // Set to middle of buffer as a temp fix until we can catch the client up correctly
  223. idLib::Printf( "PutUserCmdForPlayer: buffer overflow.\n" );
  224. }
  225. writeFrame[ playerIndex ]++;
  226. }
  227. void ResetPlayer( int playerIndex ) {
  228. for ( int i = 0; i < USERCMD_BUFFER_SIZE; i++ ) {
  229. memset( &cmdBuffer[i][playerIndex], 0, sizeof( usercmd_t ) );
  230. }
  231. writeFrame[ playerIndex ] = 0;
  232. readFrame[ playerIndex ] = -1;
  233. }
  234. bool HasUserCmdForPlayer( int playerIndex, int buffer=0 ) const {
  235. // return true if the last frame we read from (+ buffer) is < the last frame we wrote to
  236. // (remember writeFrame is where we write to *next*. readFrame is where we last read from last)
  237. bool hasCmd = ( readFrame[ playerIndex ] + buffer < writeFrame[playerIndex] - 1 );
  238. return hasCmd;
  239. }
  240. bool HasUserCmdForClientTimeBuffer( int playerIndex, int millisecondBuffer ) {
  241. // return true if there is at least one command in addition to enough
  242. // commands to cover the buffer.
  243. if ( millisecondBuffer == 0 ) {
  244. return HasUserCmdForPlayer( playerIndex );
  245. }
  246. if ( GetNumUnreadFrames( playerIndex ) < 2 ) {
  247. return false;
  248. }
  249. const int index = readFrame[ playerIndex ] + 1;
  250. const usercmd_t & firstCmd = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
  251. const usercmd_t & lastCmd = NewestUserCmdForPlayer( playerIndex );
  252. const int timeDelta = lastCmd.clientGameMilliseconds - firstCmd.clientGameMilliseconds;
  253. const bool isTimeGreaterThanBuffer = timeDelta > millisecondBuffer;
  254. return isTimeGreaterThanBuffer;
  255. }
  256. const usercmd_t & NewestUserCmdForPlayer( int playerIndex ) {
  257. int index = Max( writeFrame[ playerIndex ] - 1, 0 );
  258. return cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
  259. }
  260. const usercmd_t & GetUserCmdForPlayer( int playerIndex ) {
  261. //Get the next cmd we should process (not necessarily the newest)
  262. //Note we may have multiple reads for every write .
  263. //We want to:
  264. // A) never skip over a cmd (unless we call MakeReadPtrCurrentForPlayer() ).
  265. // B) never get ahead of the writeFrame
  266. //try to increment before reading (without this we may read the same input twice
  267. //and be a frame behind our writes in the case of)
  268. if ( readFrame[ playerIndex ] < writeFrame[ playerIndex ] - 1 ) {
  269. readFrame[ playerIndex ]++;
  270. }
  271. //grab the next command in the readFrame buffer
  272. int index = readFrame[ playerIndex ];
  273. usercmd_t & result = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
  274. return result;
  275. }
  276. int GetNextUserCmdClientTime( int playerIndex ) const {
  277. if ( !HasUserCmdForPlayer( playerIndex ) ) {
  278. return 0;
  279. }
  280. const int index = readFrame[ playerIndex ] + 1;
  281. const usercmd_t & cmd = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
  282. return cmd.clientGameMilliseconds;
  283. }
  284. // Hack to let the player inject his position into the correct usercmd.
  285. usercmd_t & GetWritableUserCmdForPlayer( int playerIndex ) {
  286. //Get the next cmd we should process (not necessarily the newest)
  287. //Note we may have multiple reads for every write .
  288. //We want to:
  289. // A) never skip over a cmd (unless we call MakeReadPtrCurrentForPlayer() ).
  290. // B) never get ahead of the writeFrame
  291. //try to increment before reading (without this we may read the same input twice
  292. //and be a frame behind our writes in the case of)
  293. if ( readFrame[ playerIndex ] < writeFrame[ playerIndex ] - 1 ) {
  294. readFrame[ playerIndex ]++;
  295. }
  296. //grab the next command in the readFrame buffer
  297. int index = readFrame[ playerIndex ];
  298. usercmd_t & result = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
  299. return result;
  300. }
  301. void MakeReadPtrCurrentForPlayer( int playerIndex ) {
  302. //forces us to the head of our read buffer. As if we have processed every cmd available to us and now HasUserCmdForPlayer() returns FALSE
  303. //Note we do -1 to point us to the last written cmd.
  304. //If a read before the next write, you will get the last write. (not garbage)
  305. //If a write is made before the next read, you *will* get the new write ( b/c GetUserCmdForPlayer pre increments)
  306. //After calling this, HasUserCmdForPlayer() will return FALSE;
  307. readFrame[ playerIndex ] = writeFrame[ playerIndex ] - 1;
  308. }
  309. void SkipBufferedCmdsForPlayer( int playerIndex ) {
  310. // Similar to MakeReadPtrCurrentForPlayer, except:
  311. // -After calling this, HasUserCmdForPlayer() will return TRUE iff there was >= 1 fresh cmd in the buffer
  312. // Also, If there are no fresh frames, we wont roll the readFrame back
  313. readFrame[ playerIndex ] = Max( readFrame[ playerIndex ], writeFrame[ playerIndex ] - 2 );
  314. }
  315. int GetNumUnreadFrames( int playerIndex ) {
  316. return (writeFrame[ playerIndex ] - 1) - readFrame[ playerIndex ];
  317. }
  318. int GetPlayerCmds( int user, usercmd_t ** buffer, const int bufferSize ) {
  319. // Fallback to getting cmds from the userCmdMgr
  320. int start = Max( writeFrame[user] - Min( bufferSize, USERCMD_BUFFER_SIZE ), 0 );
  321. int numCmds = writeFrame[user] - start;
  322. for ( int i = 0; i < numCmds; i++ ) {
  323. int index = ( start + i ) % USERCMD_BUFFER_SIZE;
  324. buffer[i] = &cmdBuffer[ index ][ user ];
  325. }
  326. return numCmds;
  327. }
  328. };
  329. #endif /* !__USERCMDGEN_H__ */