/* =========================================================================== 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 . 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 __SYS_LOBBY_BACKEND_H__ #define __SYS_LOBBY_BACKEND_H__ extern idCVar net_verboseResource; #define NET_VERBOSERESOURCE_PRINT if ( net_verboseResource.GetBool() ) idLib::Printf extern idCVar net_verbose; #define NET_VERBOSE_PRINT if ( net_verbose.GetBool() ) idLib::Printf class lobbyAddress_t { public: lobbyAddress_t(); void InitFromNetadr( const netadr_t & netadr ); void InitFromIPandPort( const char * ip, int port ); const char * ToString() const; bool UsingRelay() const; bool Compare( const lobbyAddress_t & addr, bool ignoreSessionCheck = false ) const; void WriteToMsg( idBitMsg & msg ) const; void ReadFromMsg( idBitMsg & msg ); // IP address netadr_t netAddr; }; struct lobbyConnectInfo_t { public: void WriteToMsg( idBitMsg & msg ) const { msg.WriteNetadr( netAddr ); } void ReadFromMsg( idBitMsg & msg ) { msg.ReadNetadr( &netAddr ); } lobbyConnectInfo_t() : netAddr() { } netadr_t netAddr; }; class idNetSessionPort { public: idNetSessionPort(); bool InitPort( int portNumber, bool useBackend ); bool ReadRawPacket( lobbyAddress_t & from, void * data, int & size, int maxSize ); void SendRawPacket( const lobbyAddress_t & to, const void * data, int size ); bool IsOpen(); void Close(); private: float forcePacketDropCurr; // Used with net_forceDrop and net_forceDropCorrelation float forcePacketDropPrev; idUDP UDP; }; struct lobbyUser_t { static const int INVALID_PING = 9999; // gamertags can be up to 16 4-byte characters + \0 static const int MAX_GAMERTAG = 64 + 1; lobbyUser_t() { isBot = false; peerIndex = -1; disconnecting = false; level = 1; pingMs = INVALID_PING; teamNumber = 0; arbitrationAcked = false; partyToken = 0; selectedSkin = 0; weaponAutoSwitch = true; weaponAutoReload = true; migrationGameData = -1; } // Common variables bool isBot; // true if lobbyUser is a bot. int peerIndex; // peer number on host lobbyUserID_t lobbyUserID; // Locally generated to be unique, and internally keeps the local user handle char gamertag[MAX_GAMERTAG]; int pingMs; // round trip time in milliseconds bool disconnecting; // true if we've sent a msg to disconnect this user from the session int level; int teamNumber; uint32 partyToken; // set by the server when people join as a party int selectedSkin; bool weaponAutoSwitch; bool weaponAutoReload; bool arbitrationAcked; // if the user is verified for arbitration lobbyAddress_t address; int migrationGameData; // index into the local migration gamedata array that is associated with this user. -1=no migration game data available // Platform variables bool IsDisconnected() const { return lobbyUserID.IsValid() ? false : true; } void WriteToMsg( idBitMsg & msg ) { address.WriteToMsg( msg ); lobbyUserID.WriteToMsg( msg ); msg.WriteLong( peerIndex ); msg.WriteShort( pingMs ); msg.WriteLong( partyToken ); msg.WriteString( gamertag, MAX_GAMERTAG, false ); WriteClientMutableData( msg ); } void ReadFromMsg( idBitMsg & msg ) { address.ReadFromMsg( msg ); lobbyUserID.ReadFromMsg( msg ); peerIndex = msg.ReadLong(); pingMs = msg.ReadShort(); partyToken = msg.ReadLong(); msg.ReadString( gamertag, MAX_GAMERTAG ); ReadClientMutableData( msg ); } bool UpdateClientMutableData( const idLocalUser * localUser ); void WriteClientMutableData( idBitMsg & msg ) { msg.WriteBits( selectedSkin, 4 ); msg.WriteBits( teamNumber, 2 ); // We need two bits since we use team value of 2 for spectating msg.WriteBool( weaponAutoSwitch ); msg.WriteBool( weaponAutoReload ); release_assert( msg.GetWriteBit() == 0 ); } void ReadClientMutableData( idBitMsg & msg ) { selectedSkin = msg.ReadBits( 4 ); teamNumber = msg.ReadBits( 2 ); // We need two bits since we use team value of 2 for spectating weaponAutoSwitch = msg.ReadBool(); weaponAutoReload = msg.ReadBool(); } }; /* ================================================ idLobbyBackend This class interfaces with the various back ends for the different platforms ================================================ */ class idLobbyBackend { public: enum lobbyBackendState_t { STATE_INVALID = 0, STATE_READY = 1, STATE_CREATING = 2, // In the process of creating the lobby as a host STATE_SEARCHING = 3, // In the process of searching for a lobby to join STATE_OBTAINING_ADDRESS = 4, // In the process of obtaining the address of the lobby owner STATE_ARBITRATING = 5, // Arbitrating STATE_SHUTTING_DOWN = 6, // In the process of shutting down STATE_SHUTDOWN = 7, // Was a host or peer at one point, now ready to be deleted STATE_FAILED = 8, // Failure occurred NUM_STATES }; static const char * GetStateString( lobbyBackendState_t state_ ) { static const char * stateToString[NUM_STATES] = { "STATE_INVALID", "STATE_READY", "STATE_CREATING", "STATE_SEARCHING", "STATE_OBTAINING_ADDRESS", "STATE_ARBITRATING", "STATE_SHUTTING_DOWN", "STATE_SHUTDOWN", "STATE_FAILED" }; return stateToString[ state_ ]; } enum lobbyBackendType_t { TYPE_PARTY = 0, TYPE_GAME = 1, TYPE_GAME_STATE = 2, TYPE_INVALID = 0xff, }; idLobbyBackend() : type( TYPE_INVALID ), isHost( false ), isLocal( false ) {} idLobbyBackend( lobbyBackendType_t lobbyType ) : type( lobbyType ), isHost( false ), isLocal( false ) {} virtual void StartHosting( const idMatchParameters & p, float skillLevel, lobbyBackendType_t type ) = 0; virtual void StartFinding( const idMatchParameters & p, int numPartyUsers, float skillLevel ) = 0; virtual void JoinFromConnectInfo( const lobbyConnectInfo_t & connectInfo ) = 0; virtual void GetSearchResults( idList< lobbyConnectInfo_t > & searchResults ) = 0; virtual lobbyConnectInfo_t GetConnectInfo() = 0; virtual void FillMsgWithPostConnectInfo( idBitMsg & msg ) = 0; // Passed itno PostConnectFromMsg virtual void PostConnectFromMsg( idBitMsg & msg ) = 0; // Uses results from FillMsgWithPostConnectInfo virtual bool IsOwnerOfConnectInfo( const lobbyConnectInfo_t & connectInfo ) const { return false; } virtual void Shutdown() = 0; virtual void GetOwnerAddress( lobbyAddress_t & outAddr ) = 0; virtual bool IsHost() { return isHost; } virtual void SetIsJoinable( bool joinable ) {} virtual void Pump() = 0; virtual void UpdateMatchParms( const idMatchParameters & p ) = 0; virtual void UpdateLobbySkill( float lobbySkill ) = 0; virtual void SetInGame( bool value ) {} virtual lobbyBackendState_t GetState() = 0; virtual bool IsLocal() const { return isLocal; } virtual bool IsOnline() const { return !isLocal; } virtual bool StartArbitration() { return false; } virtual void Arbitrate() {} virtual void VerifyArbitration() {} virtual bool UserArbitrated( lobbyUser_t * user ) { return false; } virtual void RegisterUser( lobbyUser_t * user, bool isLocal ) {} virtual void UnregisterUser( lobbyUser_t * user, bool isLocal ) {} virtual void StartSession() {} virtual void EndSession() {} virtual bool IsSessionStarted() { return false; } virtual void FlushStats() {} virtual void BecomeHost( int numInvites ) {} // Become the host of this lobby virtual void RegisterAddress( lobbyAddress_t & address ) {} // Called after becoming a new host, to register old addresses to send invites to virtual void FinishBecomeHost() {} void SetLobbyType( lobbyBackendType_t lobbyType ) { type = lobbyType; } lobbyBackendType_t GetLobbyType() const { return type; } const char * GetLobbyTypeString() const { return ( GetLobbyType() == TYPE_PARTY ) ? "Party" : "Game"; } bool IsRanked() { return MatchTypeIsRanked( parms.matchFlags ); } bool IsPrivate() { return MatchTypeIsPrivate( parms.matchFlags ); } protected: lobbyBackendType_t type; idMatchParameters parms; bool isLocal; // True if this lobby is restricted to local play only (won't need and can't connect to online lobbies) bool isHost; // True if we created this lobby }; class idLobbyToSessionCB { public: virtual class idLobbyBackend * GetLobbyBackend( idLobbyBackend::lobbyBackendType_t type ) const = 0; virtual bool CanJoinLocalHost() const = 0; // Ugh, hate having to ifdef these, but we're doing some fairly platform specific callbacks }; #endif // __SYS_LOBBY_BACKEND_H__