summaryrefslogtreecommitdiff
path: root/serverbrowser/ServerBrowser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'serverbrowser/ServerBrowser.cpp')
-rw-r--r--serverbrowser/ServerBrowser.cpp489
1 files changed, 489 insertions, 0 deletions
diff --git a/serverbrowser/ServerBrowser.cpp b/serverbrowser/ServerBrowser.cpp
new file mode 100644
index 0000000..ff66bbb
--- /dev/null
+++ b/serverbrowser/ServerBrowser.cpp
@@ -0,0 +1,489 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "pch_serverbrowser.h"
+
+// expose the server browser interfaces
+CServerBrowser g_ServerBrowserSingleton;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerBrowser, IServerBrowser, SERVERBROWSER_INTERFACE_VERSION, g_ServerBrowserSingleton);
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerBrowser, IVGuiModule, "VGuiModuleServerBrowser001", g_ServerBrowserSingleton); // the interface loaded by PlatformMenu.vdf
+
+// singleton accessor
+CServerBrowser &ServerBrowser()
+{
+ return g_ServerBrowserSingleton;
+}
+
+IRunGameEngine *g_pRunGameEngine = NULL;
+
+static CSteamAPIContext g_SteamAPIContext;
+CSteamAPIContext *steamapicontext = &g_SteamAPIContext;
+
+IEngineReplay *g_pEngineReplay = NULL;
+
+ConVar sb_firstopentime( "sb_firstopentime", "0", FCVAR_DEVELOPMENTONLY, "Indicates the time the server browser was first opened." );
+ConVar sb_numtimesopened( "sb_numtimesopened", "0", FCVAR_DEVELOPMENTONLY, "Indicates the number of times the server browser was opened this session." );
+
+// the original author of this code felt strdup was not acceptible.
+inline char *CloneString( const char *str )
+{
+ char *cloneStr = new char [ strlen(str)+1 ];
+ strcpy( cloneStr, str );
+ return cloneStr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CServerBrowser::CServerBrowser()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CServerBrowser::~CServerBrowser()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerBrowser::CreateDialog()
+{
+ if (!m_hInternetDlg.Get())
+ {
+ m_hInternetDlg = new CServerBrowserDialog(NULL); // SetParent() call below fills this in
+ m_hInternetDlg->Initialize();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: links to vgui and engine interfaces
+//-----------------------------------------------------------------------------
+bool CServerBrowser::Initialize(CreateInterfaceFn *factorylist, int factoryCount)
+{
+ ConnectTier1Libraries( factorylist, factoryCount );
+ ConVar_Register();
+ ConnectTier2Libraries( factorylist, factoryCount );
+ ConnectTier3Libraries( factorylist, factoryCount );
+ g_pRunGameEngine = NULL;
+
+ for ( int i = 0; i < factoryCount; ++i )
+ {
+ if ( !g_pEngineReplay )
+ {
+ g_pEngineReplay = ( IEngineReplay * )factorylist[ i ]( ENGINE_REPLAY_INTERFACE_VERSION, NULL );
+ }
+ }
+
+ SteamAPI_InitSafe();
+ SteamAPI_SetTryCatchCallbacks( false ); // We don't use exceptions, so tell steam not to use try/catch in callback handlers
+ steamapicontext->Init();
+
+ for (int i = 0; i < factoryCount; i++)
+ {
+ if (!g_pRunGameEngine)
+ {
+ g_pRunGameEngine = (IRunGameEngine *)(factorylist[i])(RUNGAMEENGINE_INTERFACE_VERSION, NULL);
+ }
+ }
+
+ // load the vgui interfaces
+#if defined( STEAM ) || defined( HL1 )
+ if ( !vgui::VGuiControls_Init("ServerBrowser", factorylist, factoryCount) )
+#else
+ if ( !vgui::VGui_InitInterfacesList("ServerBrowser", factorylist, factoryCount) )
+#endif
+ return false;
+
+ // load localization file
+ g_pVGuiLocalize->AddFile( "servers/serverbrowser_%language%.txt" );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: links to other modules interfaces (tracker)
+//-----------------------------------------------------------------------------
+bool CServerBrowser::PostInitialize(CreateInterfaceFn *modules, int factoryCount)
+{
+ // find the interfaces we need
+ for (int i = 0; i < factoryCount; i++)
+ {
+ if (!g_pRunGameEngine)
+ {
+ g_pRunGameEngine = (IRunGameEngine *)(modules[i])(RUNGAMEENGINE_INTERFACE_VERSION, NULL);
+ }
+ }
+
+ CreateDialog();
+ m_hInternetDlg->SetVisible(false);
+
+ return g_pRunGameEngine;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: true if the user can't play a game due to VAC banning
+//-----------------------------------------------------------------------------
+bool CServerBrowser::IsVACBannedFromGame( int nAppID )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Marks that the tool/game loading us intends to feed us workshop information
+//-----------------------------------------------------------------------------
+void CServerBrowser::SetWorkshopEnabled( bool bManaged )
+{
+ m_bWorkshopEnabled = bManaged;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add a mapname to our known user-subscribed workshop maps list
+//-----------------------------------------------------------------------------
+void CServerBrowser::AddWorkshopSubscribedMap( const char *pszMapName )
+{
+ CUtlString strMap( pszMapName );
+ if ( !IsWorkshopSubscribedMap( strMap ) )
+ {
+ m_vecWorkshopSubscribedMaps.AddToTail( strMap );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: remove a mapname to our known user-subscribed workshop maps list
+//-----------------------------------------------------------------------------
+void CServerBrowser::RemoveWorkshopSubscribedMap( const char *pszMapName )
+{
+ m_vecWorkshopSubscribedMaps.FindAndFastRemove( CUtlString( pszMapName ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Well, is it?
+//-----------------------------------------------------------------------------
+bool CServerBrowser::IsWorkshopEnabled()
+{
+ return m_bWorkshopEnabled;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if this map is in our subscribed list
+//-----------------------------------------------------------------------------
+bool CServerBrowser::IsWorkshopSubscribedMap( const char *pszMapName )
+{
+ return m_vecWorkshopSubscribedMaps.HasElement( CUtlString( pszMapName ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CServerBrowser::IsValid()
+{
+ return ( g_pRunGameEngine );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CServerBrowser::Activate()
+{
+ static bool firstTimeOpening = true;
+ if ( firstTimeOpening )
+ {
+ m_hInternetDlg->LoadUserData(); // reload the user data the first time the dialog is made visible, helps with the lag between module load and
+ // steamui getting Deactivate() call
+ firstTimeOpening = false;
+ }
+
+ int numTimesOpened = sb_numtimesopened.GetInt() + 1;
+ sb_numtimesopened.SetValue( numTimesOpened );
+ if ( numTimesOpened == 1 )
+ {
+ time_t aclock;
+ time( &aclock );
+ sb_firstopentime.SetValue( (int) aclock );
+ }
+
+ Open();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the server browser gets used in the game
+//-----------------------------------------------------------------------------
+void CServerBrowser::Deactivate()
+{
+ if (m_hInternetDlg.Get())
+ {
+ m_hInternetDlg->SaveUserData();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the server browser is no longer being used in the game
+//-----------------------------------------------------------------------------
+void CServerBrowser::Reactivate()
+{
+ if (m_hInternetDlg.Get())
+ {
+ m_hInternetDlg->LoadUserData();
+ if (m_hInternetDlg->IsVisible())
+ {
+ m_hInternetDlg->RefreshCurrentPage();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerBrowser::Open()
+{
+ m_hInternetDlg->Open();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns direct handle to main server browser dialog
+//-----------------------------------------------------------------------------
+vgui::VPANEL CServerBrowser::GetPanel()
+{
+ return m_hInternetDlg.Get() ? m_hInternetDlg->GetVPanel() : NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the parent panel of the main module panel
+//-----------------------------------------------------------------------------
+void CServerBrowser::SetParent(vgui::VPANEL parent)
+{
+ if (m_hInternetDlg.Get())
+ {
+ m_hInternetDlg->SetParent(parent);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Closes down the server browser for good
+//-----------------------------------------------------------------------------
+void CServerBrowser::Shutdown()
+{
+ if (m_hInternetDlg.Get())
+ {
+ m_hInternetDlg->Close();
+ m_hInternetDlg->MarkForDeletion();
+ }
+
+#if defined( STEAM )
+ vgui::VGuiControls_Shutdown();
+#endif
+
+ DisconnectTier3Libraries();
+ DisconnectTier2Libraries();
+ ConVar_Unregister();
+ DisconnectTier1Libraries();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: opens a game info dialog to watch the specified server; associated with the friend 'userName'
+//-----------------------------------------------------------------------------
+bool CServerBrowser::OpenGameInfoDialog( uint64 ulSteamIDFriend, const char *pszConnectCode )
+{
+#if !defined( _X360 ) // X360TBD: SteamFriends()
+ if ( m_hInternetDlg.Get() )
+ {
+ // activate an already-existing dialog
+ CDialogGameInfo *pDialogGameInfo = m_hInternetDlg->GetDialogGameInfoForFriend( ulSteamIDFriend );
+ if ( pDialogGameInfo )
+ {
+ pDialogGameInfo->Activate();
+ return true;
+ }
+
+ // none yet, create a new dialog
+ FriendGameInfo_t friendGameInfo;
+ if ( steamapicontext->SteamFriends()->GetFriendGamePlayed( ulSteamIDFriend, &friendGameInfo ) )
+ {
+ uint16 usConnPort = friendGameInfo.m_usGamePort;
+ if ( friendGameInfo.m_usQueryPort < QUERY_PORT_ERROR )
+ usConnPort = friendGameInfo.m_usQueryPort;
+ CDialogGameInfo *pDialogGameInfo = m_hInternetDlg->OpenGameInfoDialog( friendGameInfo.m_unGameIP, friendGameInfo.m_usGamePort, usConnPort, pszConnectCode );
+ pDialogGameInfo->SetFriend( ulSteamIDFriend );
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: joins a specified game - game info dialog will only be opened if the server is fully or passworded
+//-----------------------------------------------------------------------------
+bool CServerBrowser::JoinGame( uint64 ulSteamIDFriend, const char *pszConnectCode )
+{
+ if ( OpenGameInfoDialog( ulSteamIDFriend, pszConnectCode ) )
+ {
+ CDialogGameInfo *pDialogGameInfo = m_hInternetDlg->GetDialogGameInfoForFriend( ulSteamIDFriend );
+ pDialogGameInfo->Connect();
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: joins a game by IP/Port
+//-----------------------------------------------------------------------------
+bool CServerBrowser::JoinGame( uint32 unGameIP, uint16 usGamePort, const char *pszConnectCode )
+{
+ m_hInternetDlg->JoinGame( unGameIP, usGamePort, pszConnectCode );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: forces the game info dialog closed
+//-----------------------------------------------------------------------------
+void CServerBrowser::CloseGameInfoDialog( uint64 ulSteamIDFriend )
+{
+ CDialogGameInfo *pDialogGameInfo = m_hInternetDlg->GetDialogGameInfoForFriend( ulSteamIDFriend );
+ if ( pDialogGameInfo )
+ {
+ pDialogGameInfo->Close();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: closes all the game info dialogs
+//-----------------------------------------------------------------------------
+void CServerBrowser::CloseAllGameInfoDialogs()
+{
+ if ( m_hInternetDlg.Get() )
+ {
+ m_hInternetDlg->CloseAllGameInfoDialogs();
+ }
+}
+
+CUtlVector< gametypes_t > g_GameTypes;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void LoadGameTypes( void )
+{
+ if ( g_GameTypes.Count() > 0 )
+ return;
+
+ #define GAMETYPES_FILE "servers/ServerBrowserGameTypes.txt"
+
+ KeyValues * kv = new KeyValues( GAMETYPES_FILE );
+
+ if ( !kv->LoadFromFile( g_pFullFileSystem, GAMETYPES_FILE, "MOD" ) )
+ {
+ kv->deleteThis();
+ return;
+ }
+
+ g_GameTypes.RemoveAll();
+
+ for ( KeyValues *pData = kv->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
+ {
+ gametypes_t gametype;
+
+ gametype.pPrefix = CloneString( pData->GetString( "prefix", "" ) );
+ gametype.pGametypeName = CloneString( pData->GetString( "name", "" ) );
+ g_GameTypes.AddToTail( gametype );
+ }
+
+
+ kv->deleteThis();
+}
+
+const char *GetGameTypeName( const char *pMapName )
+{
+ LoadGameTypes();
+ for ( int i = 0; i < g_GameTypes.Count(); i++ )
+ {
+ int iLength = strlen( g_GameTypes[i].pPrefix );
+
+ if ( !Q_strncmp( pMapName, g_GameTypes[i].pPrefix, iLength ) )
+ {
+ return g_GameTypes[i].pGametypeName;
+ }
+ }
+
+ return "";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose of comments like these: none
+//-----------------------------------------------------------------------------
+const char *CServerBrowser::GetMapFriendlyNameAndGameType( const char *pszMapName, char *szFriendlyMapName, int cchFriendlyName )
+{
+ // Make sure game types are loaded
+ LoadGameTypes();
+
+ // Scan list
+ const char *pszFriendlyGameTypeName = "";
+ for ( int i = 0; i < g_GameTypes.Count(); i++ )
+ {
+ int iLength = strlen( g_GameTypes[i].pPrefix );
+
+ if ( !Q_strnicmp( pszMapName, g_GameTypes[i].pPrefix, iLength ) )
+ {
+ pszMapName += iLength;
+ pszFriendlyGameTypeName = g_GameTypes[i].pGametypeName;
+ break;
+ }
+ }
+
+ // See how many characters from the name to copy.
+ // Start by assuming we'll copy the whole thing.
+ // (After any prefix we just skipped)
+ int l = V_strlen( pszMapName );
+ const char *pszFinal = Q_stristr( pszMapName, "_final" );
+ if ( pszFinal )
+ {
+ // truncate the _final (or _final1) part of the filename if it's at the end of the name
+ const char *pszNextChar = pszFinal + Q_strlen( "_final" );
+ if ( ( *pszNextChar == '\0' ) ||
+ ( ( *pszNextChar == '1' ) && ( *(pszNextChar+1) == '\0' ) ) )
+ {
+ l = pszFinal - pszMapName;
+ }
+ }
+
+ // Safety check against buffer size
+ if ( l >= cchFriendlyName )
+ {
+ Assert( !"Map name too long for buffer!" );
+ l = cchFriendlyName-1;
+ }
+
+ // Copy friendly portion of name only
+ V_memcpy( szFriendlyMapName, pszMapName, l );
+
+ // It's like the Alamo. We never forget.
+ szFriendlyMapName[l] = '\0';
+
+ // Result should be the friendly game type name
+ return pszFriendlyGameTypeName;
+}
+