123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #ifndef __USERCMDGEN_H__
- #define __USERCMDGEN_H__
- #include "../sys/sys_session.h"
- /*
- ===============================================================================
- Samples a set of user commands from player input.
- ===============================================================================
- */
- // usercmd_t->button bits
- const int BUTTON_ATTACK = BIT(0);
- const int BUTTON_RUN = BIT(1);
- const int BUTTON_ZOOM = BIT(2);
- const int BUTTON_SCORES = BIT(3);
- const int BUTTON_USE = BIT(4);
- const int BUTTON_JUMP = BIT(5);
- const int BUTTON_CROUCH = BIT(6);
- const int BUTTON_CHATTING = BIT(7);
- // usercmd_t->impulse commands
- const int IMPULSE_0 = 0; // weap 0
- const int IMPULSE_1 = 1; // weap 1
- const int IMPULSE_2 = 2; // weap 2
- const int IMPULSE_3 = 3; // weap 3
- const int IMPULSE_4 = 4; // weap 4
- const int IMPULSE_5 = 5; // weap 5
- const int IMPULSE_6 = 6; // weap 6
- const int IMPULSE_7 = 7; // weap 7
- const int IMPULSE_8 = 8; // weap 8
- const int IMPULSE_9 = 9; // weap 9
- const int IMPULSE_10 = 10; // weap 10
- const int IMPULSE_11 = 11; // weap 11
- const int IMPULSE_12 = 12; // weap 12
- const int IMPULSE_13 = 13; // weap reload
- const int IMPULSE_14 = 14; // weap next
- const int IMPULSE_15 = 15; // weap prev
- const int IMPULSE_16 = 16; // toggle flashlight on/off
- const int IMPULSE_18 = 18; // center view
- const int IMPULSE_19 = 19; // show PDA/SCORES
- const int IMPULSE_22 = 22; // spectate
- const int IMPULSE_25 = 25; // Envirosuit light
- const int IMPULSE_27 = 27; // Chainsaw
- const int IMPULSE_28 = 28; // quick 0
- const int IMPULSE_29 = 29; // quick 1
- const int IMPULSE_30 = 30; // quick 2
- const int IMPULSE_31 = 31; // quick 3
- class usercmd_t {
- public:
- usercmd_t() :
- forwardmove(),
- rightmove(),
- buttons(),
- clientGameMilliseconds( 0 ),
- serverGameMilliseconds( 0 ),
- fireCount( 0 ),
- mx(),
- my(),
- impulse(),
- impulseSequence(),
- pos( 0.0f, 0.0f, 0.0f ),
- speedSquared( 0.0f )
- {
- angles[0] = 0;
- angles[1] = 0;
- angles[2] = 0;
- }
- // Syncronized
- short angles[3]; // view angles
- signed char forwardmove; // forward/backward movement
- signed char rightmove; // left/right movement
- byte buttons; // buttons
- int clientGameMilliseconds; // time this usercmd was sent from the client
- int serverGameMilliseconds; // interpolated server time this was applied on
- uint16 fireCount; // number of times we've fired
- // Not syncronized
- byte impulse; // impulse command
- byte impulseSequence; // incremented every time there's a new impulse
- short mx; // mouse delta x
- short my; // mouse delta y
- // Clients are authoritative on their positions
- idVec3 pos;
- float speedSquared;
- public:
- void Serialize( class idSerializer & s, const usercmd_t & base );
- void ByteSwap(); // on big endian systems, byte swap the shorts and ints
- bool operator==( const usercmd_t &rhs ) const;
- };
- typedef enum {
- INHIBIT_SESSION = 0,
- INHIBIT_ASYNC
- } inhibit_t;
- typedef enum {
- UB_NONE,
- UB_MOVEUP,
- UB_MOVEDOWN,
- UB_LOOKLEFT,
- UB_LOOKRIGHT,
- UB_MOVEFORWARD,
- UB_MOVEBACK,
- UB_LOOKUP,
- UB_LOOKDOWN,
- UB_MOVELEFT,
- UB_MOVERIGHT,
- UB_ATTACK,
- UB_SPEED,
- UB_ZOOM,
- UB_SHOWSCORES,
- UB_USE,
- UB_IMPULSE0,
- UB_IMPULSE1,
- UB_IMPULSE2,
- UB_IMPULSE3,
- UB_IMPULSE4,
- UB_IMPULSE5,
- UB_IMPULSE6,
- UB_IMPULSE7,
- UB_IMPULSE8,
- UB_IMPULSE9,
- UB_IMPULSE10,
- UB_IMPULSE11,
- UB_IMPULSE12,
- UB_IMPULSE13,
- UB_IMPULSE14,
- UB_IMPULSE15,
- UB_IMPULSE16,
- UB_IMPULSE17,
- UB_IMPULSE18,
- UB_IMPULSE19,
- UB_IMPULSE20,
- UB_IMPULSE21,
- UB_IMPULSE22,
- UB_IMPULSE23,
- UB_IMPULSE24,
- UB_IMPULSE25,
- UB_IMPULSE26,
- UB_IMPULSE27,
- UB_IMPULSE28,
- UB_IMPULSE29,
- UB_IMPULSE30,
- UB_IMPULSE31,
- UB_MAX_BUTTONS
- } usercmdButton_t;
- typedef struct {
- const char *string;
- usercmdButton_t button;
- } userCmdString_t;
- class idUsercmdGen {
- public:
- virtual ~idUsercmdGen() {}
- // Sets up all the cvars and console commands.
- virtual void Init() = 0;
- // Prepares for a new map.
- virtual void InitForNewMap() = 0;
- // Shut down.
- virtual void Shutdown() = 0;
- // Clears all key states and face straight.
- virtual void Clear() = 0;
- // Clears view angles.
- virtual void ClearAngles() = 0;
- // When the console is down or the menu is up, only emit default usercmd, so the player isn't moving around.
- // Each subsystem (session and game) may want an inhibit will OR the requests.
- virtual void InhibitUsercmd( inhibit_t subsystem, bool inhibit ) = 0;
- // Set a value that can safely be referenced by UsercmdInterrupt() for each key binding.
- virtual int CommandStringUsercmdData( const char *cmdString ) = 0;
- // Continuously modified, never reset. For full screen guis.
- virtual void MouseState( int *x, int *y, int *button, bool *down ) = 0;
- // Directly sample a button.
- virtual int ButtonState( int key ) = 0;
- // Directly sample a keystate.
- virtual int KeyState( int key ) = 0;
- // called at vsync time
- virtual void BuildCurrentUsercmd( int deviceNum ) = 0;
- // return the current usercmd
- virtual usercmd_t GetCurrentUsercmd() = 0;
- };
- extern idUsercmdGen *usercmdGen;
- extern userCmdString_t userCmdStrings[];
- /*
- ================================================
- idUserCmdMgr
- ================================================
- */
- class idUserCmdMgr {
- public:
- idUserCmdMgr() {
- SetDefaults();
- }
-
- void SetDefaults() {
- for ( int i = 0; i < cmdBuffer.Num(); ++i ) {
- cmdBuffer[i].Zero();
- }
- writeFrame.Zero();
- readFrame.Memset( -1 );
- }
- // Set to 128 for now
- // Temp fix for usercmds overflowing Correct fix is to process usercmds as they come in (like q3), rather then buffer them up.
- static const int USERCMD_BUFFER_SIZE = 128;
-
- //usercmd_t cmdBuffer[ USERCMD_BUFFER_SIZE ][ MAX_PLAYERS ];
- id2DArray< usercmd_t, USERCMD_BUFFER_SIZE, MAX_PLAYERS >::type cmdBuffer;
- idArray< int, MAX_PLAYERS > writeFrame; //"where we write to next"
- idArray< int, MAX_PLAYERS > readFrame; //"the last frame we read"
-
- void PutUserCmdForPlayer( int playerIndex, const usercmd_t & cmd ) {
- cmdBuffer[ writeFrame[ playerIndex ] % USERCMD_BUFFER_SIZE ][ playerIndex ] = cmd;
- if ( writeFrame[ playerIndex ] - readFrame[ playerIndex ] + 1 > USERCMD_BUFFER_SIZE ) {
- 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
- idLib::Printf( "PutUserCmdForPlayer: buffer overflow.\n" );
- }
- writeFrame[ playerIndex ]++;
- }
- void ResetPlayer( int playerIndex ) {
- for ( int i = 0; i < USERCMD_BUFFER_SIZE; i++ ) {
- memset( &cmdBuffer[i][playerIndex], 0, sizeof( usercmd_t ) );
- }
- writeFrame[ playerIndex ] = 0;
- readFrame[ playerIndex ] = -1;
- }
- bool HasUserCmdForPlayer( int playerIndex, int buffer=0 ) const {
- // return true if the last frame we read from (+ buffer) is < the last frame we wrote to
- // (remember writeFrame is where we write to *next*. readFrame is where we last read from last)
- bool hasCmd = ( readFrame[ playerIndex ] + buffer < writeFrame[playerIndex] - 1 );
- return hasCmd;
- }
- bool HasUserCmdForClientTimeBuffer( int playerIndex, int millisecondBuffer ) {
- // return true if there is at least one command in addition to enough
- // commands to cover the buffer.
- if ( millisecondBuffer == 0 ) {
- return HasUserCmdForPlayer( playerIndex );
- }
- if ( GetNumUnreadFrames( playerIndex ) < 2 ) {
- return false;
- }
-
- const int index = readFrame[ playerIndex ] + 1;
- const usercmd_t & firstCmd = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
- const usercmd_t & lastCmd = NewestUserCmdForPlayer( playerIndex );
- const int timeDelta = lastCmd.clientGameMilliseconds - firstCmd.clientGameMilliseconds;
- const bool isTimeGreaterThanBuffer = timeDelta > millisecondBuffer;
- return isTimeGreaterThanBuffer;
- }
- const usercmd_t & NewestUserCmdForPlayer( int playerIndex ) {
- int index = Max( writeFrame[ playerIndex ] - 1, 0 );
- return cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
- }
-
- const usercmd_t & GetUserCmdForPlayer( int playerIndex ) {
- //Get the next cmd we should process (not necessarily the newest)
- //Note we may have multiple reads for every write .
- //We want to:
- // A) never skip over a cmd (unless we call MakeReadPtrCurrentForPlayer() ).
- // B) never get ahead of the writeFrame
-
- //try to increment before reading (without this we may read the same input twice
- //and be a frame behind our writes in the case of)
- if ( readFrame[ playerIndex ] < writeFrame[ playerIndex ] - 1 ) {
- readFrame[ playerIndex ]++;
- }
- //grab the next command in the readFrame buffer
- int index = readFrame[ playerIndex ];
- usercmd_t & result = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
- return result;
- }
-
- int GetNextUserCmdClientTime( int playerIndex ) const {
- if ( !HasUserCmdForPlayer( playerIndex ) ) {
- return 0;
- }
- const int index = readFrame[ playerIndex ] + 1;
- const usercmd_t & cmd = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
- return cmd.clientGameMilliseconds;
- }
- // Hack to let the player inject his position into the correct usercmd.
- usercmd_t & GetWritableUserCmdForPlayer( int playerIndex ) {
- //Get the next cmd we should process (not necessarily the newest)
- //Note we may have multiple reads for every write .
- //We want to:
- // A) never skip over a cmd (unless we call MakeReadPtrCurrentForPlayer() ).
- // B) never get ahead of the writeFrame
-
- //try to increment before reading (without this we may read the same input twice
- //and be a frame behind our writes in the case of)
- if ( readFrame[ playerIndex ] < writeFrame[ playerIndex ] - 1 ) {
- readFrame[ playerIndex ]++;
- }
- //grab the next command in the readFrame buffer
- int index = readFrame[ playerIndex ];
- usercmd_t & result = cmdBuffer[ index % USERCMD_BUFFER_SIZE ][ playerIndex ];
- return result;
- }
- void MakeReadPtrCurrentForPlayer( int playerIndex ) {
- //forces us to the head of our read buffer. As if we have processed every cmd available to us and now HasUserCmdForPlayer() returns FALSE
- //Note we do -1 to point us to the last written cmd.
- //If a read before the next write, you will get the last write. (not garbage)
- //If a write is made before the next read, you *will* get the new write ( b/c GetUserCmdForPlayer pre increments)
- //After calling this, HasUserCmdForPlayer() will return FALSE;
- readFrame[ playerIndex ] = writeFrame[ playerIndex ] - 1;
- }
- void SkipBufferedCmdsForPlayer( int playerIndex ) {
- // Similar to MakeReadPtrCurrentForPlayer, except:
- // -After calling this, HasUserCmdForPlayer() will return TRUE iff there was >= 1 fresh cmd in the buffer
- // Also, If there are no fresh frames, we wont roll the readFrame back
- readFrame[ playerIndex ] = Max( readFrame[ playerIndex ], writeFrame[ playerIndex ] - 2 );
- }
- int GetNumUnreadFrames( int playerIndex ) {
- return (writeFrame[ playerIndex ] - 1) - readFrame[ playerIndex ];
- }
-
- int GetPlayerCmds( int user, usercmd_t ** buffer, const int bufferSize ) {
- // Fallback to getting cmds from the userCmdMgr
- int start = Max( writeFrame[user] - Min( bufferSize, USERCMD_BUFFER_SIZE ), 0 );
- int numCmds = writeFrame[user] - start;
- for ( int i = 0; i < numCmds; i++ ) {
- int index = ( start + i ) % USERCMD_BUFFER_SIZE;
- buffer[i] = &cmdBuffer[ index ][ user ];
- }
- return numCmds;
- }
- };
- #endif /* !__USERCMDGEN_H__ */
|