summaryrefslogtreecommitdiff
path: root/tracker
diff options
context:
space:
mode:
Diffstat (limited to 'tracker')
-rw-r--r--tracker/AdminServer/AdminServer.cpp197
-rw-r--r--tracker/AdminServer/AdminServer.h69
-rw-r--r--tracker/AdminServer/AdminServer.vpc117
-rw-r--r--tracker/AdminServer/BanContextMenu.cpp57
-rw-r--r--tracker/AdminServer/BanContextMenu.h32
-rw-r--r--tracker/AdminServer/BanPanel.cpp416
-rw-r--r--tracker/AdminServer/BanPanel.h78
-rw-r--r--tracker/AdminServer/BaseGamesPage.cpp247
-rw-r--r--tracker/AdminServer/BaseGamesPage.h92
-rw-r--r--tracker/AdminServer/BudgetPanelContainer.cpp175
-rw-r--r--tracker/AdminServer/BudgetPanelContainer.h60
-rw-r--r--tracker/AdminServer/ChatContextMenu.h32
-rw-r--r--tracker/AdminServer/ChatPanel.cpp87
-rw-r--r--tracker/AdminServer/ChatPanel.h44
-rw-r--r--tracker/AdminServer/ClickableTabbedPanel.cpp40
-rw-r--r--tracker/AdminServer/ClickableTabbedPanel.h40
-rw-r--r--tracker/AdminServer/ConfigPanel.cpp181
-rw-r--r--tracker/AdminServer/ConfigPanel.h54
-rw-r--r--tracker/AdminServer/DialogAddBan.cpp250
-rw-r--r--tracker/AdminServer/DialogAddBan.h67
-rw-r--r--tracker/AdminServer/DialogAddServer.cpp109
-rw-r--r--tracker/AdminServer/DialogAddServer.h42
-rw-r--r--tracker/AdminServer/DialogCvarChange.cpp151
-rw-r--r--tracker/AdminServer/DialogCvarChange.h58
-rw-r--r--tracker/AdminServer/DialogGameInfo.cpp532
-rw-r--r--tracker/AdminServer/DialogGameInfo.h110
-rw-r--r--tracker/AdminServer/DialogKickPlayer.cpp130
-rw-r--r--tracker/AdminServer/DialogKickPlayer.h57
-rw-r--r--tracker/AdminServer/DialogServerPassword.cpp119
-rw-r--r--tracker/AdminServer/DialogServerPassword.h58
-rw-r--r--tracker/AdminServer/FavoriteGames.cpp815
-rw-r--r--tracker/AdminServer/FavoriteGames.h121
-rw-r--r--tracker/AdminServer/GamePanelInfo.cpp341
-rw-r--r--tracker/AdminServer/GamePanelInfo.h105
-rw-r--r--tracker/AdminServer/GraphPanel.cpp731
-rw-r--r--tracker/AdminServer/GraphPanel.h154
-rw-r--r--tracker/AdminServer/HelpText.cpp84
-rw-r--r--tracker/AdminServer/HelpText.h35
-rw-r--r--tracker/AdminServer/IManageServer.h35
-rw-r--r--tracker/AdminServer/Iresponse.h30
-rw-r--r--tracker/AdminServer/MOTDPanel.cpp171
-rw-r--r--tracker/AdminServer/MOTDPanel.h71
-rw-r--r--tracker/AdminServer/MapCycleEditDialog.cpp263
-rw-r--r--tracker/AdminServer/MapCycleEditDialog.h45
-rw-r--r--tracker/AdminServer/MasterMsgHandler.cpp76
-rw-r--r--tracker/AdminServer/Player.h33
-rw-r--r--tracker/AdminServer/PlayerContextMenu.cpp51
-rw-r--r--tracker/AdminServer/PlayerContextMenu.h32
-rw-r--r--tracker/AdminServer/PlayerListCompare.cpp191
-rw-r--r--tracker/AdminServer/PlayerListCompare.h25
-rw-r--r--tracker/AdminServer/PlayerPanel.cpp401
-rw-r--r--tracker/AdminServer/PlayerPanel.h68
-rw-r--r--tracker/AdminServer/RawLogPanel.cpp87
-rw-r--r--tracker/AdminServer/RawLogPanel.h43
-rw-r--r--tracker/AdminServer/RemoteServer.cpp256
-rw-r--r--tracker/AdminServer/RemoteServer.h95
-rw-r--r--tracker/AdminServer/RulesContextMenu.cpp51
-rw-r--r--tracker/AdminServer/RulesContextMenu.h32
-rw-r--r--tracker/AdminServer/ServerConfigPanel.cpp61
-rw-r--r--tracker/AdminServer/ServerConfigPanel.h35
-rw-r--r--tracker/AdminServer/ServerContextMenu.cpp104
-rw-r--r--tracker/AdminServer/ServerContextMenu.h33
-rw-r--r--tracker/AdminServer/ServerList.cpp446
-rw-r--r--tracker/AdminServer/ServerList.h112
-rw-r--r--tracker/AdminServer/ServerListCompare.cpp115
-rw-r--r--tracker/AdminServer/ServerListCompare.h22
-rw-r--r--tracker/AdminServer/TokenLine.cpp150
-rw-r--r--tracker/AdminServer/TokenLine.h36
-rw-r--r--tracker/AdminServer/VarEditDialog.cpp203
-rw-r--r--tracker/AdminServer/VarEditDialog.h45
-rw-r--r--tracker/AdminServer/VarListPropertyPage.cpp225
-rw-r--r--tracker/AdminServer/VarListPropertyPage.h67
-rw-r--r--tracker/AdminServer/ban.h28
-rw-r--r--tracker/AdminServer/banlist.cpp241
-rw-r--r--tracker/AdminServer/banlist.h68
-rw-r--r--tracker/AdminServer/cmdlist.cpp177
-rw-r--r--tracker/AdminServer/cmdlist.h56
-rw-r--r--tracker/AdminServer/logmsghandler.cpp66
-rw-r--r--tracker/AdminServer/logmsghandler.h45
-rw-r--r--tracker/AdminServer/maps.h26
-rw-r--r--tracker/AdminServer/mapslist.cpp230
-rw-r--r--tracker/AdminServer/mapslist.h70
-rw-r--r--tracker/AdminServer/playerlist.cpp227
-rw-r--r--tracker/AdminServer/playerlist.h70
-rw-r--r--tracker/AdminServer/playermsghandler.cpp93
-rw-r--r--tracker/AdminServer/playermsghandler.h41
-rw-r--r--tracker/AdminServer/point.h29
-rw-r--r--tracker/AdminServer/rcon.cpp343
-rw-r--r--tracker/AdminServer/rcon.h100
-rw-r--r--tracker/AdminServer/rconmsghandler.cpp67
-rw-r--r--tracker/AdminServer/rconmsghandler.h36
-rw-r--r--tracker/AdminServer/rulesinfo.cpp132
-rw-r--r--tracker/AdminServer/rulesinfo.h67
-rw-r--r--tracker/AdminServer/rulesinfomsghandler.cpp89
-rw-r--r--tracker/AdminServer/rulesinfomsghandler.h44
-rw-r--r--tracker/AdminServer/serverinfo.cpp187
-rw-r--r--tracker/AdminServer/serverinfo.h60
-rw-r--r--tracker/AdminServer/serverinfomsghandler.cpp74
-rw-r--r--tracker/AdminServer/serverinfomsghandler.h36
-rw-r--r--tracker/AdminServer/serverinfopanel.cpp285
-rw-r--r--tracker/AdminServer/serverinfopanel.h63
-rw-r--r--tracker/AdminServer/serverpage.cpp906
-rw-r--r--tracker/AdminServer/serverpage.h197
-rw-r--r--tracker/AdminServer/serverping.cpp145
-rw-r--r--tracker/AdminServer/serverping.h55
-rw-r--r--tracker/AdminServer/serverpingmsghandler.cpp31
-rw-r--r--tracker/AdminServer/serverpingmsghandler.h36
-rw-r--r--tracker/common/CompletionEvent.cpp37
-rw-r--r--tracker/common/CompletionEvent.h32
-rw-r--r--tracker/common/DebugConsole_Interface.h30
-rw-r--r--tracker/common/DebugTimer.h22
-rw-r--r--tracker/common/IGameList.h69
-rw-r--r--tracker/common/IServerRefreshResponse.h34
-rw-r--r--tracker/common/IceKey.H65
-rw-r--r--tracker/common/IceKey.cpp393
-rw-r--r--tracker/common/MasterMsgHandler.h32
-rw-r--r--tracker/common/Socket.cpp1035
-rw-r--r--tracker/common/Socket.h162
-rw-r--r--tracker/common/TrackerMessageFlags.h22
-rw-r--r--tracker/common/TrackerProtocol.h161
-rw-r--r--tracker/common/UtlMsgBuffer.cpp332
-rw-r--r--tracker/common/UtlMsgBuffer.h198
-rw-r--r--tracker/common/inetapi.h42
-rw-r--r--tracker/common/msgbuffer.cpp421
-rw-r--r--tracker/common/msgbuffer.h108
-rw-r--r--tracker/common/netapi.cpp277
-rw-r--r--tracker/common/server.h51
-rw-r--r--tracker/common/util.cpp70
-rw-r--r--tracker/common/util.h29
129 files changed, 17839 insertions, 0 deletions
diff --git a/tracker/AdminServer/AdminServer.cpp b/tracker/AdminServer/AdminServer.cpp
new file mode 100644
index 0000000..5352efb
--- /dev/null
+++ b/tracker/AdminServer/AdminServer.cpp
@@ -0,0 +1,197 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "AdminServer.h"
+#include "IRunGameEngine.h"
+#include "IGameServerData.h"
+#include "GamePanelInfo.h"
+#include "ivprofexport.h"
+
+#include <vgui/ISystem.h>
+#include <vgui/IPanel.h>
+#include <vgui/IVGui.h>
+#include <vgui/ILocalize.h>
+#include <KeyValues.h>
+#include "filesystem.h"
+
+// expose the server browser interfaces
+CAdminServer g_AdminServerSingleton;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CAdminServer, IAdminServer, ADMINSERVER_INTERFACE_VERSION, g_AdminServerSingleton);
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CAdminServer, IVGuiModule, "VGuiModuleAdminServer001", g_AdminServerSingleton);
+
+IGameServerData *g_pGameServerData = NULL;
+IVProfExport *g_pVProfExport = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CAdminServer::CAdminServer()
+{
+ // fill in the 0-based element of the manage servers list
+ OpenedManageDialog_t empty = { 0, NULL };
+ m_OpenedManageDialog.AddToTail(empty);
+ m_hParent=0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CAdminServer::~CAdminServer()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: links to vgui and engine interfaces
+//-----------------------------------------------------------------------------
+bool CAdminServer::Initialize(CreateInterfaceFn *factorylist, int factoryCount)
+{
+ ConnectTier1Libraries( factorylist, factoryCount );
+ ConVar_Register();
+ ConnectTier2Libraries( factorylist, factoryCount );
+ ConnectTier3Libraries( factorylist, factoryCount );
+
+ // find our interfaces
+ for (int i = 0; i < factoryCount; i++)
+ {
+ // if we're running locally we can get this direct interface to the game engine
+ if (!g_pGameServerData)
+ {
+ g_pGameServerData = (IGameServerData *)(factorylist[i])(GAMESERVERDATA_INTERFACE_VERSION, NULL);
+ }
+ if ( !g_pVProfExport )
+ {
+ g_pVProfExport = (IVProfExport*)(factorylist[i])( VPROF_EXPORT_INTERFACE_VERSION, NULL );
+ }
+ }
+
+ RemoteServer().Initialize(); // now we have the game date interface, initialize the engine connection
+
+ if ( vgui::VGui_InitInterfacesList("AdminServer", factorylist, factoryCount) )
+ {
+ // load localization file
+ g_pVGuiLocalize->AddFile( "admin/admin_%language%.txt");
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: links to other modules interfaces (tracker)
+//-----------------------------------------------------------------------------
+bool CAdminServer::PostInitialize(CreateInterfaceFn *modules, int factoryCount)
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CAdminServer::IsValid()
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CAdminServer::Activate()
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns direct handle to main server browser dialog
+//-----------------------------------------------------------------------------
+vgui::VPANEL CAdminServer::GetPanel()
+{
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Closes down the server browser for good
+//-----------------------------------------------------------------------------
+void CAdminServer::Shutdown()
+{
+ DisconnectTier3Libraries();
+ DisconnectTier2Libraries();
+ ConVar_Unregister();
+ DisconnectTier1Libraries();
+}
+
+void CAdminServer::SetParent(vgui::VPANEL parent)
+{
+/* if (m_hServerPage.Get())
+ {
+ m_hServerPage->SetParent(parent);
+ }
+ */
+ m_hParent = parent;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the user enters the game
+//-----------------------------------------------------------------------------
+void CAdminServer::Deactivate()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the user returns from the game to the outside UI
+//-----------------------------------------------------------------------------
+void CAdminServer::Reactivate()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: opens a manage server dialog for a local server
+//-----------------------------------------------------------------------------
+ManageServerUIHandle_t CAdminServer::OpenManageServerDialog(const char *serverName, const char *gameDir)
+{
+ CGamePanelInfo *tmp = new CGamePanelInfo(NULL, serverName, gameDir);
+ tmp->SetParent(m_hParent);
+
+ // add a new item into the list
+ int i = m_OpenedManageDialog.AddToTail();
+ m_OpenedManageDialog[i].handle = vgui::ivgui()->PanelToHandle(tmp->GetVPanel());
+ m_OpenedManageDialog[i].manageInterface = tmp;
+
+ return (ManageServerUIHandle_t)i;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: opens a manage server dialog to a remote server
+//-----------------------------------------------------------------------------
+ManageServerUIHandle_t CAdminServer::OpenManageServerDialog(unsigned int gameIP, unsigned int gamePort, const char *password)
+{
+ Assert(false);
+ return (ManageServerUIHandle_t)0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: forces the game info dialog closed
+//-----------------------------------------------------------------------------
+void CAdminServer::CloseManageServerDialog(ManageServerUIHandle_t gameDialog)
+{
+ Assert(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets a handle to the management interface
+//-----------------------------------------------------------------------------
+IManageServer *CAdminServer::GetManageServerInterface(ManageServerUIHandle_t handle)
+{
+ // make sure it's safe
+ if ((int)handle < 1 || (int)handle > m_OpenedManageDialog.Count())
+ return NULL;
+
+ vgui::VPANEL panel = vgui::ivgui()->HandleToPanel(m_OpenedManageDialog[handle].handle);
+ if (!panel)
+ return NULL;
+
+ return m_OpenedManageDialog[handle].manageInterface;
+}
diff --git a/tracker/AdminServer/AdminServer.h b/tracker/AdminServer/AdminServer.h
new file mode 100644
index 0000000..948297b
--- /dev/null
+++ b/tracker/AdminServer/AdminServer.h
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef ADMINSERVER_H
+#define ADMINSERVER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "IAdminServer.h"
+#include "IVGuiModule.h"
+
+#include <utlvector.h>
+
+class CServerPage;
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles the UI and pinging of a half-life game server list
+//-----------------------------------------------------------------------------
+class CAdminServer : public IAdminServer, public IVGuiModule
+{
+public:
+ CAdminServer();
+ ~CAdminServer();
+
+ // IVGui module implementation
+ virtual bool Initialize(CreateInterfaceFn *factorylist, int numFactories);
+ virtual bool PostInitialize(CreateInterfaceFn *modules, int factoryCount);
+ virtual vgui::VPANEL GetPanel();
+ virtual bool Activate();
+ virtual bool IsValid();
+ virtual void Shutdown();
+ virtual void Deactivate();
+ virtual void Reactivate();
+ virtual void SetParent(vgui::VPANEL parent);
+
+ // IAdminServer implementation
+ // opens a manage server dialog for a local server
+ virtual ManageServerUIHandle_t OpenManageServerDialog(const char *serverName, const char *gameDir);
+
+ // opens a manage server dialog to a remote server
+ virtual ManageServerUIHandle_t OpenManageServerDialog(unsigned int gameIP, unsigned int gamePort, const char *password);
+
+ // forces the game info dialog closed
+ virtual void CloseManageServerDialog(ManageServerUIHandle_t gameDialog);
+
+ // Gets a handle to the interface
+ virtual IManageServer *GetManageServerInterface(ManageServerUIHandle_t handle);
+
+private:
+ struct OpenedManageDialog_t
+ {
+ unsigned long handle;
+ IManageServer *manageInterface;
+ };
+ CUtlVector<OpenedManageDialog_t> m_OpenedManageDialog;
+ vgui::VPANEL m_hParent;
+};
+
+
+class IVProfExport;
+extern IVProfExport *g_pVProfExport;
+
+
+#endif // AdminServer_H
diff --git a/tracker/AdminServer/AdminServer.vpc b/tracker/AdminServer/AdminServer.vpc
new file mode 100644
index 0000000..25dc40c
--- /dev/null
+++ b/tracker/AdminServer/AdminServer.vpc
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------------
+// ADMINSERVER.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+// $AdditionalIncludeDirectories "$BASE,.\,"
+ $PreprocessorDefinitions "$BASE;ADMINSERVER_EXPORTS;BUDGET_ADMIN_SERVER"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE wsock32.lib"
+ }
+}
+
+$Project "AdminServer"
+{
+ $Folder "Source Files"
+ {
+ $File "AdminServer.cpp"
+ $File "BanContextMenu.cpp"
+ $File "ConfigPanel.cpp"
+ $File "GamePanelInfo.cpp"
+ $File "MapCycleEditDialog.cpp"
+ $File "..\common\msgbuffer.cpp"
+ $File "PlayerContextMenu.cpp"
+ $File "PlayerListCompare.cpp"
+ $File "RemoteServer.cpp"
+ $File "VarEditDialog.cpp"
+ $File "VarListPropertyPage.cpp"
+ $File "$SRCDIR\common\vgui\vgui_basebudgetpanel.cpp"
+ $File "$SRCDIR\common\vgui\vgui_budgetbargraphpanel.cpp"
+ $File "$SRCDIR\common\vgui\vgui_budgethistorypanel.cpp"
+ $File "$SRCDIR\common\vgui\vgui_budgetpanelshared.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+
+ $Folder "Utils"
+ {
+ $File "TokenLine.cpp"
+ }
+
+ $Folder "Generic Dialogs"
+ {
+ $File "DialogAddBan.cpp"
+ $File "DialogCvarChange.cpp"
+ }
+
+ $Folder "Pages"
+ {
+ $File "BanPanel.cpp"
+ $File "BudgetPanelContainer.cpp"
+ $File "ChatPanel.cpp"
+ $File "GraphPanel.cpp"
+ $File "PlayerPanel.cpp"
+ $File "RawLogPanel.cpp"
+ $File "ServerConfigPanel.cpp"
+ $File "serverinfopanel.cpp"
+ }
+ }
+
+ $Folder "Header Files"
+ {
+ $File "AdminServer.h"
+ $File "BanContextMenu.h"
+ $File "BanPanel.h"
+ $File "BudgetPanelContainer.h"
+ $File "ChatPanel.h"
+ $File "ConfigPanel.h"
+ $File "DialogAddBan.h"
+ $File "DialogCvarChange.h"
+ $File "GamePanelInfo.h"
+ $File "GraphPanel.h"
+ $File "$SRCDIR\common\IGameServerData.h"
+ $File "IManageServer.h"
+ $File "$SRCDIR\public\tier1\interface.h"
+ $File "..\common\IServerRefreshResponse.h"
+ $File "$SRCDIR\common\ivprofexport.h"
+ $File "MapCycleEditDialog.h"
+ $File "..\common\msgbuffer.h"
+ $File "PlayerContextMenu.h"
+ $File "PlayerListCompare.h"
+ $File "PlayerPanel.h"
+ $File "RawLogPanel.h"
+ $File "RemoteServer.h"
+ $File "ServerConfigPanel.h"
+ $File "serverinfopanel.h"
+ $File "TokenLine.h"
+ $File "$SRCDIR\public\tier1\utlbuffer.h"
+ $File "$SRCDIR\public\tier1\utllinkedlist.h"
+ $File "$SRCDIR\public\tier1\utlsymbol.h"
+ $File "$SRCDIR\public\tier1\utlvector.h"
+ $File "VarEditDialog.h"
+ $File "VarListPropertyPage.h"
+ $File "$SRCDIR\common\vgui\vgui_basebudgetpanel.h"
+ $File "$SRCDIR\common\vgui\vgui_budgetbargraphpanel.h"
+ $File "$SRCDIR\common\vgui\vgui_budgethistorypanel.h"
+ $File "$SRCDIR\common\vgui\vgui_budgetpanelshared.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib tier2
+ $Lib tier3
+ $Lib vgui_controls
+ $Lib mathlib
+ }
+}
diff --git a/tracker/AdminServer/BanContextMenu.cpp b/tracker/AdminServer/BanContextMenu.cpp
new file mode 100644
index 0000000..25fe677
--- /dev/null
+++ b/tracker/AdminServer/BanContextMenu.cpp
@@ -0,0 +1,57 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "BanContextMenu.h"
+
+#include <vgui/IInput.h>
+#include <vgui/IPanel.h>
+#include <vgui/ISurface.h>
+#include <KeyValues.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBanContextMenu::CBanContextMenu(Panel *parent) : Menu(parent, "BanContextMenu")
+{
+ CBanContextMenu::parent=parent;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CBanContextMenu::~CBanContextMenu()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the menu
+//-----------------------------------------------------------------------------
+void CBanContextMenu::ShowMenu(Panel *target, unsigned int banID)
+{
+ DeleteAllItems();
+
+ if(banID==-1)
+ {
+ AddMenuItem("ban", "#Ban_Menu_Add", new KeyValues("addban", "banID", banID), CBanContextMenu::parent);
+ }
+ else
+ {
+ AddMenuItem("ban", "#Ban_Menu_Remove", new KeyValues("removeban", "banID", banID), CBanContextMenu::parent);
+ AddMenuItem("ban", "#Ban_Menu_Change", new KeyValues("changeban", "banID", banID), CBanContextMenu::parent);
+ }
+
+ MakePopup();
+ int x, y, gx, gy;
+ input()->GetCursorPos(x, y);
+ ipanel()->GetPos(surface()->GetEmbeddedPanel(), gx, gy);
+ SetPos(x - gx, y - gy);
+ MoveToFront();
+ RequestFocus();
+ SetVisible(true);
+}
diff --git a/tracker/AdminServer/BanContextMenu.h b/tracker/AdminServer/BanContextMenu.h
new file mode 100644
index 0000000..161e5ad
--- /dev/null
+++ b/tracker/AdminServer/BanContextMenu.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef BANCONTEXTMENU_H
+#define BANCONTEXTMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Menu.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic right-click context menu for servers
+//-----------------------------------------------------------------------------
+class CBanContextMenu : public vgui::Menu
+{
+public:
+ CBanContextMenu(vgui::Panel *parent);
+ ~CBanContextMenu();
+
+ // call this to activate the menu
+ void ShowMenu(vgui::Panel *target, unsigned int banID);
+private:
+ vgui::Panel *parent; // so we can send it messages
+};
+
+
+#endif // BANCONTEXTMENU_H
diff --git a/tracker/AdminServer/BanPanel.cpp b/tracker/AdminServer/BanPanel.cpp
new file mode 100644
index 0000000..641290d
--- /dev/null
+++ b/tracker/AdminServer/BanPanel.cpp
@@ -0,0 +1,416 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+
+#include "BanPanel.h"
+#include "PlayerContextMenu.h"
+#include "DialogAddBan.h"
+
+#include <vgui/Cursor.h>
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+#include <vgui/IVGui.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/QueryBox.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/FileOpenDialog.h>
+
+#include "filesystem.h"
+
+#include "DialogCvarChange.h"
+#include "tokenline.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBanPanel::CBanPanel(vgui::Panel *parent, const char *name) : PropertyPage(parent, name)
+{
+ m_pBanListPanel = new ListPanel(this, "BanList");
+ m_pBanListPanel->AddColumnHeader(0, "type", "#Ban_List_Type", 150 );
+ m_pBanListPanel->AddColumnHeader(1, "id", "#Ban_List_ID", 200 );
+ m_pBanListPanel->AddColumnHeader(2, "time", "#Ban_List_Time", 200 );
+ m_pBanListPanel->SetSortColumn(2);
+ m_pBanListPanel->SetEmptyListText("#Ban_List_Empty");
+
+ m_pAddButton = new Button(this, "Add", "#Ban_List_Add");
+ m_pRemoveButton = new Button(this, "Remove", "#Ban_List_Remove");
+ m_pChangeButton = new Button(this, "Change", "#Ban_List_Edit");
+ m_pImportButton = new Button(this, "Import", "#Ban_List_Import");
+
+ m_pAddButton->SetCommand(new KeyValues("addban"));
+ m_pRemoveButton->SetCommand(new KeyValues("removeban"));
+ m_pChangeButton->SetCommand(new KeyValues("changeban"));
+ m_pImportButton->SetCommand(new KeyValues("importban"));
+
+ m_pBanContextMenu = new CBanContextMenu(this);
+ m_pBanContextMenu->SetVisible(false);
+
+ m_flUpdateTime = 0.0f;
+ m_bPageViewed = false;
+
+ LoadControlSettings("Admin/BanPanel.res", "PLATFORM");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CBanPanel::~CBanPanel()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the page
+//-----------------------------------------------------------------------------
+void CBanPanel::OnPageShow()
+{
+ BaseClass::OnPageShow();
+ OnItemSelected();
+ if (!m_bPageViewed)
+ {
+ m_bPageViewed = true;
+ // force update on first page view
+ m_flUpdateTime = 0.0f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Requests new data set from server
+//-----------------------------------------------------------------------------
+void CBanPanel::OnResetData()
+{
+ RemoteServer().RequestValue(this, "banlist");
+ // update once every 5 minutes
+ m_flUpdateTime = (float)system()->GetFrameTime() + (60 * 5.0f);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if the page data should be refreshed
+//-----------------------------------------------------------------------------
+void CBanPanel::OnThink()
+{
+ if (m_flUpdateTime < system()->GetFrameTime())
+ {
+ OnResetData();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Wrap g_pVGuiLocalize->Find() and not return NULL
+//-----------------------------------------------------------------------------
+static const wchar_t * LocalizeFind( const char *identifier, const wchar_t *defaultText )
+{
+ const wchar_t *str = g_pVGuiLocalize->Find(identifier);
+ if ( !str )
+ str = defaultText;
+ return str;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Received response from server containing data
+//-----------------------------------------------------------------------------
+void CBanPanel::OnServerDataResponse(const char *value, const char *response)
+{
+ // build the list
+ if (!stricmp(value, "banlist"))
+ {
+ // clear current list
+ m_pBanListPanel->DeleteAllItems();
+
+ // scan through response for all items
+ int item = 0;
+ float banTime = 0.0f;
+ char id[64] = { 0 };
+ while (3 == sscanf(response, "%i %s : %f min\n", &item, id, &banTime))
+ {
+ KeyValues *ban = new KeyValues("ban");
+
+ // determine type
+ if (IsIPAddress(id))
+ {
+ // ip address
+ ban->SetWString("type", LocalizeFind("#Ban_IP", L"IP Address"));
+ }
+ else
+ {
+ // must be a userID
+ ban->SetWString("type", LocalizeFind("#Ban_Auth_ID", L"AuthID"));
+ }
+ ban->SetString("id", id);
+
+ if (banTime > 0.0f)
+ {
+ ban->SetFloat("time", banTime);
+ }
+ else
+ {
+ ban->SetWString("time", LocalizeFind("#Ban_Permanent", L"permanent"));
+ }
+
+ // add to list
+ m_pBanListPanel->AddItem(ban, 0, false, false);
+
+ // move to the next item
+ response = (const char *)strchr(response, '\n');
+ if (!response)
+ break;
+ response++;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Refreshes the list on the user hitting F5
+//-----------------------------------------------------------------------------
+void CBanPanel::OnKeyCodeTyped(vgui::KeyCode code)
+{
+ if (code == KEY_F5)
+ {
+ OnResetData();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: opens context menu (user right clicked on a server)
+//-----------------------------------------------------------------------------
+void CBanPanel::OnOpenContextMenu(int row)
+{
+/* CONTEXT MENU CODE TEMPORARILY DISABLED UNTIL VERIFIED AS WORKING
+ if (m_pBanListPanel->IsVisible() && m_pBanListPanel->IsCursorOver()
+ && m_pBanListPanel->GetNumSelectedRows())
+ // show the ban changing menu IF its the visible panel and the cursor is
+ // over it
+ {
+
+ unsigned int banID =m_pBanListPanel->GetSelectedRow(0);
+
+ // activate context menu
+ m_pBanContextMenu->ShowMenu(this, banID);
+ }
+ else
+ {
+ m_pBanContextMenu->ShowMenu(this, -1);
+ }
+*/
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Manually adds a new ban
+//-----------------------------------------------------------------------------
+void CBanPanel::AddBan()
+{
+ CDialogAddBan *box = new CDialogAddBan(this);
+ box->AddActionSignalTarget(this);
+ box->Activate("addban", "", "");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: prompts the user to remove an existing ban
+//-----------------------------------------------------------------------------
+void CBanPanel::RemoveBan()
+{
+ int itemID = m_pBanListPanel->GetSelectedItem(0);
+ if ( itemID == -1 )
+ return;
+
+ // ask the user whether or not they want to remove the ban
+ KeyValues *kv = m_pBanListPanel->GetItem(itemID);
+ if (kv != NULL)
+ {
+ // build the message
+ wchar_t id[256];
+ g_pVGuiLocalize->ConvertANSIToUnicode(kv->GetString("id"), id, sizeof(id));
+ wchar_t message[256];
+ g_pVGuiLocalize->ConstructString(message, sizeof(message), g_pVGuiLocalize->Find("#Ban_Remove_Msg"), 1, id);
+
+ // activate the confirmation dialog
+ QueryBox *box = new QueryBox(g_pVGuiLocalize->Find("#Ban_Title_Remove"), message);
+ box->SetOKCommand(new KeyValues("removebanbyid", "id", kv->GetString("id")));
+ box->AddActionSignalTarget(this);
+ box->DoModal();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: change the time length of a ban
+//-----------------------------------------------------------------------------
+void CBanPanel::ChangeBan()
+{
+ int itemID = m_pBanListPanel->GetSelectedItem(0);
+ if (itemID == -1)
+ return;
+
+ KeyValues *kv = m_pBanListPanel->GetItem(itemID);
+ if (kv != NULL)
+ {
+ char timeText[20];
+ float time = kv->GetFloat("time");
+ _snprintf(timeText, sizeof(timeText), "%0.2f", time);
+
+ // open a dialog asking them what time to change the ban lenght to
+ CDialogCvarChange *box = new CDialogCvarChange(this);
+ box->AddActionSignalTarget(this);
+ box->SetTitle("#Ban_Title_Change", true);
+ box->Activate(kv->GetString("id"), timeText, "changeban", "#Ban_Change_Time");
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes the specified ban
+//-----------------------------------------------------------------------------
+void CBanPanel::RemoveBanByID(const char *id)
+{
+ Assert(id && *id);
+ if (!id || !*id)
+ return;
+
+ // send down the command
+ char cmd[512];
+ _snprintf(cmd, sizeof(cmd) -1, "%s %s\n", IsIPAddress(id) ? "removeip" : "removeid", id);
+ RemoteServer().SendCommand(cmd);
+
+ // force the file to be written
+ if (IsIPAddress(id))
+ {
+ RemoteServer().SendCommand("writeip");
+ }
+ else
+ {
+ RemoteServer().SendCommand("writeid");
+ }
+
+ // refresh
+ OnResetData();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes a ban
+//-----------------------------------------------------------------------------
+void CBanPanel::ChangeBanTimeByID(const char *id, const char *newtime)
+{
+ Assert(id && *id);
+ if (!id || !*id)
+ return;
+
+ // if the newtime string is not valid, then set it to 0 (permanent ban)
+ if (!newtime || atof(newtime) < 0.001)
+ {
+ newtime = "0";
+ }
+
+ // send down the command
+ char cmd[512];
+ _snprintf(cmd, sizeof(cmd) -1, "%s %s %s\n", IsIPAddress(id) ? "addip" : "banid", newtime, id);
+ RemoteServer().SendCommand(cmd);
+ if (IsIPAddress(id))
+ {
+ RemoteServer().SendCommand("writeip");
+ }
+ else
+ {
+ RemoteServer().SendCommand("writeid");
+ }
+
+ // refresh
+ OnResetData();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes a ban
+//-----------------------------------------------------------------------------
+void CBanPanel::OnCvarChangeValue( KeyValues *kv )
+{
+ const char *idText = kv->GetString( "player", "" );
+ const char *durationText = kv->GetString( "value", "0" );
+
+ ChangeBanTimeByID( idText, durationText );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when a row on the list panel is selected.
+//-----------------------------------------------------------------------------
+void CBanPanel::OnItemSelected()
+{
+ int itemID = m_pBanListPanel->GetSelectedItem(0);
+ if (itemID == -1)
+ {
+ m_pRemoveButton->SetEnabled(false);
+ m_pChangeButton->SetEnabled(false);
+ }
+ else
+ {
+ m_pRemoveButton->SetEnabled(true);
+ m_pChangeButton->SetEnabled(true);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Asks the user for the ban file to import
+//-----------------------------------------------------------------------------
+void CBanPanel::ImportBanList()
+{
+ // Pop up the dialog
+ FileOpenDialog *pFileDialog = new FileOpenDialog(this, "#Ban_Find_Ban_File", true);
+ pFileDialog->AddFilter( "*.cfg", "#Config_files", true );
+ pFileDialog->AddFilter( "*.*", "#All_files", false );
+ pFileDialog->DoModal(true);
+ pFileDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: When a file is selected print out its full path in the debugger
+//-----------------------------------------------------------------------------
+void CBanPanel::OnFileSelected(const char *fullpath)
+{
+ char line[255];
+ TokenLine tok;
+
+ // this can take a while, put up a waiting cursor
+ surface()->SetCursor(dc_hourglass);
+
+ // we don't use filesystem() here becuase we want to let the user pick
+ // a file from anywhere on their filesystem... so we use stdio
+ FILE *f = fopen(fullpath,"rb");
+ while (!feof(f) && fgets(line, 255, f))
+ {
+ // parse each line of the config file adding the ban
+ tok.SetLine(line);
+ if (tok.CountToken() == 3)
+ {
+ // add the ban
+ const char *id = tok.GetToken(2);
+ ChangeBanTimeByID(id, "0");
+ }
+ }
+
+ // change the cursor back to normal and shutdown file
+ surface()->SetCursor(dc_user);
+ if (f)
+ {
+ fclose(f);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the id string is an IP address, false if it's a WON or STEAM ID
+//-----------------------------------------------------------------------------
+bool CBanPanel::IsIPAddress(const char *id)
+{
+ int s1, s2, s3, s4;
+ return (4 == sscanf(id, "%d.%d.%d.%d", &s1, &s2, &s3, &s4));
+}
diff --git a/tracker/AdminServer/BanPanel.h b/tracker/AdminServer/BanPanel.h
new file mode 100644
index 0000000..af5c9e0
--- /dev/null
+++ b/tracker/AdminServer/BanPanel.h
@@ -0,0 +1,78 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef BANPANEL_H
+#define BANPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <KeyValues.h>
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/PropertyPage.h>
+#include "utlvector.h"
+
+#include "BanContextMenu.h"
+#include "RemoteServer.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CBanPanel : public vgui::PropertyPage, public IServerDataResponse
+{
+ DECLARE_CLASS_SIMPLE( CBanPanel, vgui::PropertyPage );
+public:
+ CBanPanel(vgui::Panel *parent, const char *name);
+ ~CBanPanel();
+
+ virtual void OnResetData();
+
+protected:
+ // property page handlers
+ virtual void OnPageShow();
+
+ virtual void OnThink();
+
+ // server response on user data
+ virtual void OnServerDataResponse(const char *value, const char *response);
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+
+private:
+ MESSAGE_FUNC( AddBan, "addban" );
+ MESSAGE_FUNC( RemoveBan, "removeban" );
+ MESSAGE_FUNC( ChangeBan, "changeban" );
+
+ MESSAGE_FUNC_CHARPTR( RemoveBanByID, "removebanbyid", id );
+ MESSAGE_FUNC_CHARPTR_CHARPTR( ChangeBanTimeByID, "AddBanValue", id, time );
+ MESSAGE_FUNC_PARAMS( OnCvarChangeValue, "CvarChangeValue", kv );
+
+ // returns true if the id string is an IP address, false if it's a WON or STEAM ID
+ bool IsIPAddress(const char *id);
+
+ // msg handlers
+ MESSAGE_FUNC_INT( OnOpenContextMenu, "OpenContextMenu", itemID );
+ void OnEffectPlayer(KeyValues *data);
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+
+ MESSAGE_FUNC( ImportBanList, "importban" );
+ MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath );
+
+ vgui::ListPanel *m_pBanListPanel;
+ vgui::Button *m_pAddButton;
+ vgui::Button *m_pRemoveButton;
+ vgui::Button *m_pChangeButton;
+ vgui::Button *m_pImportButton;
+
+ CBanContextMenu *m_pBanContextMenu;
+ float m_flUpdateTime;
+ bool m_bPageViewed;
+};
+
+#endif // BANPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/BaseGamesPage.cpp b/tracker/AdminServer/BaseGamesPage.cpp
new file mode 100644
index 0000000..659ca15
--- /dev/null
+++ b/tracker/AdminServer/BaseGamesPage.cpp
@@ -0,0 +1,247 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "BaseGamesPage.h"
+#include "ServerListCompare.h"
+#include "util.h"
+#include "serverpage.h"
+
+#include <VGUI_Controls.h>
+#include <VGUI_CheckButton.h>
+#include <VGUI_ComboBox.h>
+#include <VGUI_ImagePanel.h>
+#include <VGUI_IScheme.h>
+#include <VGUI_IVGui.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_MenuButton.h>
+#include <VGUI_Menu.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_MouseCode.h>
+
+#include <stdio.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBaseGamesPage::CBaseGamesPage(vgui::Panel *parent, const char *name) : Frame(parent, name), m_Servers(this)
+{
+ ivgui()->AddTickSignal(GetVPanel());
+
+ //SetSize(500, 500);
+
+ //SetParent(parent); // doesn't have any effect....
+ m_pParent=parent;
+
+ // load the password icon
+ m_pPasswordIcon = new ImagePanel(NULL, NULL);
+ m_pPasswordIcon->SetImage(scheme()->GetImage(scheme()->GetDefaultScheme(), "server/icon_password"));
+
+ // Init UI
+// m_pConnect = new Button(this, "ConnectButton", "Connect");
+ m_pRefresh = new Button(this, "RefreshButton", "Refresh");
+ m_pRefresh->SetCommand("refresh");
+ //m_pRefresh->AddActionSignalTarget(this);
+
+ m_pAddIP = new Button(this, "AddIPButton", "Add IP");
+
+ m_pManage = new Button(this, "ManageButton", "Manage");
+ m_pManage->SetCommand(new KeyValues("Manage"));
+ m_pManage->AddActionSignalTarget(this);
+
+
+// m_pRefreshMenu = new Menu(this, "RefreshMenu");
+// m_pRefreshMenu->MakePopup();
+ //m_pRefresh->SetMenu(m_pRefreshMenu);
+ //m_pRefresh->SetOpenDirection(MenuButton::UP);
+ //m_pRefreshMenu->AddMenuItem("Refresh", "Get new info for servers in current list ", "refresh", this);
+ //m_pRefreshMenu->AddMenuItem("GetNewList", "Get new server list ", "getnewlist", this);
+ //m_pRefreshMenu->AddMenuItem("StopRefresh", "Stop refreshing server list ", "stoprefresh", this);
+ m_pGameList = new OurListPanel(this, "gamelist");
+
+ // Add the column headers
+ m_pGameList->AddColumnHeader(0, "Password", util->GetString(""), 20, false, NOT_RESIZABLE, NOT_RESIZABLE );
+ m_pGameList->AddColumnHeader(1, "Name", util->GetString(" Servers"), 50, true, RESIZABLE, RESIZABLE);
+ m_pGameList->AddColumnHeader(2, "GameDesc", util->GetString(" Game"), 80, true, RESIZABLE, NOT_RESIZABLE);
+ m_pGameList->AddColumnHeader(3, "Players", util->GetString(" Players"), 55, true, RESIZABLE, NOT_RESIZABLE);
+ m_pGameList->AddColumnHeader(4, "Map", util->GetString(" Map" ), 90, true, RESIZABLE, NOT_RESIZABLE);
+ m_pGameList->AddColumnHeader(5, "Ping", util->GetString(" Latency" ), 55, true, RESIZABLE, NOT_RESIZABLE);
+
+ // setup fast sort functions
+ m_pGameList->SetSortFunc(0, PasswordCompare);
+ m_pGameList->SetSortFunc(1, ServerNameCompare);
+ m_pGameList->SetSortFunc(2, GameCompare);
+ m_pGameList->SetSortFunc(3, PlayersCompare);
+ m_pGameList->SetSortFunc(4, MapCompare);
+ m_pGameList->SetSortFunc(5, PingCompare);
+
+ // Sort by ping time by default
+ m_pGameList->SetSortColumn(5);
+
+ m_pGameList->AddActionSignalTarget(this);
+
+// LoadControlSettings("Admin\\DialogAdminServerPage.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CBaseGamesPage::~CBaseGamesPage()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseGamesPage::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+/* // game list in middle
+ int x = 0, y = 0, wide, tall;
+ GetSize(wide, tall);
+ m_pGameList->SetBounds(10, 30, wide - 20, tall - 200);
+
+ Repaint();
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseGamesPage::OnTick()
+{
+ m_Servers.RunFrame();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseGamesPage::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ m_pGameList->SetFont(scheme()->GetFont(scheme()->GetDefaultScheme(), "DefaultSmall"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets information about specified server
+//-----------------------------------------------------------------------------
+serveritem_t &CBaseGamesPage::GetServer(unsigned int serverID)
+{
+ return m_Servers.GetServer(serverID);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: call to let the UI now whether the game list is currently refreshing
+//-----------------------------------------------------------------------------
+void CBaseGamesPage::SetRefreshing(bool state)
+{
+ if(!CServerPage::GetInstance())
+ {
+ return;
+ }
+
+ if (state)
+ {
+ CServerPage::GetInstance()->UpdateStatusText("Refreshing server list...");
+ }
+ else
+ {
+ CServerPage::GetInstance()->UpdateStatusText("");
+ }
+
+// m_pRefreshMenu->FindChildByName("Refresh")->SetVisible(!state);
+ //m_pRefreshMenu->FindChildByName("GetNewList")->SetVisible(!state);
+// m_pRefreshMenu->FindChildByName("StopRefresh")->SetVisible(state);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseGamesPage::OnCommand(const char *command)
+{
+ if (!stricmp(command, "Connect"))
+ {
+ OnBeginConnect();
+ }
+ else if (!stricmp(command, "stoprefresh"))
+ {
+ // cancel the existing refresh
+ StopRefresh();
+ }
+ else if (!stricmp(command, "refresh"))
+ {
+ // start a new refresh
+ StartRefresh();
+ }
+ else if (!stricmp(command, "GetNewList"))
+ {
+ GetNewServerList();
+ }
+ else if (!stricmp(command, "addip"))
+ {
+ PostMessage(this,new KeyValues("AddServerByName")); // CFavorites handles this message
+ }
+ else if (!stricmp(command, "config"))
+ {
+ CServerPage::GetInstance()->ConfigPanel();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the game dir combo box is changed
+//-----------------------------------------------------------------------------
+void CBaseGamesPage::OnTextChanged(Panel *panel, const char *text)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles filter dropdown being toggled
+//-----------------------------------------------------------------------------
+void CBaseGamesPage::OnButtonToggled(Panel *panel, int state)
+{
+
+ // treat changing these buttons like any other filter has changed
+ OnTextChanged(panel, "");
+
+}
+
+void CBaseGamesPage::OnManage()
+{
+ if (m_pGameList->GetNumSelectedRows())
+ {
+ // get the server
+ unsigned int serverID = m_pGameList->GetDataItem(m_pGameList->GetSelectedRow(0))->userData;
+
+
+ PostMessage(m_pParent->GetVPanel(), new KeyValues("Manage", "serverID", serverID));
+ }
+}
+
+
+void CBaseGamesPage::OurListPanel::OnMouseDoublePressed( vgui::MouseCode code )
+{
+ PostMessage(m_pParent->GetVPanel(), new KeyValues("Manage"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message map
+//-----------------------------------------------------------------------------
+MessageMapItem_t CBaseGamesPage::m_MessageMap[] =
+{
+ MAP_MESSAGE_PTR_INT( CBaseGamesPage, "ButtonToggled", OnButtonToggled, "panel", "state" ),
+ MAP_MESSAGE_PTR_CONSTCHARPTR( CBaseGamesPage, "TextChanged", OnTextChanged, "panel", "text" ),
+ MAP_MESSAGE( CBaseGamesPage , "Manage",OnManage ),
+};
+IMPLEMENT_PANELMAP(CBaseGamesPage, BaseClass);
diff --git a/tracker/AdminServer/BaseGamesPage.h b/tracker/AdminServer/BaseGamesPage.h
new file mode 100644
index 0000000..b6e0eb6
--- /dev/null
+++ b/tracker/AdminServer/BaseGamesPage.h
@@ -0,0 +1,92 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef BASEGAMESPAGE_H
+#define BASEGAMESPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Frame.h>
+#include "ServerList.h"
+#include "IServerRefreshResponse.h"
+#include "server.h"
+#include "IGameList.h"
+
+namespace vgui
+{
+class ListPanel;
+class ImagePanel;
+class ComboBox;
+class ToggleButton;
+class CheckButton;
+class TextEntry;
+class MenuButton;
+class Menu;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Base property page for all the games lists (internet/favorites/lan/etc.)
+//-----------------------------------------------------------------------------
+class CBaseGamesPage : public vgui2::Frame, public IServerRefreshResponse, public IGameList
+{
+public:
+ CBaseGamesPage(vgui::Panel *parent, const char *name);
+ ~CBaseGamesPage();
+
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ // gets information about specified server
+ virtual serveritem_t &GetServer(unsigned int serverID);
+
+ virtual void SetRefreshing(bool state);
+
+protected:
+ virtual void OnTick();
+ virtual void OnCommand(const char *command);
+// virtual void OnOnMouseDoublePressed(enum vgui::MouseCode code);
+
+ // an inner class
+ class OurListPanel: public vgui::ListPanel
+ {
+ public:
+ OurListPanel(vgui::Panel *parent, const char *panelName): vgui::ListPanel(parent,panelName) { m_pParent=parent;};
+
+ virtual void OnMouseDoublePressed( vgui::MouseCode code );
+ private:
+ vgui::Panel *m_pParent;
+
+ };
+
+ // a list panel we grab the double click event from :)
+ OurListPanel *m_pGameList;
+ CServerList m_Servers;
+ vgui::ImagePanel *m_pPasswordIcon; // password icon
+
+private:
+ void OnButtonToggled(vgui::Panel *panel, int state);
+ void OnTextChanged(vgui::Panel *panel, const char *text);
+ void OnManage();
+
+ // command buttons
+ vgui::Button *m_pConnect;
+ vgui::Button *m_pRefresh;
+ vgui::Button *m_pManage;
+ vgui::Button *m_pAddIP;
+
+ vgui::Panel *m_pParent;
+
+// vgui::Menu *m_pRefreshMenu;
+
+ typedef vgui::Frame BaseClass;
+
+ DECLARE_PANELMAP();
+};
+
+
+#endif // BASEGAMESPAGE_H
diff --git a/tracker/AdminServer/BudgetPanelContainer.cpp b/tracker/AdminServer/BudgetPanelContainer.cpp
new file mode 100644
index 0000000..8070a7c
--- /dev/null
+++ b/tracker/AdminServer/BudgetPanelContainer.cpp
@@ -0,0 +1,175 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "BudgetPanelContainer.h"
+#include "mathlib/mathlib.h"
+#include "vgui/vgui_budgetpanelshared.h"
+#include "AdminServer.h"
+#include "ivprofexport.h"
+#include "vgui/ilocalize.h"
+#include "vgui/ISurface.h"
+#include "vgui/vgui_BaseBudgetPanel.h"
+
+
+// -------------------------------------------------------------------------------------------------------------------- //
+// CBudgetPanelAdmin declaration.
+// -------------------------------------------------------------------------------------------------------------------- //
+
+class CBudgetPanelAdmin : public CBudgetPanelShared
+{
+ typedef CBudgetPanelShared BaseClass;
+
+public:
+
+ CBudgetPanelAdmin( vgui::Panel *pParent, const char *pElementName );
+
+ virtual void SetupCustomConfigData( CBudgetPanelConfigData &data );
+ virtual void PostChildPaint();
+ virtual void OnTick();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ void DrawColoredText(
+ vgui::HFont font,
+ int x, int y,
+ int r, int g, int b, int a,
+ const char *pText,
+ ... );
+
+private:
+ Color m_budgetTextColor;
+};
+
+
+
+CBudgetPanelAdmin::CBudgetPanelAdmin( vgui::Panel *pParent, const char *pElementName ) :
+ BaseClass( pParent, pElementName, BUDGETFLAG_SERVER )
+{
+ MarkAsDedicatedServer();
+}
+
+
+void CBudgetPanelAdmin::SetupCustomConfigData( CBudgetPanelConfigData &data )
+{
+ GetBounds( data.m_xCoord, data.m_yCoord, data.m_Width, data.m_Height );
+}
+
+
+void CBudgetPanelAdmin::DrawColoredText(
+ vgui::HFont font,
+ int x, int y,
+ int r, int g, int b, int a,
+ const char *pText,
+ ... )
+{
+ char msg[4096];
+ va_list marker;
+ va_start( marker, pText );
+ _vsnprintf( msg, sizeof( msg ), pText, marker );
+ va_end( marker );
+
+ wchar_t unicodeStr[4096];
+ int nChars = g_pVGuiLocalize->ConvertANSIToUnicode( msg, unicodeStr, sizeof( unicodeStr ) );
+
+ vgui::surface()->DrawSetTextFont( font );
+ vgui::surface()->DrawSetTextColor( r, g, b, a );
+ vgui::surface()->DrawSetTextPos( x, y );
+ vgui::surface()->DrawPrintText( unicodeStr, nChars-1 );
+}
+
+
+void CBudgetPanelAdmin::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ m_budgetTextColor = pScheme->GetColor( "BrightControlText", Color( 0, 255, 0, 255 ) );
+}
+
+
+void CBudgetPanelAdmin::PostChildPaint()
+{
+ DrawColoredText( m_hFont, 0, 0, m_budgetTextColor[0], m_budgetTextColor[1], m_budgetTextColor[2], m_budgetTextColor[3], "%i fps (showbudget 3D driver time included)", RoundFloatToInt(g_fFrameRate) );
+ DrawColoredText( m_hFont, 0, 16, m_budgetTextColor[0], m_budgetTextColor[1], m_budgetTextColor[2], m_budgetTextColor[3], "%.1f ms", g_fFrameTimeLessBudget*1000.0f );
+
+ BaseClass::PostChildPaint();
+}
+
+
+void CBudgetPanelAdmin::OnTick()
+{
+ // Don't do all the work if we're not being drawn.
+ if ( IsVisible() )
+ {
+ SnapshotVProfHistory( 0 );
+ MarkForFullRepaint();
+ }
+
+ BaseClass::OnTick();
+}
+
+
+
+// ------------------------------------------------------------------------------------------------------------------------------------------------ //
+// The budget panel container class. Just holds CBudgetPanelAdmin.
+// ------------------------------------------------------------------------------------------------------------------------------------------------ //
+
+CBudgetPanelContainer::CBudgetPanelContainer(vgui::Panel *parent, const char *name) : PropertyPage(parent, name)
+{
+ LoadControlSettings("Admin/BudgetPanel.res", "PLATFORM");
+ m_pBudgetPanelAdmin = new CBudgetPanelAdmin( this, "AdminBudgetPanel" );
+ m_pBudgetPanelAdmin->SetVisible( false );
+ InvalidateLayout();
+}
+
+
+CBudgetPanelContainer::~CBudgetPanelContainer()
+{
+}
+
+
+void CBudgetPanelContainer::OnServerDataResponse( const char *value, const char *response )
+{
+}
+
+
+void CBudgetPanelContainer::Paint()
+{
+
+}
+
+
+void CBudgetPanelContainer::PerformLayout()
+{
+ BaseClass::PerformLayout();
+ int x, y, wide, tall;
+ GetBounds( x, y, wide, tall );
+ m_pBudgetPanelAdmin->SetBounds( 12, 12, wide - 24, tall - 24 );
+ m_pBudgetPanelAdmin->SendConfigDataToBase();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the page
+//-----------------------------------------------------------------------------
+void CBudgetPanelContainer::OnPageShow()
+{
+ if ( g_pVProfExport )
+ g_pVProfExport->AddListener();
+
+ m_pBudgetPanelAdmin->SetVisible( true );
+ BaseClass::OnPageShow();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides the page
+//-----------------------------------------------------------------------------
+void CBudgetPanelContainer::OnPageHide()
+{
+ if ( g_pVProfExport )
+ g_pVProfExport->RemoveListener();
+
+ m_pBudgetPanelAdmin->SetVisible( false );
+ BaseClass::OnPageHide();
+}
diff --git a/tracker/AdminServer/BudgetPanelContainer.h b/tracker/AdminServer/BudgetPanelContainer.h
new file mode 100644
index 0000000..c20adbf
--- /dev/null
+++ b/tracker/AdminServer/BudgetPanelContainer.h
@@ -0,0 +1,60 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef BUDGETPANELCONTAINER_H
+#define BUDGETPANELCONTAINER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include <KeyValues.h>
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/PropertyPage.h>
+#include "utlvector.h"
+#include "RemoteServer.h"
+
+
+class CBudgetPanelAdmin;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CBudgetPanelContainer : public vgui::PropertyPage, public IServerDataResponse
+{
+ DECLARE_CLASS_SIMPLE( CBudgetPanelContainer, vgui::PropertyPage );
+public:
+ CBudgetPanelContainer(vgui::Panel *parent, const char *name);
+ ~CBudgetPanelContainer();
+
+
+// Panel overrides.
+public:
+ virtual void Paint();
+ virtual void PerformLayout();
+
+
+// PropertyPage overrides.
+public:
+ void OnPageShow();
+ void OnPageHide();
+
+
+// IServerDataResponse overrides.
+public:
+ virtual void OnServerDataResponse(const char *value, const char *response);
+
+
+private:
+ CBudgetPanelAdmin *m_pBudgetPanelAdmin;
+};
+
+
+#endif // BUDGETPANELCONTAINER_H
diff --git a/tracker/AdminServer/ChatContextMenu.h b/tracker/AdminServer/ChatContextMenu.h
new file mode 100644
index 0000000..92a6a8a
--- /dev/null
+++ b/tracker/AdminServer/ChatContextMenu.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef CHATCONTEXTMENU_H
+#define CHATCONTEXTMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Menu.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic right-click context menu for servers
+//-----------------------------------------------------------------------------
+class CChatContextMenu : public vgui::Menu
+{
+public:
+ CChatContextMenu(vgui::Panel *parent);
+ ~CChatContextMenu();
+
+ // call this to activate the menu
+ void ShowMenu(vgui::Panel *target);
+private:
+ vgui::Panel *parent; // so we can send it messages
+};
+
+
+#endif // CHATCONTEXTMENU_H
diff --git a/tracker/AdminServer/ChatPanel.cpp b/tracker/AdminServer/ChatPanel.cpp
new file mode 100644
index 0000000..343f2d0
--- /dev/null
+++ b/tracker/AdminServer/ChatPanel.cpp
@@ -0,0 +1,87 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ChatPanel.h"
+#include "RemoteServer.h"
+
+#include <vgui/IVGui.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/RichText.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/PHandle.h>
+
+#include <stdio.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CChatPanel::CChatPanel(vgui::Panel *parent, const char *name) : PropertyPage(parent, name)
+{
+ m_pServerChatPanel = new RichText(this, "ServerChatText");
+ m_pServerChatPanel->SetMaximumCharCount(8000);
+
+ m_pEnterChatPanel = new TextEntry(this,"ChatMessage");
+
+ m_pSendChatButton = new Button(this, "SendChat", "#Chat_Panel_Send");
+ m_pSendChatButton->SetCommand(new KeyValues("SendChat"));
+ m_pSendChatButton->SetAsDefaultButton(true);
+
+ LoadControlSettings("Admin/ChatPanel.res", "PLATFORM");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CChatPanel::~CChatPanel()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the page
+//-----------------------------------------------------------------------------
+void CChatPanel::OnPageShow()
+{
+ BaseClass::OnPageShow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides the page
+//-----------------------------------------------------------------------------
+void CChatPanel::OnPageHide()
+{
+ BaseClass::OnPageHide();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: inserts a new string into the main chat panel
+//-----------------------------------------------------------------------------
+void CChatPanel::DoInsertString(const char *str)
+{
+ m_pServerChatPanel->InsertString(str);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: run when the send button is pressed, send a rcon "say" to the server
+//-----------------------------------------------------------------------------
+void CChatPanel::OnSendChat()
+{
+ // build a chat command and send it to the server
+ char chat_text[512];
+ strcpy(chat_text, "say ");
+ m_pEnterChatPanel->GetText(chat_text + 4, sizeof(chat_text) - 4);
+ if (strlen("say ") != strlen(chat_text))
+ {
+ RemoteServer().SendCommand(chat_text);
+
+ // the message is sent, zero the text
+ m_pEnterChatPanel->SetText("");
+ }
+}
diff --git a/tracker/AdminServer/ChatPanel.h b/tracker/AdminServer/ChatPanel.h
new file mode 100644
index 0000000..d99269b
--- /dev/null
+++ b/tracker/AdminServer/ChatPanel.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef CHATPANEL_H
+#define CHATPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <KeyValues.h>
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/PropertyPage.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CChatPanel : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( CChatPanel, vgui::PropertyPage );
+public:
+ CChatPanel(vgui::Panel *parent, const char *name);
+ ~CChatPanel();
+
+ // property page handlers
+ virtual void OnPageShow();
+ virtual void OnPageHide();
+ void DoInsertString(const char *str);
+
+private:
+ MESSAGE_FUNC( OnSendChat, "SendChat" );
+
+ vgui::RichText *m_pServerChatPanel;
+ vgui::TextEntry *m_pEnterChatPanel;
+ vgui::Button *m_pSendChatButton;
+};
+
+#endif // CHATPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/ClickableTabbedPanel.cpp b/tracker/AdminServer/ClickableTabbedPanel.cpp
new file mode 100644
index 0000000..e2c8616
--- /dev/null
+++ b/tracker/AdminServer/ClickableTabbedPanel.cpp
@@ -0,0 +1,40 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ClickableTabbedPanel.h"
+#include <vgui/KeyValues.h>
+
+
+using namespace vgui;
+
+CClickableTabbedPanel::CClickableTabbedPanel(vgui2::Panel *parent, const char *panelName) : vgui2::PropertySheet(parent,panelName)
+{
+
+ //PropertySheet::onTabPressed
+
+}
+
+CClickableTabbedPanel::~CClickableTabbedPanel()
+{
+
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : code -
+//-----------------------------------------------------------------------------
+/*void CClickableTabbedPanel::onMousePressed(MouseCode code)
+{
+ // check for context menu open
+ if (code == MOUSE_RIGHT)
+ {
+ postActionSignal(new KeyValues("OpenContextMenu", "itemID", -1));
+ }
+
+}*/
diff --git a/tracker/AdminServer/ClickableTabbedPanel.h b/tracker/AdminServer/ClickableTabbedPanel.h
new file mode 100644
index 0000000..ac3dfec
--- /dev/null
+++ b/tracker/AdminServer/ClickableTabbedPanel.h
@@ -0,0 +1,40 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef CLICKABLETABBEDPANEL_H
+#define CLICKABLETABBEDPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/MouseCode.h>
+
+#include <vgui_controls/PropertySheet.h>
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/Panel.h>
+
+namespace vgui
+{
+class Panel;
+};
+
+
+class CClickableTabbedPanel: public vgui2::PropertySheet
+{
+
+public:
+ CClickableTabbedPanel(vgui2::Panel *parent, const char *panelName);
+ ~CClickableTabbedPanel();
+
+
+private:
+// void onMousePressed(vgui2::MouseCode code);
+
+
+};
+
+#endif //CLICKABLETABBEDPANEL \ No newline at end of file
diff --git a/tracker/AdminServer/ConfigPanel.cpp b/tracker/AdminServer/ConfigPanel.cpp
new file mode 100644
index 0000000..fb1c6f5
--- /dev/null
+++ b/tracker/AdminServer/ConfigPanel.cpp
@@ -0,0 +1,181 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ConfigPanel.h"
+//#include "Info.h"
+
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ToggleButton.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/MessageBox.h>
+#include <vgui_controls/RadioButton.h>
+
+#include <stdio.h>
+
+using namespace vgui;
+
+static const long RETRY_TIME = 10000; // refresh server every 10 seconds
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CConfigPanel::CConfigPanel(vgui::Panel *parent, bool autorefresh,bool savercon,int refreshtime,
+ bool graphs, int graphsrefreshtime,bool getlogs) : Frame(parent, "ConfigPanel")
+{
+ 196, 181, 80,
+
+ SetMinimumSize(400,240);
+ SetSizeable(false);
+ MakePopup();
+
+ m_pOkayButton = new Button(this, "Okay", "#Okay_Button");
+ m_pCloseButton = new Button(this, "Close", "#Close_Button");
+
+ m_pRefreshCheckButton = new CheckButton(this, "RefreshCheckButton", "");
+
+ m_pRconCheckButton = new CheckButton(this, "RconCheckButton", "");
+
+ m_pRefreshTextEntry= new TextEntry(this,"RefreshTextEntry");
+
+ m_pGraphsButton = new CheckButton(this, "GraphsButton", "");
+ m_pGraphsRefreshTimeTextEntry= new TextEntry(this,"GraphsRefreshTimeTextEntry");
+
+ m_pLogsButton = new CheckButton(this, "LogsButton", "");
+
+ SetTitle("My servers - Options",true);
+
+ LoadControlSettings("Admin\\ConfigPanel.res", "PLATFORM");
+
+ m_pRefreshCheckButton->SetSelected(autorefresh);
+ m_pRconCheckButton->SetSelected(savercon);
+ m_pGraphsButton->SetSelected(graphs);
+ m_pLogsButton->SetSelected(getlogs);
+
+ m_pRefreshTextEntry->SetEnabled(m_pRefreshCheckButton->IsSelected());
+ m_pRefreshTextEntry->SetEditable(m_pRefreshCheckButton->IsSelected());
+ m_pGraphsRefreshTimeTextEntry->SetEnabled(m_pGraphsButton->IsSelected());
+ m_pGraphsRefreshTimeTextEntry->SetEditable(m_pGraphsButton->IsSelected());
+
+ char refreshText[20];
+ _snprintf(refreshText,20,"%i",refreshtime);
+
+ m_pRefreshTextEntry->SetText(refreshText);
+
+ _snprintf(refreshText,20,"%i",graphsrefreshtime);
+
+ m_pGraphsRefreshTimeTextEntry->SetText(refreshText);
+
+ SetVisible(true);
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CConfigPanel::~CConfigPanel()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the dialog
+//-----------------------------------------------------------------------------
+void CConfigPanel::Run()
+{
+ RequestFocus();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the dialog when it's closed
+//-----------------------------------------------------------------------------
+void CConfigPanel::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: turn on and off components when check boxes are checked
+//-----------------------------------------------------------------------------
+void CConfigPanel::OnButtonToggled(Panel *panel)
+{
+ if (panel == m_pRefreshCheckButton)
+ // you can only edit the refresh time if you allow auto refresh
+ {
+ m_pRefreshTextEntry->SetEnabled(m_pRefreshCheckButton->IsSelected());
+ m_pRefreshTextEntry->SetEditable(m_pRefreshCheckButton->IsSelected());
+ }
+ else if (panel == m_pGraphsButton)
+ // you can only edit the refresh time if you allow auto refresh
+ {
+ m_pGraphsRefreshTimeTextEntry->SetEnabled(m_pGraphsButton->IsSelected());
+ m_pGraphsRefreshTimeTextEntry->SetEditable(m_pGraphsButton->IsSelected());
+ }
+
+
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the text of a control by name
+//-----------------------------------------------------------------------------
+void CConfigPanel::SetControlText(const char *textEntryName, const char *text)
+{
+ TextEntry *entry = dynamic_cast<TextEntry *>(FindChildByName(textEntryName));
+ if (entry)
+ {
+ entry->SetText(text);
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Parse posted messages
+//
+//-----------------------------------------------------------------------------
+void CConfigPanel::OnCommand(const char *command)
+{
+
+ if(!stricmp(command,"okay"))
+ { // save away the new settings
+ char timeText[20];
+ int time,timeGraphs;
+
+ m_pRefreshTextEntry->GetText(timeText,20);
+ sscanf(timeText,"%i",&time);
+
+ memset(timeText, 0x0, sizeof(timeText));
+ m_pGraphsRefreshTimeTextEntry->GetText(timeText, 20);
+ sscanf(timeText,"%i",&timeGraphs);
+
+
+ if(time>0 && time < 9999 && timeGraphs>0 && timeGraphs< 9999)
+ {
+
+ OnClose();
+
+ }
+ else
+ {
+ MessageBox *dlg = new MessageBox ("#Config_Panel", "#Config_Time_Error");
+ dlg->DoModal();
+ }
+ }
+ else if(!stricmp(command,"close") )
+ {
+ Close();
+ }
+}
diff --git a/tracker/AdminServer/ConfigPanel.h b/tracker/AdminServer/ConfigPanel.h
new file mode 100644
index 0000000..270cad4
--- /dev/null
+++ b/tracker/AdminServer/ConfigPanel.h
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef CONFIGPANEL_H
+#define CONFIGPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CConfigPanel : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CConfigPanel, vgui::Frame );
+public:
+ CConfigPanel(vgui::Panel *parent, bool autorefresh,bool savercon,int refreshtime,bool graphs, int graphsrefreshtime,bool getlogs);
+ ~CConfigPanel();
+
+ void Run();
+
+protected:
+ // message handlers
+ MESSAGE_FUNC_PTR( OnButtonToggled, "ButtonToggled", panel );
+ MESSAGE_FUNC_PTR( OnRadioButtonChecked, "RadioButtonChecked", panel )
+ {
+ OnButtonToggled( panel );
+ }
+
+ // vgui overrides
+ virtual void OnClose();
+ virtual void OnCommand(const char *command);
+
+private:
+
+ void SetControlText(const char *textEntryName, const char *text);
+
+ vgui::Button *m_pOkayButton;
+ vgui::Button *m_pCloseButton;
+ vgui::CheckButton *m_pRconCheckButton;
+ vgui::CheckButton *m_pRefreshCheckButton;
+ vgui::TextEntry *m_pRefreshTextEntry;
+ vgui::CheckButton *m_pGraphsButton;
+ vgui::TextEntry *m_pGraphsRefreshTimeTextEntry;
+ vgui::CheckButton *m_pLogsButton;
+};
+
+#endif // CONFIGPANEL_H
diff --git a/tracker/AdminServer/DialogAddBan.cpp b/tracker/AdminServer/DialogAddBan.cpp
new file mode 100644
index 0000000..5464ea9
--- /dev/null
+++ b/tracker/AdminServer/DialogAddBan.cpp
@@ -0,0 +1,250 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+#include "DialogAddBan.h"
+
+#include <vgui/ISurface.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/MessageBox.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CDialogAddBan::CDialogAddBan(vgui::Panel *parent) : Frame(parent, "DialogAddBan")
+{
+ SetSize(320, 200);
+ SetTitle("#Game_Ban_Add_Title", false);
+
+ m_pIDTextEntry = new TextEntry(this, "IDTextEntry");
+
+ m_pOkayButton = new Button(this, "OkayButton", "#Okay_Button");
+
+ m_pPermBanRadio = new RadioButton(this, "PermBanRadio", "#Add_Ban_Time_Permanent");
+ m_pTempBanRadio = new RadioButton(this, "TempBanRadio", "#Add_Ban_Time_Temporary");
+ m_pPermBanRadio->SetSelected(true);
+
+ m_pTimeTextEntry = new TextEntry(this, "TimeTextEntry");
+ m_pTimeCombo = new ComboBox(this, "TimeCombo",3,false);
+ int defaultItem = m_pTimeCombo->AddItem("#Add_Ban_Period_Minutes", NULL);
+ m_pTimeCombo->AddItem("#Add_Ban_Period_Hours", NULL);
+ m_pTimeCombo->AddItem("#Add_Ban_Period_Days", NULL);
+ m_pTimeCombo->ActivateItem(defaultItem);
+
+ LoadControlSettings("Admin\\DialogAddBan.res", "PLATFORM");
+
+ SetTitle("#Add_Ban_Title", true);
+ SetSizeable(false);
+
+ // set our initial position in the middle of the workspace
+ MoveToCenterOfScreen();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CDialogAddBan::~CDialogAddBan()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: initializes the dialog and brings it to the foreground
+//-----------------------------------------------------------------------------
+void CDialogAddBan::Activate(const char *type,const char *player,const char *authid)
+{
+
+ m_cType=type;
+
+ m_pOkayButton->SetAsDefaultButton(true);
+ MakePopup();
+ MoveToFront();
+
+ RequestFocus();
+ m_pIDTextEntry->RequestFocus();
+ SetVisible(true);
+
+ SetTextEntry("PlayerTextEntry",player);
+ SetTextEntry("IDTextEntry",authid);
+
+ BaseClass::Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the text of a labell by name
+//-----------------------------------------------------------------------------
+void CDialogAddBan::SetLabelText(const char *textEntryName, const char *text)
+{
+ Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
+ if (entry)
+ {
+ entry->SetText(text);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the text of a labell by name
+//-----------------------------------------------------------------------------
+void CDialogAddBan::SetTextEntry(const char *textEntryName, const char *text)
+{
+ TextEntry *entry = dynamic_cast<TextEntry *>(FindChildByName(textEntryName));
+ if (entry)
+ {
+ entry->SetText(text);
+ }
+}
+
+bool CDialogAddBan::IsIPCheck()
+{
+ char buf[64];
+ int dotCount=0;
+ m_pIDTextEntry->GetText(buf, sizeof(buf)-1);
+
+ for(unsigned int i=0;i<strlen(buf);i++)
+ {
+ if(buf[i]=='.')
+ {
+ dotCount++;
+ }
+ }
+
+ if(dotCount>0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDialogAddBan::OnCommand(const char *command)
+{
+ bool bClose = false;
+
+ if (!stricmp(command, "Okay"))
+ {
+ KeyValues *msg = new KeyValues("AddBanValue");
+ char buf[64],idbuf[64];
+ float time;
+ m_pIDTextEntry->GetText(idbuf, sizeof(idbuf));
+ m_pTimeTextEntry->GetText(buf, 64);
+
+
+ if(strlen(idbuf)<=0)
+ {
+ MessageBox *dlg = new MessageBox("#Add_Ban_Error", "#Add_Ban_ID_Invalid");
+ dlg->DoModal();
+ bClose=false;
+ }
+ else if(strlen(buf)<=0 && !m_pPermBanRadio->IsSelected())
+ {
+ MessageBox *dlg = new MessageBox("#Add_Ban_Error", "#Add_Ban_Time_Empty");
+ dlg->DoModal();
+ bClose=false;
+ }
+ else
+ {
+ if(m_pPermBanRadio->IsSelected())
+ {
+ time=0;
+ }
+ else
+ {
+ sscanf(buf,"%f",&time);
+ m_pTimeCombo->GetText(buf,64);
+ if(strstr(buf,"hour"))
+ {
+ time*=60;
+ }
+ else if(strstr(buf,"day"))
+ {
+ time*=(60*24);
+ }
+ if(time<0)
+ {
+ MessageBox *dlg = new MessageBox("#Add_Ban_Error", "#Add_Ban_Time_Invalid");
+ dlg->DoModal();
+ bClose=false;
+ }
+ }
+
+ if(time>=0)
+ {
+ msg->SetFloat("time", time);
+ msg->SetString("id", idbuf);
+ msg->SetString("type",m_cType);
+ msg->SetInt("ipcheck",IsIPCheck());
+
+ PostActionSignal(msg);
+
+ bClose = true;
+ }
+ }
+
+ }
+ else if (!stricmp(command, "Close"))
+ {
+ bClose = true;
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+
+ if (bClose)
+ {
+ Close();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDialogAddBan::PerformLayout()
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: deletes the dialog on close
+//-----------------------------------------------------------------------------
+void CDialogAddBan::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the perm/temp ban time radio buttons are pressed
+//-----------------------------------------------------------------------------
+void CDialogAddBan::OnButtonToggled(Panel *panel)
+{
+ if (panel == m_pPermBanRadio)
+ {
+ m_pTimeTextEntry->SetEnabled(false);
+ m_pTimeCombo->SetEnabled(false);
+ }
+ else
+ {
+ m_pTimeTextEntry->SetEnabled(true);
+ m_pTimeCombo->SetEnabled(true);
+ }
+
+ Repaint();
+}
diff --git a/tracker/AdminServer/DialogAddBan.h b/tracker/AdminServer/DialogAddBan.h
new file mode 100644
index 0000000..a580b8f
--- /dev/null
+++ b/tracker/AdminServer/DialogAddBan.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DIALOGADDBAN_H
+#define DIALOGADDBAN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/RadioButton.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Prompt for user to enter a password to be able to connect to the server
+//-----------------------------------------------------------------------------
+class CDialogAddBan : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CDialogAddBan, vgui::Frame );
+public:
+ CDialogAddBan(vgui::Panel *parent);
+ ~CDialogAddBan();
+
+ // initializes the dialog and brings it to the foreground
+ void Activate(const char *type,const char *player, const char *authid);
+
+ /* message returned:
+ "AddBanValue"
+ "id"
+ "time"
+ "type"
+ "ipcheck"
+ */
+
+ // make the input stars, ala a password entry dialog
+ void MakePassword();
+
+ // set the text in a certain label name
+ void SetLabelText(const char *textEntryName, const char *text);
+ void SetTextEntry(const char *textEntryName, const char *text);
+
+ // returns if the IPCheck check button is checked
+ bool IsIPCheck();
+
+private:
+ virtual void PerformLayout();
+ virtual void OnCommand(const char *command);
+ virtual void OnClose();
+ MESSAGE_FUNC_PTR( OnButtonToggled, "RadioButtonChecked", panel );
+
+ vgui::TextEntry *m_pTimeTextEntry;
+ vgui::TextEntry *m_pIDTextEntry;
+ vgui::Button *m_pOkayButton;
+ vgui::ComboBox *m_pTimeCombo;
+ vgui::RadioButton *m_pPermBanRadio;
+ vgui::RadioButton *m_pTempBanRadio;
+
+ const char *m_cType;
+};
+
+
+#endif // DIALOGADDBAN_H
diff --git a/tracker/AdminServer/DialogAddServer.cpp b/tracker/AdminServer/DialogAddServer.cpp
new file mode 100644
index 0000000..699fbf9
--- /dev/null
+++ b/tracker/AdminServer/DialogAddServer.cpp
@@ -0,0 +1,109 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "DialogAddServer.h"
+#include "INetAPI.h"
+#include "IGameList.h"
+#include "Server.h"
+
+#include <VGUI_MessageBox.h>
+#include <VGUI_KeyValues.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : *gameList - game list to add specified server to
+//-----------------------------------------------------------------------------
+CDialogAddServer::CDialogAddServer(IGameList *gameList) : Frame(NULL, "DialogAddServer")
+{
+ MakePopup();
+
+ m_pGameList = gameList;
+
+ SetTitle("Add Server - Servers", true);
+
+ LoadControlSettings("Admin\\DialogAddServer.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CDialogAddServer::~CDialogAddServer()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates this dialog
+//-----------------------------------------------------------------------------
+void CDialogAddServer::Open()
+{
+ MoveToFront();
+ RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CDialogAddServer::OnCommand(const char *command)
+{
+ if (!stricmp(command, "OK"))
+ {
+ OnOK();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles the OK button being pressed; adds the server to the game list
+//-----------------------------------------------------------------------------
+void CDialogAddServer::OnOK()
+{
+ // try and parse out IP address
+ const char *address = GetControlString("ServerNameText", "");
+ netadr_t netaddr;
+ if (net->StringToAdr(address, &netaddr))
+ {
+ // net address successfully parsed, add the server to the game list
+ serveritem_t server;
+ memset(&server, 0, sizeof(server));
+ for (int i = 0; i < 4; i++)
+ {
+ server.ip[i] = netaddr.ip[i];
+ }
+ server.port = (netaddr.port & 0xff) << 8 | (netaddr.port & 0xff00) >> 8;;
+ if (!server.port)
+ {
+ // use the default port since it was not entered
+ server.port = 27015;
+ }
+ m_pGameList->AddNewServer(server);
+ m_pGameList->StartRefresh();
+ }
+ else
+ {
+ // could not parse the ip address, popup an error
+ MessageBox *dlg = new MessageBox("Add Server - Error", "The server IP address you entered is invalid.");
+ dlg->DoModal();
+ }
+
+ // mark ourselves to be closed
+ PostMessage(this, new KeyValues("Close"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes dialog on close
+//-----------------------------------------------------------------------------
+void CDialogAddServer::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
diff --git a/tracker/AdminServer/DialogAddServer.h b/tracker/AdminServer/DialogAddServer.h
new file mode 100644
index 0000000..e18b2a1
--- /dev/null
+++ b/tracker/AdminServer/DialogAddServer.h
@@ -0,0 +1,42 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DIALOGADDSERVER_H
+#define DIALOGADDSERVER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Frame.h>
+
+class IGameList;
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog which lets the user add a server by IP address
+//-----------------------------------------------------------------------------
+class CDialogAddServer : public vgui::Frame
+{
+public:
+ CDialogAddServer(IGameList *gameList);
+ ~CDialogAddServer();
+
+ // activates this dialog
+ void Open();
+
+private:
+ virtual void OnClose();
+ virtual void OnCommand(const char *command);
+
+ void OnOK();
+
+ IGameList *m_pGameList;
+
+ typedef vgui::Frame BaseClass;
+};
+
+
+#endif // DIALOGADDSERVER_H
diff --git a/tracker/AdminServer/DialogCvarChange.cpp b/tracker/AdminServer/DialogCvarChange.cpp
new file mode 100644
index 0000000..3c94d3a
--- /dev/null
+++ b/tracker/AdminServer/DialogCvarChange.cpp
@@ -0,0 +1,151 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+#include "DialogCvarChange.h"
+
+#include <vgui/IInput.h>
+#include <vgui/ISurface.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CDialogCvarChange::CDialogCvarChange(vgui::Panel *parent) : Frame(parent, "DialogCvarChange")
+{
+ SetSize(320, 200);
+
+ m_bAddCvarText = true;
+
+ m_pInfoLabel = new Label(this, "InfoLabel", "");
+ m_pCvarLabel = new Label(this, "CvarLabel", "");
+ m_pCvarEntry = new TextEntry(this, "CvarEntry");
+ m_pOkayButton = new Button(this, "OkayButton", "#Okay_Button");
+
+ LoadControlSettings("Admin/DialogCvarChange.res", "PLATFORM");
+
+ SetTitle("#Cvar_Title", true);
+
+ SetSizeable(false);
+ // set our initial position in the middle of the workspace
+ MoveToCenterOfScreen();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CDialogCvarChange::~CDialogCvarChange()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides value text
+//-----------------------------------------------------------------------------
+void CDialogCvarChange::MakePassword()
+{
+ m_pCvarEntry->SetTextHidden(true);
+ m_bAddCvarText = false; // this isn't asking about a cvar
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: initializes the dialog and brings it to the foreground
+//-----------------------------------------------------------------------------
+void CDialogCvarChange::Activate(const char *cvarName, const char *curValue, const char *type, const char *question)
+{
+ m_pCvarLabel->SetText(cvarName);
+ if (!m_bAddCvarText)
+ {
+ m_pCvarLabel->SetVisible(false); // hide this
+ }
+
+ m_pInfoLabel->SetText(question);
+
+ m_cType=type;
+
+ m_pOkayButton->SetAsDefaultButton(true);
+ MakePopup();
+ MoveToFront();
+
+ m_pCvarEntry->SetText(curValue);
+ m_pCvarEntry->RequestFocus();
+ RequestFocus();
+
+ // make it modal
+ input()->SetAppModalSurface(GetVPanel());
+ SetVisible(true);
+
+ BaseClass::Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the text of a labell by name
+//-----------------------------------------------------------------------------
+void CDialogCvarChange::SetLabelText(const char *textEntryName, const char *text)
+{
+ Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
+ if (entry)
+ {
+ entry->SetText(text);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles button presses
+//-----------------------------------------------------------------------------
+void CDialogCvarChange::OnCommand(const char *command)
+{
+ bool bClose = false;
+
+ if (!stricmp(command, "Okay"))
+ {
+ KeyValues *msg = new KeyValues("CvarChangeValue");
+ char buf[64];
+ m_pCvarLabel->GetText(buf,64);
+
+ msg->SetString("player", buf );
+ m_pCvarEntry->GetText(buf, sizeof(buf)-1);
+ msg->SetString("value", buf);
+ msg->SetString("type",m_cType);
+
+ PostActionSignal(msg);
+
+ bClose = true;
+ }
+ else if (!stricmp(command, "Close"))
+ {
+ bClose = true;
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+
+ if (bClose)
+ {
+ Close();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: deletes the dialog on close
+//-----------------------------------------------------------------------------
+void CDialogCvarChange::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
+
+
+
diff --git a/tracker/AdminServer/DialogCvarChange.h b/tracker/AdminServer/DialogCvarChange.h
new file mode 100644
index 0000000..0b4ee22
--- /dev/null
+++ b/tracker/AdminServer/DialogCvarChange.h
@@ -0,0 +1,58 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DIALOGCVARCHANGE_H
+#define DIALOGCVARCHANGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Prompt for user to enter a password to be able to connect to the server
+//-----------------------------------------------------------------------------
+class CDialogCvarChange : public vgui::Frame
+{
+public:
+ CDialogCvarChange(vgui::Panel *parent);
+ ~CDialogCvarChange();
+
+ // initializes the dialog and brings it to the foreground
+ void Activate(const char *cvarName, const char *curValue, const char *type, const char *question);
+
+ /* message returned:
+ "CvarChangeValue"
+ "player"
+ "value"
+ "type"
+ */
+
+ // make the input stars, ala a password entry dialog
+ void MakePassword();
+
+ // set the text in a certain label name
+ void SetLabelText(const char *textEntryName, const char *text);
+
+private:
+ virtual void OnCommand(const char *command);
+ virtual void OnClose();
+
+ vgui::Label *m_pInfoLabel;
+ vgui::Label *m_pCvarLabel;
+ vgui::TextEntry *m_pCvarEntry;
+ vgui::Button *m_pOkayButton;
+
+ bool m_bAddCvarText; // if true puts the cvar name into the dialog
+
+ typedef vgui::Frame BaseClass;
+ const char *m_cType;
+
+};
+
+
+#endif // DIALOGCVARCHANGE_H
diff --git a/tracker/AdminServer/DialogGameInfo.cpp b/tracker/AdminServer/DialogGameInfo.cpp
new file mode 100644
index 0000000..7299c51
--- /dev/null
+++ b/tracker/AdminServer/DialogGameInfo.cpp
@@ -0,0 +1,532 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "DialogGameInfo.h"
+#include "Info.h"
+#include "IRunGameEngine.h"
+#include "IGameList.h"
+#include "TrackerProtocol.h"
+#include "serverpage.h"
+#include "ServerList.h"
+#include "DialogServerPassword.h"
+
+#include <VGUI_Controls.h>
+#include <VGUI_ISystem.h>
+#include <VGUI_ISurface.h>
+#include <VGUI_IVGui.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_Label.h>
+#include <VGUI_TextEntry.h>
+#include <VGUI_Button.h>
+#include <VGUI_ToggleButton.h>
+#include <VGUI_RadioButton.h>
+
+#include <stdio.h>
+
+using namespace vgui;
+
+static const long RETRY_TIME = 10000; // refresh server every 10 seconds
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CDialogGameInfo::CDialogGameInfo(IGameList *gameList, unsigned int serverID, int serverIP, int serverPort) : Frame(NULL, "DialogGameInfo"), m_Servers(this)
+{
+ MakePopup();
+ SetBounds(0, 0, 512, 384);
+ m_bConnecting = false;
+ m_bServerFull = false;
+ m_bShowAutoRetryToggle = false;
+ m_bServerNotResponding = false;
+ m_bShowingExtendedOptions = false;
+
+ m_szPassword[0] = 0;
+
+ m_iServerID = serverID;
+
+ m_pConnectButton = new Button(this, "Connect", "&Join Game");
+ m_pCloseButton = new Button(this, "Close", "&Close");
+ m_pRefreshButton = new Button(this, "Refresh", "&Refresh");
+ m_pInfoLabel = new Label(this, "InfoLabel", "");
+ m_pAutoRetry = new ToggleButton(this, "AutoRetry", "&Auto-Retry");
+ m_pAutoRetry->AddActionSignalTarget(this);
+
+ m_pAutoRetryAlert = new RadioButton(this, "AutoRetryAlert", "A&lert me when a player slot is available on server.");
+ m_pAutoRetryJoin = new RadioButton(this, "AutoRetryJoin", "J&oin the server as soon as a player slot is available.");
+
+ m_pAutoRetryAlert->SetSelected(true);
+
+ m_pConnectButton->SetCommand(new KeyValues("Connect"));
+ m_pCloseButton->SetCommand(new KeyValues("Close"));
+ m_pRefreshButton->SetCommand(new KeyValues("Refresh"));
+
+ m_iRequestRetry = 0;
+
+ SetSizeable(false);
+
+ if (gameList)
+ {
+ // we already have the game info, fill it in
+ serveritem_t &server = gameList->GetServer(serverID);
+ m_iServerID = m_Servers.AddNewServer(server);
+ }
+ else
+ {
+ // create a new server to watch
+ serveritem_t server;
+ memset(&server, 0, sizeof(server));
+ *((int *)server.ip) = serverIP;
+ server.port = serverPort;
+ m_iServerID = m_Servers.AddNewServer(server);
+ }
+
+ // refresh immediately
+ RequestInfo();
+
+ // let us be ticked every frame
+ ivgui()->AddTickSignal(this->GetVPanel());
+
+ LoadControlSettings("Admin\\DialogGameInfo.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CDialogGameInfo::~CDialogGameInfo()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the dialog
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::Run(const char *titleName)
+{
+ char buf[512];
+ if (titleName)
+ {
+ sprintf(buf, "Game Info - %s", titleName);
+ }
+ else
+ {
+ strcpy(buf, "Game Info");
+ }
+ SetTitle(buf, true);
+
+ // get the info from the user
+ RequestInfo();
+
+ RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes which server to watch
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::ChangeGame(int serverIP, int serverPort)
+{
+ // check to see if it's the same game
+ serveritem_t &server = m_Servers.GetServer(m_iServerID);
+
+ if (*(int *)server.ip == serverIP && server.port == serverPort)
+ {
+ return;
+ }
+
+ // change the server
+ m_Servers.Clear();
+
+ // create a new server to watch
+ serveritem_t newServer;
+ memset(&newServer, 0, sizeof(newServer));
+ *((int *)newServer.ip) = serverIP;
+ newServer.port = serverPort;
+ m_iServerID = m_Servers.AddNewServer(newServer);
+
+ // start refresh immediately
+ RequestInfo();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Relayouts the data
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // get the server we're watching
+ serveritem_t &server = m_Servers.GetServer(m_iServerID);
+
+ SetControlText("ServerText", server.name);
+ SetControlText("GameText", server.gameDescription);
+ SetControlText("MapText", server.map);
+
+ char buf[128];
+ if (server.maxPlayers > 0)
+ {
+ sprintf(buf, "%d / %d", server.players, server.maxPlayers);
+ }
+ else
+ {
+ buf[0] = 0;
+ }
+ SetControlText("PlayersText", buf);
+
+ if (server.ip[0] && server.port)
+ {
+ char buf[64];
+ sprintf(buf, "%d.%d.%d.%d:%d", server.ip[0], server.ip[1], server.ip[2], server.ip[3], server.port);
+ SetControlText("ServerIPText", buf);
+ m_pConnectButton->SetEnabled(true);
+ }
+ else
+ {
+ SetControlText("ServerIPText", "");
+ m_pConnectButton->SetEnabled(false);
+ }
+
+ sprintf(buf, "%d", server.ping);
+ SetControlText("PingText", buf);
+
+ // set the info text
+ if (m_pAutoRetry->IsSelected())
+ {
+ if (server.players < server.maxPlayers)
+ {
+ m_pInfoLabel->SetText("Press 'Join Game' to connect to the server.");
+ }
+ else if (m_pAutoRetryJoin->IsSelected())
+ {
+ m_pInfoLabel->SetText("You will join the server as soon as a player slot is free.");
+ }
+ else
+ {
+ m_pInfoLabel->SetText("You will be alerted as soon player slot is free on the server.");
+ }
+ }
+ else if (m_bServerFull)
+ {
+ m_pInfoLabel->SetText("Could not connect - server is full.");
+ }
+ else if (m_bServerNotResponding)
+ {
+ char text[100];
+ _snprintf(text,100,"Server is not responding.%d.%d.%d.%d:%d", server.ip[0], server.ip[1], server.ip[2], server.ip[3], server.port);
+
+ m_pInfoLabel->SetText(text);
+ }
+ else
+ {
+ // clear the status
+ m_pInfoLabel->SetText("");
+ }
+
+ // auto-retry layout
+ m_pAutoRetry->SetVisible(m_bShowAutoRetryToggle);
+
+ if (m_pAutoRetry->IsSelected())
+ {
+ m_pAutoRetryAlert->SetVisible(true);
+ m_pAutoRetryJoin->SetVisible(true);
+ }
+ else
+ {
+ m_pAutoRetryAlert->SetVisible(false);
+ m_pAutoRetryJoin->SetVisible(false);
+ }
+
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up the current scheme colors
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ // force the label to get it's scheme settings
+ m_pInfoLabel->InvalidateLayout(true);
+ // override them
+ m_pInfoLabel->SetFgColor(GetSchemeColor("BrightControlText"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Forces the game info dialog to try and connect
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::Connect()
+{
+ OnConnect();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Connects the user to this game
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::OnConnect()
+{
+ // flag that we are attempting connection
+ m_bConnecting = true;
+
+ // reset state
+ m_bServerFull = false;
+ m_bServerNotResponding = false;
+
+ InvalidateLayout();
+
+ // need to refresh server before attempting to connect, to make sure there is enough room on the server
+ RequestInfo();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles Refresh button press, starts a re-ping of the server
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::OnRefresh()
+{
+ // re-ask the server for the game info
+ RequestInfo();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the dialog when it's closed
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Forces the whole dialog to redraw when the auto-retry button is toggled
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::OnButtonToggled(Panel *panel)
+{
+ if (panel == m_pAutoRetry)
+ {
+ ShowAutoRetryOptions(m_pAutoRetry->IsSelected());
+ }
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets whether the extended auto-retry options are visible or not
+// Input : state -
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::ShowAutoRetryOptions(bool state)
+{
+ // we need to extend the dialog
+ int growSize = 60;
+ if (!state)
+ {
+ growSize = -growSize;
+ }
+
+ // alter the dialog size accordingly
+ int wide, tall;
+ GetSize(wide, tall);
+ tall += growSize;
+ SetSize(wide, tall);
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the text of a control by name
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::SetControlText(const char *textEntryName, const char *text)
+{
+ TextEntry *entry = dynamic_cast<TextEntry *>(FindChildByName(textEntryName));
+ if (entry)
+ {
+ entry->SetText(text);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Requests the right info from the server
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::RequestInfo()
+{
+ // reset the time at which we auto-refresh
+ m_iRequestRetry = system()->GetTimeMillis() + RETRY_TIME;
+
+ if (!m_Servers.IsRefreshing())
+ {
+ m_Servers.AddServerToRefreshList(m_iServerID);
+ m_Servers.StartRefresh();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every frame, handles resending network messages
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::OnTick()
+{
+ // check to see if we should perform an auto-refresh
+ if (m_iRequestRetry && m_iRequestRetry < system()->GetTimeMillis())
+ {
+ // reask
+ RequestInfo();
+ }
+
+ m_Servers.RunFrame();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the server has successfully responded
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::ServerResponded(serveritem_t &server)
+{
+ if (m_bConnecting)
+ {
+ ConnectToServer();
+ }
+ else if (m_pAutoRetry->IsSelected())
+ {
+ // auto-retry is enabled, see if we can join
+ if (server.players < server.maxPlayers)
+ {
+ // there is a slot free, we can join
+
+ // make the sound
+ surface()->PlaySound("Servers\\game_ready.wav");
+
+ // flash this window
+ FlashWindow();
+
+ // if it's set, connect right away
+ if (m_pAutoRetryJoin->IsSelected())
+ {
+ ConnectToServer();
+ }
+ }
+ }
+
+ m_bServerNotResponding = false;
+
+ InvalidateLayout();
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when a server response has timed out
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::ServerFailedToRespond(serveritem_t &server)
+{
+ // the server didn't respond, mark that in the UI
+ // only mark if we haven't ever received a response
+ if (!server.hadSuccessfulResponse)
+ {
+ m_bServerNotResponding = true;
+ }
+
+ InvalidateLayout();
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Connects to the server
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::ConnectToServer()
+{
+ m_bConnecting = false;
+ serveritem_t &server = m_Servers.GetServer(m_iServerID);
+
+ // check to see if we need a password
+ if (server.password && !m_szPassword[0])
+ {
+ CDialogServerPassword *box = new CDialogServerPassword();
+ box->AddActionSignalTarget(this);
+ box->Activate(server.name, server.serverID);
+ return;
+ }
+
+ // check the player count
+ if (server.players >= server.maxPlayers)
+ {
+ // mark why we cannot connect
+ m_bServerFull = true;
+ // give them access to auto-retry options
+ m_bShowAutoRetryToggle = true;
+ InvalidateLayout();
+ return;
+ }
+
+ // tell the engine to connect
+ char buf[64];
+ sprintf(buf, "%d.%d.%d.%d:%d", server.ip[0], server.ip[1], server.ip[2], server.ip[3], server.port);
+
+ const char *gameDir = server.gameDir;
+ if (g_pRunGameEngine->IsRunning())
+ {
+ char command[256];
+
+ // set the server password, if any
+ if (m_szPassword[0])
+ {
+ sprintf(command, "password \"%s\"\n", m_szPassword);
+ g_pRunGameEngine->AddTextCommand(command);
+ }
+
+ // send engine command to change servers
+ sprintf(command, "connect %s\n", buf);
+ g_pRunGameEngine->AddTextCommand(command);
+ }
+ else
+ {
+ char command[256];
+// sprintf(command, " -game %s +connect %s", gameDir, buf);
+ sprintf(command, " +connect %s", buf);
+ if (m_szPassword[0])
+ {
+ strcat(command, " +password \"");
+ strcat(command, m_szPassword);
+ strcat(command, "\"");\
+ }
+
+ g_pRunGameEngine->RunEngine(gameDir, command);
+ }
+
+ // close this dialog
+ PostMessage(this, new KeyValues("Close"));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the current refresh list is complete
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::RefreshComplete()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles response from the get password dialog
+//-----------------------------------------------------------------------------
+void CDialogGameInfo::OnJoinServerWithPassword(const char *password)
+{
+ // copy out the password
+ v_strncpy(m_szPassword, password, sizeof(m_szPassword));
+
+ // retry connecting to the server again
+ OnConnect();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Message map
+//-----------------------------------------------------------------------------
+MessageMapItem_t CDialogGameInfo::m_MessageMap[] =
+{
+ MAP_MESSAGE( CDialogGameInfo, "Refresh", OnRefresh ),
+ MAP_MESSAGE( CDialogGameInfo, "Connect", OnConnect ),
+
+ MAP_MESSAGE_PTR( CDialogGameInfo, "ButtonToggled", OnButtonToggled, "panel" ),
+ MAP_MESSAGE_PTR( CDialogGameInfo, "RadioButtonChecked", OnButtonToggled, "panel" ),
+
+ MAP_MESSAGE_CONSTCHARPTR( CDialogGameInfo, "JoinServerWithPassword", OnJoinServerWithPassword, "password" ),
+};
+
+IMPLEMENT_PANELMAP( CDialogGameInfo, Frame );
diff --git a/tracker/AdminServer/DialogGameInfo.h b/tracker/AdminServer/DialogGameInfo.h
new file mode 100644
index 0000000..ef23223
--- /dev/null
+++ b/tracker/AdminServer/DialogGameInfo.h
@@ -0,0 +1,110 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DIALOGGAMEINFO_H
+#define DIALOGGAMEINFO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Frame.h>
+#include "ServerList.h"
+#include "IServerRefreshResponse.h"
+
+class KeyValues;
+
+namespace vgui
+{
+class Button;
+class ToggleButton;
+class RadioButton;
+class Label;
+class TextEntry;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CDialogGameInfo : public vgui::Frame, public IServerRefreshResponse
+{
+public:
+ CDialogGameInfo(class IGameList *gameList, unsigned int serverID, int serverIP = 0, int serverPort = 0);
+ ~CDialogGameInfo();
+
+ void Run(const char *titleName);
+ void ChangeGame(int serverIP, int serverPort);
+
+ // forces the dialog to attempt to connect to the server
+ void Connect();
+
+ // implementation of IServerRefreshResponse interface
+ // called when the server has successfully responded
+ virtual void ServerResponded(serveritem_t &server);
+
+ // called when a server response has timed out
+ virtual void ServerFailedToRespond(serveritem_t &server);
+
+ // called when the current refresh list is complete
+ virtual void RefreshComplete();
+
+protected:
+ // message handlers
+ void OnConnect();
+ void OnRefresh();
+ void OnButtonToggled(vgui::Panel *toggleButton);
+
+ // response from the get password dialog
+ void OnJoinServerWithPassword(const char *password);
+
+ DECLARE_PANELMAP();
+
+ // vgui overrides
+ void OnTick();
+ virtual void OnClose();
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+private:
+ long m_iRequestRetry; // time at which to retry the request
+
+ // methods
+ void RequestInfo();
+ void ConnectToServer();
+ void ShowAutoRetryOptions(bool state);
+
+ void SetControlText(const char *textEntryName, const char *text);
+
+ vgui::Button *m_pConnectButton;
+ vgui::Button *m_pCloseButton;
+ vgui::Button *m_pRefreshButton;
+ vgui::Label *m_pInfoLabel;
+ vgui::ToggleButton *m_pAutoRetry;
+ vgui::RadioButton *m_pAutoRetryAlert;
+ vgui::RadioButton *m_pAutoRetryJoin;
+
+ // the ID of the server we're watching
+ unsigned int m_iServerID;
+
+ // server refreshing object
+ CServerList m_Servers;
+
+ // true if we should try connect to the server when it refreshes
+ bool m_bConnecting;
+
+ // password, if entered
+ char m_szPassword[64];
+
+ // state
+ bool m_bServerNotResponding;
+ bool m_bServerFull;
+ bool m_bShowAutoRetryToggle;
+ bool m_bShowingExtendedOptions;
+
+ typedef vgui::Frame BaseClass;
+};
+
+#endif // DIALOGGAMEINFO_H
diff --git a/tracker/AdminServer/DialogKickPlayer.cpp b/tracker/AdminServer/DialogKickPlayer.cpp
new file mode 100644
index 0000000..2d55b92
--- /dev/null
+++ b/tracker/AdminServer/DialogKickPlayer.cpp
@@ -0,0 +1,130 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+#include "DialogKickPlayer.h"
+
+#include <VGUI_Button.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_Label.h>
+#include <VGUI_TextEntry.h>
+
+#include <VGUI_Controls.h>
+#include <VGUI_ISurface.h>
+
+using namespace vgui;
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CDialogKickPlayer::CDialogKickPlayer() : Frame(NULL, "DialogKickPlayer")
+{
+ SetSize(320, 200);
+
+ m_pInfoLabel = new Label(this, "InfoLabel", "Kick Player?");
+ m_pPlayerLabel = new Label(this, "PlayerLabel", "<player name>");
+ m_pOkayButton = new Button(this, "OkayButton", "&Okay");
+
+ LoadControlSettings("Admin\\DialogKickPlayer.res");
+
+ SetTitle("Kick/Ban/Status Player", true);
+
+ // set our initial position in the middle of the workspace
+ MoveToCenterOfScreen();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CDialogKickPlayer::~CDialogKickPlayer()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: initializes the dialog and brings it to the foreground
+//-----------------------------------------------------------------------------
+void CDialogKickPlayer::Activate(const char *playerName,const char *question,const char *type)
+{
+ m_pPlayerLabel->SetText(playerName);
+ m_pInfoLabel->SetText(question);
+ m_pInfoLabel->SizeToContents();
+
+// SetSize(
+ int wide,tall;
+ m_pInfoLabel->GetSize(wide,tall);
+
+ SetWide(max(wide+50,GetWide()));
+
+ m_cType=type;
+
+ m_pOkayButton->SetAsDefaultButton(true);
+ MakePopup();
+ MoveToFront();
+
+ RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CDialogKickPlayer::OnCommand(const char *command)
+{
+ bool bClose = false;
+
+ if (!stricmp(command, "Okay"))
+ {
+ KeyValues *msg = new KeyValues("KickPlayer");
+ char buf[64];
+ m_pPlayerLabel->GetText(buf,64);
+ msg->SetString("player", buf );
+ msg->SetString("type",m_cType);
+
+ PostActionSignal(msg);
+
+ bClose = true;
+ }
+ else if (!stricmp(command, "Close"))
+ {
+ bClose = true;
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+
+ if (bClose)
+ {
+ PostMessage(this, new KeyValues("Close"));
+ MarkForDeletion();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDialogKickPlayer::PerformLayout()
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: deletes the dialog on close
+//-----------------------------------------------------------------------------
+void CDialogKickPlayer::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
+
+
+
diff --git a/tracker/AdminServer/DialogKickPlayer.h b/tracker/AdminServer/DialogKickPlayer.h
new file mode 100644
index 0000000..c51d407
--- /dev/null
+++ b/tracker/AdminServer/DialogKickPlayer.h
@@ -0,0 +1,57 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DIALOGKICKPLAYER_H
+#define DIALOGKICKPLAYER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Frame.h>
+
+
+namespace vgui
+{
+class TextEntry;
+class Label;
+class Button;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Prompt for user to enter a password to be able to connect to the server
+//-----------------------------------------------------------------------------
+class CDialogKickPlayer : public vgui::Frame
+{
+public:
+ CDialogKickPlayer();
+ ~CDialogKickPlayer();
+
+ // initializes the dialog and brings it to the foreground
+ void Activate(const char *playerName, const char *question,const char *type);
+
+ /* message returned:
+ "KickPlayer"
+ "player"
+ "type"
+ */
+
+private:
+ virtual void PerformLayout();
+ virtual void OnCommand(const char *command);
+ virtual void OnClose();
+
+ vgui::Label *m_pInfoLabel;
+ vgui::Label *m_pPlayerLabel;
+ vgui::Button *m_pOkayButton;
+
+ typedef vgui::Frame BaseClass;
+ const char *m_cType;
+
+};
+
+
+#endif // DIALOGKICKPLAYER_H
diff --git a/tracker/AdminServer/DialogServerPassword.cpp b/tracker/AdminServer/DialogServerPassword.cpp
new file mode 100644
index 0000000..ffb3129
--- /dev/null
+++ b/tracker/AdminServer/DialogServerPassword.cpp
@@ -0,0 +1,119 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "DialogServerPassword.h"
+
+#include <VGUI_Button.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_Label.h>
+#include <VGUI_TextEntry.h>
+
+#include <VGUI_Controls.h>
+#include <VGUI_ISurface.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CDialogServerPassword::CDialogServerPassword() : Frame(NULL, "DialogServerPassword")
+{
+ m_iServerID = -1;
+ SetSize(320, 240);
+
+ m_pInfoLabel = new Label(this, "InfoLabel", "This server requires a password to join.");
+ m_pGameLabel = new Label(this, "GameLabel", "<game label>");
+ m_pPasswordEntry = new TextEntry(this, "PasswordEntry");
+ m_pConnectButton = new Button(this, "ConnectButton", "&Connect");
+ m_pPasswordEntry->SetTextHidden(true);
+
+ LoadControlSettings("Admin\\DialogServerPassword.res");
+
+ SetTitle("Server Requires Password - Servers", true);
+
+ // set our initial position in the middle of the workspace
+ MoveToCenterOfScreen();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CDialogServerPassword::~CDialogServerPassword()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: initializes the dialog and brings it to the foreground
+//-----------------------------------------------------------------------------
+void CDialogServerPassword::Activate(const char *serverName, unsigned int serverID)
+{
+ m_pGameLabel->SetText(serverName);
+ m_iServerID = serverID;
+
+ m_pConnectButton->SetAsDefaultButton(true);
+ MakePopup();
+ MoveToFront();
+ m_pPasswordEntry->RequestFocus();
+ RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CDialogServerPassword::OnCommand(const char *command)
+{
+ bool bClose = false;
+
+ if (!stricmp(command, "Connect"))
+ {
+ KeyValues *msg = new KeyValues("JoinServerWithPassword");
+ char buf[64];
+ m_pPasswordEntry->GetText(0, buf, sizeof(buf)-1);
+ msg->SetString("password", buf);
+ msg->SetInt("serverID", m_iServerID);
+ PostActionSignal(msg);
+
+ bClose = true;
+ }
+ else if (!stricmp(command, "Close"))
+ {
+ bClose = true;
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+
+ if (bClose)
+ {
+ PostMessage(this, new KeyValues("Close"));
+ MarkForDeletion();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDialogServerPassword::PerformLayout()
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: deletes the dialog on close
+//-----------------------------------------------------------------------------
+void CDialogServerPassword::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
+
+
+
diff --git a/tracker/AdminServer/DialogServerPassword.h b/tracker/AdminServer/DialogServerPassword.h
new file mode 100644
index 0000000..04f7537
--- /dev/null
+++ b/tracker/AdminServer/DialogServerPassword.h
@@ -0,0 +1,58 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DIALOGSERVERPASSWORD_H
+#define DIALOGSERVERPASSWORD_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Frame.h>
+
+
+namespace vgui
+{
+class TextEntry;
+class Label;
+class Button;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Prompt for user to enter a password to be able to connect to the server
+//-----------------------------------------------------------------------------
+class CDialogServerPassword : public vgui::Frame
+{
+public:
+ CDialogServerPassword();
+ ~CDialogServerPassword();
+
+ // initializes the dialog and brings it to the foreground
+ void Activate(const char *serverName, unsigned int serverID);
+
+ /* message returned:
+ "JoinServerWithPassword"
+ "serverID"
+ "password"
+ */
+
+private:
+ virtual void PerformLayout();
+ virtual void OnCommand(const char *command);
+ virtual void OnClose();
+
+ vgui::Label *m_pInfoLabel;
+ vgui::Label *m_pGameLabel;
+ vgui::TextEntry *m_pPasswordEntry;
+ vgui::Button *m_pConnectButton;
+
+ typedef vgui::Frame BaseClass;
+
+ int m_iServerID;
+};
+
+
+#endif // DIALOGSERVERPASSWORD_H
diff --git a/tracker/AdminServer/FavoriteGames.cpp b/tracker/AdminServer/FavoriteGames.cpp
new file mode 100644
index 0000000..be72489
--- /dev/null
+++ b/tracker/AdminServer/FavoriteGames.cpp
@@ -0,0 +1,815 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "FavoriteGames.h"
+
+#include "proto_oob.h"
+#include "ServerContextMenu.h"
+#include "ServerListCompare.h"
+#include "Socket.h"
+#include "util.h"
+#include "serverpage.h"
+#include "DialogAddServer.h"
+#include "FavoriteGames.h"
+#include "filesystem.h"
+#include "tier1/utlbuffer.h"
+
+#include <VGUI_Controls.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_IScheme.h>
+#include <VGUI_IVGui.h>
+#include <VGUI_ImagePanel.h>
+#include <VGUI_ISystem.h>
+#include <VGUI_MessageBox.h>
+#include <VGUI_Button.h>
+
+using namespace vgui;
+
+const int TIMEOUT = 99999;
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CFavoriteGames::CFavoriteGames(vgui::Panel *parent) : CBaseGamesPage(parent, "FavoriteGames")
+{
+ m_iServerRefreshCount = 0;
+ m_pImportFavoritesdlg = NULL;
+ m_bSaveRcon=false;
+ StartRefresh();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CFavoriteGames::~CFavoriteGames()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CFavoriteGames::LoadFavoritesList(KeyValues *favoritesData,bool loadrcon)
+{
+ // load in favorites
+ for (KeyValues *dat = favoritesData->GetFirstSubKey(); dat != NULL; dat = dat->GetNextKey())
+ {
+ serveritem_t server;
+ memset(&server, 0, sizeof(server));
+
+ const char *addr = dat->GetString("address");
+ int ip1, ip2, ip3, ip4, port;
+ sscanf(addr, "%d.%d.%d.%d:%d", &ip1, &ip2, &ip3, &ip4, &port);
+ server.ip[0] = ip1;
+ server.ip[1] = ip2;
+ server.ip[2] = ip3;
+ server.ip[3] = ip4;
+ server.port = port;
+ server.players = 0;
+ v_strncpy(server.name, dat->GetString("name"), sizeof(server.name));
+ v_strncpy(server.map, dat->GetString("map"), sizeof(server.map));
+ v_strncpy(server.gameDir, dat->GetString("gamedir"), sizeof(server.gameDir));
+ server.players = dat->GetInt("players");
+ server.maxPlayers = dat->GetInt("maxplayers");
+
+ if(loadrcon)
+ {
+ v_strncpy(server.rconPassword,dat->GetString("rconpassword"),sizeof(server.rconPassword));
+ }
+
+ // add to main list
+ AddNewServer(server);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: updates the Rconpassword for a server, and perhaps more later :)
+//-----------------------------------------------------------------------------
+
+void CFavoriteGames::UpdateServer(serveritem_t &serverIn)
+{
+ for (int i = 0; i < m_Servers.ServerCount(); i++)
+ {
+ serveritem_t &serverOut = m_Servers.GetServer(i);
+
+ if( !memcmp(serverOut.ip,serverIn.ip,sizeof(serverIn.ip)) &&
+ serverOut.port==serverIn.port)
+ {
+ // we have a match!
+
+ v_strncpy(serverOut.rconPassword,serverIn.rconPassword,sizeof(serverOut.rconPassword));
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: saves the current list of servers to the favorites section of the data file
+//-----------------------------------------------------------------------------
+void CFavoriteGames::SaveFavoritesList(KeyValues *favoritesData,bool savercon)
+{
+ favoritesData->Clear();
+
+ // loop through all the servers writing them into the doc
+ for (int i = 0; i < m_Servers.ServerCount(); i++)
+ {
+ serveritem_t &server = m_Servers.GetServer(i);
+
+ // always save away all the entries, even if they didn't respond this time
+ //if (server.doNotRefresh)
+ // continue;
+
+ KeyValues *dat = favoritesData->CreateNewKey();
+
+ dat->SetString("name", server.name);
+ dat->SetString("gamedir", server.gameDir);
+ dat->SetInt("players", server.players);
+ dat->SetInt("maxplayers", server.maxPlayers);
+ dat->SetString("map", server.map);
+ if(savercon)
+ {
+ dat->SetString("rconpassword",server.rconPassword);
+ }
+
+ char buf[64];
+ sprintf(buf, "%d.%d.%d.%d:%d", server.ip[0], server.ip[1], server.ip[2], server.ip[3], server.port);
+ dat->SetString("address", buf);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the game list supports the specified ui elements
+// Input : item -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CFavoriteGames::SupportsItem(InterfaceItem_e item)
+{
+ switch (item)
+ {
+ case GETNEWLIST:
+ case FILTERS:
+ default:
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: starts the servers refreshing
+//-----------------------------------------------------------------------------
+void CFavoriteGames::StartRefresh()
+{
+ // stop current refresh
+ m_Servers.StopRefresh();
+
+ // build the refresh list from the server list
+ for (int i = 0; i < m_Servers.ServerCount(); i++)
+ {
+ // When managing servers it doesn't matter if they don't respond
+ //if (m_Servers.GetServer(i).doNotRefresh)
+ // continue;
+
+ m_Servers.AddServerToRefreshList(i);
+ }
+
+ m_Servers.StartRefresh();
+
+ SetRefreshing(IsRefreshing());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets a new server list
+//-----------------------------------------------------------------------------
+void CFavoriteGames::GetNewServerList()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: stops current refresh/GetNewServerList()
+//-----------------------------------------------------------------------------
+void CFavoriteGames::StopRefresh()
+{
+ // stop the server list refreshing
+ m_Servers.StopRefresh();
+
+ // clear update states
+ m_iServerRefreshCount = 0;
+
+ // update UI
+ RefreshComplete();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the list is currently refreshing servers
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CFavoriteGames::IsRefreshing()
+{
+ return m_Servers.IsRefreshing();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds a new server to list
+// Input : &server -
+//-----------------------------------------------------------------------------
+void CFavoriteGames::AddNewServer(serveritem_t &newServer)
+{
+ // copy server into main server list
+ unsigned int index = m_Servers.AddNewServer(newServer);
+
+ // reget the server
+ serveritem_t &server = m_Servers.GetServer(index);
+ server.hadSuccessfulResponse = true;
+ server.doNotRefresh = false;
+ server.listEntry = NULL;
+ server.serverID = index;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Continues the refresh
+// Input : moreAvailable -
+// lastUnique -
+//-----------------------------------------------------------------------------
+void CFavoriteGames::ListReceived(bool moreAvailable, int lastUnique)
+{
+ m_Servers.StartRefresh();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when Connect button is pressed
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnBeginConnect()
+{
+ if (!m_pGameList->GetNumSelectedRows())
+ return;
+
+ // get the server
+ int serverIndex = m_pGameList->GetDataItem(m_pGameList->GetSelectedRow(0))->userData;
+
+ // stop the current refresh
+ StopRefresh();
+
+ // join the game
+ CServerPage::GetInstance()->JoinGame(this, serverIndex);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays the current game info without connecting
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnViewGameInfo()
+{
+ if (!m_pGameList->GetNumSelectedRows())
+ return;
+
+ // get the server
+ int serverIndex = m_pGameList->GetDataItem(m_pGameList->GetSelectedRow(0))->userData;
+
+ // stop the current refresh
+ StopRefresh();
+
+ // join the game
+ CServerPage::GetInstance()->OpenGameInfoDialog(this, serverIndex);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: reapplies filters (does nothing with this)
+//-----------------------------------------------------------------------------
+void CFavoriteGames::ApplyFilters()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the server has successfully responded
+// Input : &server -
+//-----------------------------------------------------------------------------
+void CFavoriteGames::ServerResponded(serveritem_t &server)
+{
+ // update UI
+ KeyValues *kv;
+ if (server.listEntry)
+ {
+ // we're updating an existing entry
+ kv = server.listEntry->kv;
+ server.listEntry->userData = server.serverID;
+ }
+ else
+ {
+ // new entry
+ kv = new KeyValues("Server");
+ }
+
+ if (server.name[0] && server.maxPlayers)
+ {
+ kv->SetString("name", server.name);
+ kv->SetString("map", server.map);
+ kv->SetString("GameDir", server.gameDir);
+ kv->SetString("GameDesc", server.gameDescription);
+ kv->SetPtr("password", server.password ? m_pPasswordIcon : NULL);
+
+ char buf[256];
+ sprintf(buf, "%d / %d", server.players, server.maxPlayers);
+ kv->SetString("Players", buf);
+ }
+
+ if(server.ping==TIMEOUT)
+ {
+ kv->SetString("Ping", "timeout");
+ }
+ else
+ {
+ kv->SetInt("Ping", server.ping);
+ }
+
+ if (!server.listEntry)
+ {
+ // new server, add to list
+ int index = m_pGameList->AddItem(kv, server.serverID);
+ server.listEntry = m_pGameList->GetDataItem(index);
+ }
+ else
+ {
+ m_pGameList->ApplyItemChanges(server.listEntry->row);
+ }
+
+ m_iServerRefreshCount++;
+
+ if (m_pGameList->GetItemCount() > 1)
+ {
+ char buf[64];
+ sprintf(buf, " Servers (%d)", m_pGameList->GetItemCount());
+ m_pGameList->SetColumnHeaderText(1, buf);
+ }
+ else
+ {
+ m_pGameList->SetColumnHeaderText(1, " Servers");
+ }
+
+ m_pGameList->Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when a server response has timed out, treated just like a normal server
+//-----------------------------------------------------------------------------
+void CFavoriteGames::ServerFailedToRespond(serveritem_t &server)
+{
+ server.ping=TIMEOUT;
+ ServerResponded(server);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the current refresh list is complete
+//-----------------------------------------------------------------------------
+void CFavoriteGames::RefreshComplete()
+{
+ SetRefreshing(false);
+ m_pGameList->SortList();
+ m_iServerRefreshCount = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: opens context menu (user right clicked on a server)
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnOpenContextMenu(int row)
+{
+ CServerContextMenu *menu = CServerPage::GetInstance()->GetContextMenu();
+ if (m_pGameList->GetNumSelectedRows())
+ {
+ // get the server
+ unsigned int serverID = m_pGameList->GetDataItem(m_pGameList->GetSelectedRow(0))->userData;
+ serveritem_t &server = m_Servers.GetServer(serverID);
+
+ // activate context menu
+ menu->ShowMenu(this, serverID, true, true, false,true);
+ menu->AddMenuItem("RemoveServer", "R&emove server from favorites", new KeyValues("RemoveFromFavorites"), this);
+ }
+ else
+ {
+ // no selected rows, so don't display default stuff in menu
+ menu->ShowMenu(this, -1, false, false, false,false);
+ }
+
+ menu->AddMenuItem("AddServerByName", "&Add server by IP address", new KeyValues("AddServerByName"), this);
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: refreshes a single server
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnRefreshServer(int serverID)
+{
+ // walk the list of selected servers refreshing them
+ for (int i = 0; i < m_pGameList->GetNumSelectedRows(); i++)
+ {
+ int row = m_pGameList->GetSelectedRow(i);
+
+ ListPanel::DATAITEM *data = m_pGameList->GetDataItem(row);
+ if (data)
+ {
+ serverID = data->userData;
+
+ // refresh this server
+ m_Servers.AddServerToRefreshList(serverID);
+ }
+ }
+
+ m_Servers.StartRefresh();
+ SetRefreshing(IsRefreshing());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds a server to the favorites
+// Input : serverID -
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnRemoveFromFavorites()
+{
+ // iterate the selection
+ while (m_pGameList->GetNumSelectedRows() > 0)
+ {
+ int row = m_pGameList->GetSelectedRow(0);
+ int serverID = m_pGameList->GetDataItem(row)->userData;
+
+ if (serverID >= m_Servers.ServerCount())
+ continue;
+
+ serveritem_t &server = m_Servers.GetServer(serverID);
+
+ // remove from favorites list
+ if (server.listEntry)
+ {
+ // find the row in the list and kill
+ m_pGameList->RemoveItem(server.listEntry->row);
+ server.listEntry = NULL;
+ }
+
+ server.doNotRefresh = true;
+ }
+
+ InvalidateLayout();
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a server by IP address
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnAddServerByName()
+{
+ // open the add server dialog
+ CDialogAddServer *dlg = new CDialogAddServer(this);
+ dlg->Open();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Load a file into a CUtlBuffer class
+//-----------------------------------------------------------------------------
+int LoadFileIntoBuffer(CUtlBuffer &buf, char *pszFilename)
+{
+ // Open the file
+ FileHandle_t fh = g_pFullFileSystem->Open( pszFilename, "rb" );
+ if (fh == 0)
+ {
+ MessageBox *dlg = new MessageBox ("Unable to open datafile.", false);
+ dlg->DoModal();
+ return 0; //file didn't load
+ }
+
+ int nFileSize = g_pFullFileSystem->Size(fh);
+
+ // Read the file in one gulp
+ buf.EnsureCapacity( nFileSize );
+ int result = g_pFullFileSystem->Read( buf.Base(), nFileSize, fh );
+ g_pFullFileSystem->Close( fh );
+
+ return nFileSize;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Import Favorite Servers from previous installations of
+// Halflife
+//-----------------------------------------------------------------------------
+void CFavoriteGames::ImportFavorites()
+{
+ // disabled for now due to filesystem not accepting non-relative paths
+ return;
+
+ char name[512];
+ // check if halflife is installed
+ if (vgui::system()->GetRegistryString("HKEY_LOCAL_MACHINE\\Software\\Valve\\Half-life\\InstallPath", name, sizeof(name)))
+ {
+ // attach name of favorites file
+ strcat(name, "\\favsvrs.dat");
+ }
+ // check if counterstrike is installed
+ else if (vgui::system()->GetRegistryString("HKEY_LOCAL_MACHINE\\Software\\Sierra OnLine\\Setup\\CSTRIKE\\Directory", name, sizeof(name)))
+ {
+ // attach name of favorites file
+ strcat(name, "\\favsvrs.dat");
+ }
+ else // no hl installation, no fav servers?
+ {
+ return;
+ }
+
+ // see if the favorite server list file exists.
+ FileHandle_t fh = g_pFullFileSystem->Open(name, "rb");
+ if ( !fh )
+ {
+ return;
+ }
+ g_pFullFileSystem->Close(fh);
+
+
+ // it exists! yay lets transfer the servers over into the server browser
+
+ // pop up a message about what we are doing
+ m_pImportFavoritesdlg = new MessageBox ("Updating Favorites", "Transferring your Favorites. This may take a minute...", this);
+ m_pImportFavoritesdlg->SetCommand("OnImportFavoritesFile");
+ m_pImportFavoritesdlg->AddActionSignalTarget(this);
+ // hide the ok button since they dont have to do anything
+ m_pImportFavoritesdlg->SetOkButtonVisible(false);
+ // don't let them close this window
+ m_pImportFavoritesdlg->DisableCloseButton(false);
+ // dont let them put this window on the menubar
+ m_pImportFavoritesdlg->SetMenuButtonVisible(false);
+ // Pop up the box
+ m_pImportFavoritesdlg->DoModal();
+ // execute the message box's command
+ KeyValues *command = new KeyValues("Command");
+ command->SetString("Command", "OnImportFavoritesFile");
+ // post the message with a delay so that the box will display before the command is executed
+ PostMessage(this, command, (float).1);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parse posted messages
+//
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnCommand(const char *command)
+{
+ if (!strcmp(command, "OnImportFavoritesFile"))
+ {
+ OnImportFavoritesFile();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Import Favorite Servers from previous installations of
+// Halflife
+//-----------------------------------------------------------------------------
+void CFavoriteGames::OnImportFavoritesFile()
+{
+ char name[512];
+ // check if they have halflife
+ if (vgui::system()->GetRegistryString("HKEY_LOCAL_MACHINE\\Software\\Valve\\Half-life\\InstallPath", name, sizeof(name)))
+ {
+ // add filename
+ strcat(name, "\\favsvrs.dat");
+ }
+ // check if they have counterstrike
+ else if (vgui::system()->GetRegistryString("HKEY_LOCAL_MACHINE\\Software\\Sierra OnLine\\Setup\\CSTRIKE\\Directory", name, sizeof(name)))
+ {
+ // add filename
+ strcat(name, "\\favsvrs.dat");
+ }
+ else // no hl installation, no fav servers? // should never hit this!
+ {
+ return;
+ }
+
+ // load the file in one gulp
+ CUtlBuffer buf ( 0, 1024, true);
+ int fileSize = LoadFileIntoBuffer(buf, name);
+ if ( fileSize == 0)
+ {
+ MessageBox *dlg = new MessageBox ("Unable to load favorites", "Error loading file.", this);
+ dlg->DoModal();
+ return; //file didn't load
+ }
+
+ // scan for the favorite servers
+ char data[255];
+ buf.GetString(data);
+ while (buf.TellGet() < fileSize)
+ {
+ // store the start of the server description so we can go back
+ // if its a favorite
+ int serverStart;
+ if ( strstr (data, "server") != NULL)
+ {
+ buf.GetString(data); // get the '{'
+ serverStart = buf.TellGet();
+ }
+
+ // check if server is a favorite
+ if ( strstr (data, "favorite") != NULL)
+ {
+ buf.GetString(data);
+ if ( strstr(data, "1") )// server is a favorite
+ {
+ // go back to the start and load the details
+ buf.SeekGet( CUtlBuffer::SEEK_HEAD, serverStart);
+ // try and add this server
+ if (!LoadAFavoriteServer (buf))
+ {
+ // file may be corrupt, had trouble parsing it
+ break;
+ };
+ }
+ }
+ buf.EatWhiteSpace();
+ buf.GetString(data);
+ }
+
+ // we are done. Hide the message box.
+ m_pImportFavoritesdlg->SetVisible(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Check to make sure we are reading what is expected
+//
+//-----------------------------------------------------------------------------
+bool CFavoriteGames::CheckForCorruption(char *data, const char *checkString)
+{
+ if (strcmp(data, checkString) != 0)
+ {
+ MessageBox *dlg = new MessageBox ("Unable to load favorites", "Error loading. File may be corrupt.");
+ dlg->DoModal();
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parse throught the details of a server and populate a serveritem_t structure
+// Add it to the favorites list at the end.
+//-----------------------------------------------------------------------------
+bool CFavoriteGames::LoadAFavoriteServer (CUtlBuffer &buf)
+{
+ serveritem_t fav;
+ char data[255];
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"address\""))
+ return false;;
+ buf.GetString(data);
+ int temp[4];
+ sscanf (data, "\"%d.%d.%d.%d\"\n", &temp[0], &temp[1], &temp[2], &temp[3]);
+ fav.ip[0] = temp[0];
+ fav.ip[1] = temp[1];
+ fav.ip[2] = temp[2];
+ fav.ip[3] = temp[3];
+
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"port\" \"%d\"", &fav.port );
+ if (fav.port < 0)
+ fav.port += 65536;
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"name\" \"%s\"", fav.name );
+ fav.name[strlen(fav.name)-1]='\0'; // remove trailing quote
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"map\" \"%s\"", fav.map );
+ fav.map[strlen(fav.map)-1]='\0'; // remove trailing quote
+
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"game\" \"%s\"", fav.gameDescription );
+ fav.gameDescription[strlen(fav.gameDescription)-1]='\0'; // remove trailing quote
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"dir\" \"%s\"", fav.gameDir );
+ fav.gameDir[strlen(fav.gameDir)-1
+ ]='\0'; // remove trailing quote
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"url\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"dl\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"maxplayers\" \"%d\"", &fav.maxPlayers );
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"currentplayers\" \"%d\"", &fav.players );
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"protocol\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"favorite\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"ipx\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"mod\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"version\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"size\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"svtype\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"svos\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.EatWhiteSpace();
+ buf.Scanf ("\"password\" \"%d\"\n", &fav.password );
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"svside\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"cldll\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"lan\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"svping\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"noresponse\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"packetloss\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"status\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"filtered\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"fullmax\""))
+ return false;;
+ buf.GetString(data);
+
+ buf.GetString(data);
+ if (CheckForCorruption(data, "\"hlversion\""))
+ return false;;
+ buf.GetString(data);
+
+ AddNewServer(fav);
+
+ return true;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Message map
+//-----------------------------------------------------------------------------
+MessageMapItem_t CFavoriteGames::m_MessageMap[] =
+{
+ MAP_MESSAGE( CFavoriteGames, "ConnectToServer", OnBeginConnect ),
+ MAP_MESSAGE( CFavoriteGames, "ViewGameInfo", OnViewGameInfo ),
+ MAP_MESSAGE( CFavoriteGames, "RemoveFromFavorites", OnRemoveFromFavorites ),
+ MAP_MESSAGE( CFavoriteGames, "AddServerByName", OnAddServerByName ),
+ MAP_MESSAGE_INT( CFavoriteGames, "RefreshServer", OnRefreshServer, "serverID" ),
+ MAP_MESSAGE_INT( CFavoriteGames, "OpenContextMenu", OnOpenContextMenu, "row" ),
+};
+IMPLEMENT_PANELMAP(CFavoriteGames, BaseClass);
+
diff --git a/tracker/AdminServer/FavoriteGames.h b/tracker/AdminServer/FavoriteGames.h
new file mode 100644
index 0000000..6e9ddb0
--- /dev/null
+++ b/tracker/AdminServer/FavoriteGames.h
@@ -0,0 +1,121 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef FAVORITEGAMES_H
+#define FAVORITEGAMES_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "BaseGamesPage.h"
+
+#include "IGameList.h"
+#include "IServerRefreshResponse.h"
+#include "server.h"
+
+class KeyValues;
+
+namespace vgui
+{
+class ListPanel;
+class MessageBox;
+};
+
+class CUtlBuffer;
+
+//-----------------------------------------------------------------------------
+// Purpose: Favorite games list
+//-----------------------------------------------------------------------------
+class CFavoriteGames : public CBaseGamesPage
+{
+public:
+ CFavoriteGames(vgui::Panel *parent);
+ ~CFavoriteGames();
+
+ // favorites list, loads/saves into keyvalues
+ void LoadFavoritesList(vgui::KeyValues *favoritesData,bool loadrcon);
+ void SaveFavoritesList(vgui::KeyValues *favoritesData,bool savercon);
+
+ // property page handlers
+// virtual void OnPageShow();
+// virtual void OnPageHide();
+
+ // IGameList handlers
+ // returns true if the game list supports the specified ui elements
+ virtual bool SupportsItem(InterfaceItem_e item);
+
+ // starts the servers refreshing
+ virtual void StartRefresh();
+
+ // gets a new server list
+ virtual void GetNewServerList();
+
+ // stops current refresh/GetNewServerList()
+ virtual void StopRefresh();
+
+ // returns true if the list is currently refreshing servers
+ virtual bool IsRefreshing();
+
+ // gets information about specified server
+// virtual serveritem_t &GetServer(unsigned int serverID);
+
+ // adds a new server to list
+ virtual void AddNewServer(serveritem_t &server);
+
+ // marks that server list has been fully received
+ virtual void ListReceived(bool moreAvailable, int lastUnique);
+
+ // called when Connect button is pressed
+ virtual void OnBeginConnect();
+
+ // called to look at game info
+ virtual void OnViewGameInfo();
+
+ // reapplies filters (does nothing with this)
+ virtual void ApplyFilters();
+
+ // IServerRefreshResponse handlers
+ // called when the server has successfully responded
+ virtual void ServerResponded(serveritem_t &server);
+
+ // called when a server response has timed out
+ virtual void ServerFailedToRespond(serveritem_t &server);
+
+ // called when the current refresh list is complete
+ virtual void RefreshComplete();
+
+ virtual void ImportFavorites();
+ virtual void OnImportFavoritesFile();
+
+ // updates the rconPassword field for this server
+ void UpdateServer(serveritem_t &serverIn);
+
+
+private:
+ // context menu message handlers
+ void OnOpenContextMenu(int row);
+ void OnRefreshServer(int serverID);
+ void OnRemoveFromFavorites();
+ void OnAddServerByName();
+
+ void OnCommand(const char *command);
+ bool LoadAFavoriteServer (CUtlBuffer &buf);
+ bool CheckForCorruption(char *data, const char *checkString);
+
+ int m_iServerRefreshCount; // number of servers refreshed
+ bool m_bSaveRcon;
+
+ DECLARE_PANELMAP();
+ typedef CBaseGamesPage BaseClass;
+
+ // message that favorites are being imported
+ vgui::MessageBox *m_pImportFavoritesdlg;
+
+};
+
+
+#endif // FAVORITEGAMES_H
diff --git a/tracker/AdminServer/GamePanelInfo.cpp b/tracker/AdminServer/GamePanelInfo.cpp
new file mode 100644
index 0000000..44ff791
--- /dev/null
+++ b/tracker/AdminServer/GamePanelInfo.cpp
@@ -0,0 +1,341 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+#include "winsock.h" // this BUGGER defines PropertySheet to PropertySheetA ....
+#undef PropertySheet
+#include "tokenline.h"
+
+#include "GamePanelInfo.h"
+//#include "Info.h"
+#include "IRunGameEngine.h"
+
+#include "DialogCvarChange.h"
+#include "DialogAddBan.h"
+#include "BudgetPanelContainer.h"
+
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <KeyValues.h>
+#include <vgui/Cursor.h>
+#include <vgui/ILocalize.h>
+
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/MessageBox.h>
+#include <vgui_controls/QueryBox.h>
+#include <vgui_controls/Image.h>
+#include <vgui_controls/ImagePanel.h>
+
+#include "tier0/icommandline.h"
+
+#include <proto_oob.h>
+#include <netadr.h>
+
+using namespace vgui;
+
+static const long RETRY_TIME = 10000; // refresh server every 10 seconds
+static const long MAP_CHANGE_TIME = 20000; // refresh 20 seconds after a map change
+static const long RESTART_TIME = 60000; // refresh 60 seconds after a "_restart"
+
+#include "IManageServer.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CGamePanelInfo::CGamePanelInfo(vgui::Panel *parent, const char *name, const char *mod) : Frame(parent, name)
+{
+ SetSize(560, 420);
+ SetMinimumSize(560, 420);
+ m_bRemoteServer = false;
+ m_bShuttingDown = false;
+
+ // Create an Animating Image Panel
+ m_pAnimImagePanel = new AnimatingImagePanel(this, "AnAnimatingImagePanel");
+
+ // Each image file is named ss1, ss2, ss3... ss20, one image for each frame of the animation.
+ // This loads the 20 images in to the Animation class.
+ m_pAnimImagePanel->LoadAnimation("resource\\steam\\g", 12);
+
+ //!! animation temporarily disabled until UI pass done
+ //m_pAnimImagePanel->StartAnimation();
+ m_pAnimImagePanel->SetVisible(false);
+
+ // the main container for the various sub panels
+ m_pDetailsSheet = new PropertySheet(this, "Panels");
+
+ // the sub panels
+ m_pPlayerListPanel = new CPlayerPanel(this, "Player List");
+ m_pBanListPanel = new CBanPanel(this, "Ban List");
+ m_pServerLogPanel = new CRawLogPanel(this, "ServerLog");
+// chat panel disabled until we get the parsing done
+// m_pServerChatPanel = new CChatPanel(this, "ChatPanel");
+ m_pServerConfigPanel = new CServerConfigPanel(this, "ServerConfigPanel", mod);
+ m_pGraphsPanel = new CGraphPanel(this,"GraphsPanel");
+ m_pServerInfoPanel = new CServerInfoPanel(this, "ServerInfo");
+
+ if ( CommandLine()->CheckParm( "-BudgetPanel" ) )
+ m_pBudgetPanel = new CBudgetPanelContainer( this, "BudgetPanel" );
+ else
+ m_pBudgetPanel = NULL;
+
+ m_pServerInfoPanel->AddActionSignalTarget(this);
+
+ m_pDetailsSheet->AddPage(m_pServerInfoPanel,"#Game_Main_Settings");
+ m_pDetailsSheet->AddPage(m_pServerConfigPanel,"#Game_Configure");
+ m_pDetailsSheet->AddPage(m_pGraphsPanel,"#Game_Server_Statistics");
+ m_pDetailsSheet->AddPage(m_pPlayerListPanel,"#Game_Current_Players");
+ m_pDetailsSheet->AddPage(m_pBanListPanel,"#Game_Bans");
+
+ if ( m_pBudgetPanel )
+ m_pDetailsSheet->AddPage(m_pBudgetPanel,"#Game_Budgets");
+
+// chat panel disabled until we get the parsing done
+// m_pDetailsSheet->AddPage(m_pServerChatPanel,"#Game_Chat");
+ m_pDetailsSheet->AddPage(m_pServerLogPanel,"#Game_Console");
+
+ // let us be ticked every frame
+ ivgui()->AddTickSignal(this->GetVPanel());
+
+ LoadControlSettingsAndUserConfig("Admin\\DialogGamePanelInfo.res");
+
+ SetNewTitle(false, name);
+ SetVisible(true);
+
+ MoveToCenterOfScreen();
+ RequestFocus();
+ MoveToFront();
+
+ //!! hack, force the server info panel to refresh fast
+ // because the info it receives while loading the server is wrong
+ PostMessage(m_pServerInfoPanel, new KeyValues("ResetData"), 0.1f);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CGamePanelInfo::~CGamePanelInfo()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the title of the dialog
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::SetNewTitle(bool connectionFailed, const char *additional_text)
+{
+ const char *localized_title = "#Game_RemoteTitle";
+ if (!m_bRemoteServer)
+{
+ localized_title = "Game_LocalTitle";
+ }
+ else if (connectionFailed)
+ {
+ localized_title = "#Game_RemoteTitle_Failed";
+ }
+
+ wchar_t serverName[256];
+ g_pVGuiLocalize->ConvertANSIToUnicode(additional_text, serverName, sizeof(serverName));
+ wchar_t title[256];
+ g_pVGuiLocalize->ConstructString(title, sizeof(title), g_pVGuiLocalize->Find(localized_title), 1, serverName);
+
+ SetTitle(title, true);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the title
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnUpdateTitle()
+{
+ SetNewTitle(false, m_pServerInfoPanel->GetHostname());
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::SetAsRemoteServer(bool remote)
+{
+ m_bRemoteServer = remote;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Relayouts the data
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::PerformLayout()
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every frame, handles resending network messages
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnTick()
+{
+ // service the server I/O queue
+ RemoteServer().ProcessServerResponse();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles button responses
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnCommand(const char *command)
+{
+ if (!stricmp(command, "stop2"))
+ {
+ RemoteServer().SendCommand("quit");
+ m_bShuttingDown = true;
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: produces a dialog asking a player to enter a new ban
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnStop()
+{
+ QueryBox *box = new QueryBox("#Game_Stop_Server_Title", "#Game_Restart_Server");
+ box->AddActionSignalTarget(this);
+ box->SetOKButtonText("#Game_Stop_Server");
+ box->SetOKCommand(new KeyValues("Command", "command", "stop2"));
+ box->ShowWindow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: displays the help page
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnHelp()
+{
+ system()->ShellExecute("open", "Admin\\Admin.html");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Does any processing needed before closing the dialog
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnClose()
+{
+ if (m_bRemoteServer || m_bShuttingDown)
+ {
+ BaseClass::OnClose();
+ return;
+ }
+
+ // closing the window will kill the local server, notify user
+ OnStop();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: allow the build mode editor to edit the current sub panel
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::ActivateBuildMode()
+{
+// BaseClass::ActivateBuildMode();
+// return;
+ // no subpanel, no build mode
+ EditablePanel *pg = dynamic_cast<EditablePanel *>(m_pDetailsSheet->GetActivePage());
+ if (pg)
+ {
+ pg->ActivateBuildMode();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes text to the console
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::AddToConsole(const char *msg)
+{
+ if (m_pServerLogPanel)
+ {
+ // hack, look for restart message
+ if (*msg == 3 && !strncmp(msg + 1, "MasterRequestRestart", strlen("MasterRequestRestart")))
+ {
+ OnMasterRequestRestart();
+ }
+ else if (*msg == 3 && !strncmp(msg + 1, "MasterOutOfDate", strlen("MasterOutOfDate")))
+ {
+ const char *details = strstr( msg, "MasterOutOfDate" );
+ if ( details )
+ {
+ OnMasterOutOfDate(details + strlen("MasterOutOfDate"));
+ }
+ }
+ else
+ {
+ // nothing special, just print
+ m_pServerLogPanel->DoInsertString(msg);
+ }
+ }
+}
+
+void CGamePanelInfo::OnMasterOutOfDate( const char *msg)
+{
+#if !defined(_DEBUG)
+
+ // open a dialog informing user that they need to restart the server
+ if (!m_hOutOfDateQueryBox.Get())
+ {
+ char *fullmsg = (char *) _alloca( strlen(msg) + strlen( "\n\nDo you wish to shutdown now?\n") + 1 );
+
+ _snprintf( fullmsg, strlen(msg) + strlen( "\n\nDo you wish to shutdown now?\n") + 1 , "%s\n\nDo you wish to shutdown now?\n", msg );
+ m_hOutOfDateQueryBox = new QueryBox("Server restart pending", fullmsg);
+ m_hOutOfDateQueryBox->AddActionSignalTarget(this);
+ m_hOutOfDateQueryBox->SetOKCommand(new KeyValues("RestartServer"));
+ m_hOutOfDateQueryBox->ShowWindow();
+ }
+ else
+ {
+ // reshow the existing window
+ m_hOutOfDateQueryBox->Activate();
+ }
+
+#endif // !defined(_DEBUG)
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when master server has requested the dedicated server restart
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnMasterRequestRestart()
+{
+#if !defined(_DEBUG)
+
+ // open a dialog informing user that they need to restart the server
+ if (!m_hRestartQueryBox.Get())
+ {
+ m_hRestartQueryBox = new QueryBox("Server restart needed", "Your server is out of date, and will not be listed\non the master server until you restart.\n\nDo you wish to shutdown now?\n");
+ m_hRestartQueryBox->AddActionSignalTarget(this);
+ m_hRestartQueryBox->SetOKCommand(new KeyValues("RestartServer"));
+ m_hRestartQueryBox->ShowWindow();
+ }
+ else
+ {
+ // reshow the existing window
+ m_hRestartQueryBox->Activate();
+ }
+
+#endif // !defined(_DEBUG)
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Restarts the server
+//-----------------------------------------------------------------------------
+void CGamePanelInfo::OnRestartServer()
+{
+ //!! mark us as needing restart
+ //!! this doesn't work yet, just shut us down
+
+ // shut us down
+ RemoteServer().SendCommand("quit");
+ m_bShuttingDown = true;
+ Close();
+}
diff --git a/tracker/AdminServer/GamePanelInfo.h b/tracker/AdminServer/GamePanelInfo.h
new file mode 100644
index 0000000..c52dd60
--- /dev/null
+++ b/tracker/AdminServer/GamePanelInfo.h
@@ -0,0 +1,105 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef GAMEPANELINFO_H
+#define GAMEPANELINFO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//#include <string.h>
+
+#include <KeyValues.h>
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/AnimatingImagePanel.h>
+#include <vgui_controls/Image.h>
+#include <vgui_controls/PropertyPage.h>
+
+#undef PropertySheet
+
+#include <vgui_controls/PropertySheet.h>
+
+#include "BanContextMenu.h"
+#include "chatpanel.h"
+#include "rawlogpanel.h"
+#include "serverconfigpanel.h"
+#include "playerpanel.h"
+#include "banpanel.h"
+#include "graphpanel.h"
+#include "serverinfopanel.h"
+
+#define PASSWORD_LEN 64
+#define MOD_LEN 64
+
+#include "imanageserver.h" // IManageServer interface
+
+
+class CBudgetPanelContainer;
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CGamePanelInfo : public vgui::Frame, public IManageServer
+{
+ DECLARE_CLASS_SIMPLE( CGamePanelInfo, vgui::Frame );
+public:
+ CGamePanelInfo(vgui::Panel *parent, const char *name, const char *mod);
+ ~CGamePanelInfo();
+
+ // IManageServer interface extras
+ void ShowPage() { Activate(); }
+ void AddToConsole(const char *msg);
+ void SetAsRemoteServer(bool remote);
+
+protected:
+ // message handlers
+ void OnStop();
+ MESSAGE_FUNC( OnHelp, "Help" );
+ void OnMasterRequestRestart();
+ void OnMasterOutOfDate( const char *msg);
+ MESSAGE_FUNC( OnRestartServer, "RestartServer" );
+ MESSAGE_FUNC( OnUpdateTitle, "UpdateTitle" );
+ void SetNewTitle(bool connectionFailed, const char *additional_text); // sets the windows title
+
+ // vgui overrides
+ virtual void OnTick();
+ virtual void OnClose();
+ virtual void PerformLayout();
+ virtual void ActivateBuildMode();
+ virtual void OnCommand(const char *command);
+
+private:
+ // methods
+ vgui::ComboBox *m_pViewCombo;
+ vgui::AnimatingImagePanel *m_pAnimImagePanel;
+
+ // GUI pabels
+ // main property sheet
+ vgui::PropertySheet *m_pDetailsSheet;
+
+ // panels in the sheet
+ CPlayerPanel *m_pPlayerListPanel;
+ CBanPanel *m_pBanListPanel;
+ CRawLogPanel *m_pServerLogPanel;
+ CChatPanel *m_pServerChatPanel;
+ CServerConfigPanel *m_pServerConfigPanel;
+ CGraphPanel *m_pGraphsPanel;
+ CServerInfoPanel *m_pServerInfoPanel;
+ CBudgetPanelContainer *m_pBudgetPanel;
+
+ // state
+ bool m_bRemoteServer;
+ bool m_bShuttingDown;
+
+ vgui::DHANDLE<vgui::QueryBox> m_hRestartQueryBox;
+ vgui::DHANDLE<vgui::QueryBox> m_hOutOfDateQueryBox;
+};
+
+#endif // GAMEPANELINFO_H
diff --git a/tracker/AdminServer/GraphPanel.cpp b/tracker/AdminServer/GraphPanel.cpp
new file mode 100644
index 0000000..59ba15d
--- /dev/null
+++ b/tracker/AdminServer/GraphPanel.cpp
@@ -0,0 +1,731 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+
+#include "GraphPanel.h"
+
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/IScheme.h>
+#include <vgui/ILocalize.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ToggleButton.h>
+#include <vgui_controls/RadioButton.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/PropertySheet.h>
+#include <vgui_controls/CheckButton.h>
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+#define STATS_UPDATE_RATE 5.0f
+
+
+// colors for the various graph lines+controls
+Color CGraphPanel::CGraphsImage::CPUColor= Color(0,255,0,255); // green
+Color CGraphPanel::CGraphsImage::FPSColor= Color(255,0,0,255); // red
+Color CGraphPanel::CGraphsImage::NetInColor = Color(255,255,0,255); // yellow
+Color CGraphPanel::CGraphsImage::NetOutColor = Color(0,255,255,255); // light blue
+Color CGraphPanel::CGraphsImage::PlayersColor = Color(255,0,255,255); // purple
+Color CGraphPanel::CGraphsImage::PingColor = Color(0,0,0,255); // black
+//Color CGraphPanel::CGraphsImage::lineColor = Color(76,88,68,255);
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CGraphPanel::CGraphPanel(vgui::Panel *parent, const char *name) : PropertyPage(parent, name)
+{
+ SetMinimumSize(300,200);
+
+ m_pGraphsPanel = new ImagePanel(this,"Graphs");
+ m_pGraphs = new CGraphsImage();
+ m_pGraphsPanel->SetImage(m_pGraphs);
+
+ m_pInButton = new CheckButton(this,"InCheck","#Graph_In");
+ m_pOutButton = new CheckButton(this,"OutCheck","#Graph_Out");
+ m_pFPSButton = new CheckButton(this,"FPSCheck","#Graph_FPS");
+ m_pCPUButton = new CheckButton(this,"CPUCheck","#Graph_CPU");
+ m_pPINGButton = new CheckButton(this,"PingCheck","#Graph_Ping");
+ m_pPlayerButton = new CheckButton(this,"PlayersCheck","#Graph_Players");
+
+ m_pTimeCombo = new ComboBox(this, "TimeCombo",3,false);
+ m_pTimeCombo->AddItem("#Graph_Minutes", NULL);
+ int defaultItem = m_pTimeCombo->AddItem("#Graph_Hours", NULL);
+ m_pTimeCombo->AddItem("#Graph_Day", NULL);
+ m_pTimeCombo->ActivateItem(defaultItem);
+
+ m_pVertCombo = new ComboBox(this, "VertCombo",6,false);
+ m_pVertCombo->AddItem("#Graph_In", NULL);
+ m_pVertCombo->AddItem("#Graph_Out", NULL);
+ m_pVertCombo->AddItem("#Graph_FPS", NULL);
+ defaultItem = m_pVertCombo->AddItem("#Graph_CPU", NULL);
+ m_pVertCombo->AddItem("#Graph_Ping", NULL);
+ m_pVertCombo->AddItem("#Graph_Players", NULL);
+ m_pVertCombo->ActivateItem(defaultItem);
+
+ // now setup defaults
+ m_pCPUButton->SetSelected(true);
+ m_pInButton->SetSelected(false);
+ m_pOutButton->SetSelected(false);
+ m_pFPSButton->SetSelected(false);
+ m_pPINGButton->SetSelected(false);
+
+ LoadControlSettings("Admin/GraphPanel.res", "PLATFORM");
+
+ int w,h;
+ m_pGraphsPanel->GetSize(w,h);
+ m_pGraphs->SaveSize(w,h);
+ m_pGraphs->SetDraw(m_pCPUButton->IsSelected(),m_pFPSButton->IsSelected(),
+ m_pInButton->IsSelected(),m_pOutButton->IsSelected(),m_pPINGButton->IsSelected(),m_pPlayerButton->IsSelected());
+
+ m_pPINGButton->SetFgColor(m_pGraphs->GetPingColor());
+ m_pCPUButton->SetFgColor(m_pGraphs->GetCPUColor());
+ m_pFPSButton->SetFgColor(m_pGraphs->GetFPSColor());
+ m_pInButton->SetFgColor(m_pGraphs->GetInColor());
+ m_pOutButton->SetFgColor(m_pGraphs->GetOutColor());
+ m_pPlayerButton->SetFgColor(m_pGraphs->GetPlayersColor());
+
+ ivgui()->AddTickSignal(GetVPanel());
+ m_flNextStatsUpdateTime = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CGraphPanel::~CGraphPanel()
+{
+
+}
+
+void CGraphPanel::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ m_pGraphsPanel->SetBorder( pScheme->GetBorder("ButtonDepressedBorder"));
+ m_pGraphs->SetBgColor(GetSchemeColor("WindowBG", pScheme));
+ m_pGraphs->SetAxisColor(Color(76,88,68,255));
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the page
+//-----------------------------------------------------------------------------
+void CGraphPanel::OnPageShow()
+{
+ BaseClass::OnPageShow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides the page
+//-----------------------------------------------------------------------------
+void CGraphPanel::OnPageHide()
+{
+ BaseClass::OnPageHide();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called every frame to update stats page
+//-----------------------------------------------------------------------------
+void CGraphPanel::OnTick()
+{
+ if (m_flNextStatsUpdateTime > system()->GetFrameTime())
+ return;
+
+ m_flNextStatsUpdateTime = (float)system()->GetFrameTime() + STATS_UPDATE_RATE;
+ RemoteServer().RequestValue(this, "stats");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: tells the image about the new size
+//-----------------------------------------------------------------------------
+void CGraphPanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+ int w,h,x,y;
+ m_pGraphsPanel->GetBounds(x,y,w,h);
+
+ m_pGraphs->SaveSize(w,h); // tell the image about the resize
+
+ // push the mid axis label to the middle of the image
+ Label *entry = dynamic_cast<Label *>(FindChildByName("AxisMid"));
+ if (entry)
+ {
+ int entry_x,entry_y;
+ entry->GetPos(entry_x,entry_y);
+ entry->SetPos(entry_x,y+(h/2)-8);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles stats command returns
+//-----------------------------------------------------------------------------
+void CGraphPanel::OnServerDataResponse(const char *value, const char *response)
+{
+ if (!stricmp(value, "stats"))
+ {
+ // parse the stats out of the response
+ Points_t p;
+ float uptime, users;
+ sscanf(response, "%f %f %f %f %f %f %f", &p.cpu, &p.in, &p.out, &uptime, &users, &p.fps, &p.players);
+ p.cpu = p.cpu / 100; // its given as a value between 0<x<100, we want 0<x<1
+ p.ping = 0;
+ p.time = (float)system()->GetCurrentTime();
+ m_pGraphs->AddPoint(p);
+
+ // days:hours:minutes:seconds
+ char timeText[64];
+ _snprintf(timeText, sizeof(timeText), "%i", (int)p.players);
+ SetControlString("TotalUsersLabel", timeText);
+
+ // mark the vert combo has changed to force it to update graph ranges
+ m_pVertCombo->GetText(timeText, 64);
+ OnTextChanged(m_pVertCombo, timeText);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: the paint routine for the graph image. Handles the layout and drawing of the graph image
+//-----------------------------------------------------------------------------
+void CGraphPanel::CGraphsImage::Paint()
+{
+ int x,y;
+ float distPoints; // needs to be a float, rounding errors cause problems with lots of points
+ int bottom=5; // be 5 pixels above the bottom
+ int left=2;
+
+ int *pCpuX=NULL, *pCpuY=NULL;
+ int *pInX=NULL, *pInY=NULL;
+ int *pOutX=NULL, *pOutY=NULL;
+ int *pFPSX=NULL, *pFPSY=NULL;
+ int *pPingX=NULL, *pPingY=NULL;
+ int *pPlayersX=NULL, *pPlayersY=NULL;
+
+ GetSize(x,y);
+
+ SetColor(bgColor);
+ SetBkColor(bgColor);
+ DrawFilledRect(0,0,x,y);
+
+ y-=4; // borders
+ x-=4;
+
+
+ if(!cpu && !fps && !net_i && !net_o && !ping && !players) // no graphs selected
+ return;
+
+ if(points.Count()<2)
+ return; // not enough points yet...
+
+ if(x<=200 || y<=100)
+ return; // to small
+
+
+ distPoints= static_cast<float>(x)/static_cast<float>(points.Count()-1);
+ if(distPoints<=0)
+ {
+ distPoints=1;
+ }
+
+ SetColor(lineColor);
+ SetBkColor(lineColor);
+ //DrawLine(4,5,x,5);
+ DrawLine(4,y/2,x,y/2);
+ //DrawLine(4,y,x,y);
+
+ float RangePing=maxPing;
+ float RangeFPS=maxFPS;
+ float Range=0;
+ float RangePlayers=maxPlayers;
+
+
+ if(ping)
+ {
+ RangePing+=static_cast<float>(maxPing*0.1); // don't let the top of the range touch the top of the panel
+
+ if(RangePing<=1)
+ { // don't let the zero be at the top of the screen
+ RangePing=1.0;
+ }
+ pPingX = new int[points.Count()];
+ pPingY = new int[points.Count()];
+ }
+
+ if(cpu)
+ {
+ pCpuX = new int[points.Count()];
+ pCpuY = new int[points.Count()];
+ }
+
+ if(fps)
+ {
+ RangeFPS+=static_cast<float>(maxFPS*0.1); // don't let the top of the range touch the top of the panel
+
+ if(RangeFPS<=1)
+ { // don't let the zero be at the top of the screen
+ RangeFPS=1.0;
+ }
+ pFPSX = new int[points.Count()];
+ pFPSY = new int[points.Count()];
+ }
+
+ if(net_i)
+ {
+
+ // put them on a common scale, base it at zero
+ Range = max(maxIn,maxOut);
+
+ Range+=static_cast<float>(Range*0.1); // don't let the top of the range touch the top of the panel
+
+ if(Range<=1)
+ { // don't let the zero be at the top of the screen
+ Range=1.0;
+ }
+
+ pInX = new int[points.Count()];
+ pInY = new int[points.Count()];
+ }
+
+ if(net_o)
+ {
+ // put them on a common scale, base it at zero
+ Range = max(maxIn,maxOut);
+
+ Range+=static_cast<float>(Range*0.1); // don't let the top of the range touch the top of the panel
+
+ if(Range<=1)
+ { // don't let the zero be at the top of the screen
+ Range=1.0;
+ }
+
+ pOutX = new int[points.Count()];
+ pOutY = new int[points.Count()];
+ }
+
+ if(players)
+ {
+ RangePlayers+=static_cast<float>(maxPlayers*0.1); // don't let the top of the range touch the top of the panel
+
+ pPlayersX = new int[points.Count()];
+ pPlayersY = new int[points.Count()];
+ }
+
+ for(int i=0;i<points.Count();i++)
+ // draw the graphs, left to right
+ {
+
+ if(cpu)
+ {
+ pCpuX[i] = left+static_cast<int>(i*distPoints);
+ pCpuY[i] = static_cast<int>((1-points[i].cpu)*y);
+ }
+
+ if(net_i)
+ {
+ pInX[i] = left+static_cast<int>(i*distPoints);
+ pInY[i] = static_cast<int>(( (Range-points[i].in)/Range)*y-bottom);
+ }
+
+ if(net_o)
+ {
+ pOutX[i] = left+static_cast<int>(i*distPoints);
+ pOutY[i] = static_cast<int>(((Range-points[i].out)/Range)*y-bottom);
+ }
+
+ if(fps)
+ {
+ pFPSX[i] = left+static_cast<int>(i*distPoints);
+ pFPSY[i] = static_cast<int>(( (RangeFPS-points[i].fps)/RangeFPS)*y-bottom);
+ }
+
+ if(ping)
+ {
+ pPingX[i] = left+static_cast<int>(i*distPoints);
+ pPingY[i] = static_cast<int>(( (RangePing-points[i].ping)/RangePing)*y-bottom);
+ }
+
+ if(players)
+ {
+ pPlayersX[i] = left+static_cast<int>(i*distPoints);
+ pPlayersY[i] = static_cast<int>(( (RangePlayers-points[i].players)/RangePlayers)*y-bottom);
+ }
+
+
+ }
+ // we use DrawPolyLine, its much, much, much more efficient than calling lots of DrawLine()'s
+
+ if(cpu)
+ {
+ SetColor(CPUColor); // green
+ DrawPolyLine(pCpuX, pCpuY, points.Count());
+ delete [] pCpuX;
+ delete [] pCpuY;
+ }
+
+ if(net_i)
+ {
+ SetColor(NetInColor); // red
+ DrawPolyLine(pInX, pInY, points.Count());
+ delete [] pInX;
+ delete [] pInY;
+ }
+ if(net_o)
+ {
+ SetColor(NetOutColor); //yellow
+ DrawPolyLine(pOutX, pOutY, points.Count());
+ delete [] pOutX;
+ delete [] pOutY;
+ }
+ if(fps)
+ {
+ SetColor(FPSColor);
+ DrawPolyLine(pFPSX, pFPSY, points.Count());
+ delete [] pFPSX;
+ delete [] pFPSY;
+ }
+
+ if(ping)
+ {
+ SetColor(PingColor);
+ DrawPolyLine(pPingX, pPingY, points.Count());
+ delete [] pPingX;
+ delete [] pPingY;
+ }
+
+ if(players)
+ {
+ SetColor(PlayersColor);
+ DrawPolyLine(pPlayersX, pPlayersY, points.Count());
+ delete [] pPlayersX;
+ delete [] pPlayersY;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor for the graphs image
+//-----------------------------------------------------------------------------
+CGraphPanel::CGraphsImage::CGraphsImage(): vgui::Image(), points()
+{
+ maxIn=maxOut=minIn=minOut=minFPS=maxFPS=minPing=maxPing=0;
+ net_i=net_o=fps=cpu=ping=players=false;
+ numAvgs=0;
+ memset(&avgPoint,0x0,sizeof(Points_t));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets which graph to draw, true means draw it
+//-----------------------------------------------------------------------------
+void CGraphPanel::CGraphsImage::SetDraw(bool cpu_in,bool fps_in,bool net_in,bool net_out,bool ping_in,bool players_in)
+{
+ cpu=cpu_in;
+ fps=fps_in;
+ net_i=net_in;
+ net_o=net_out;
+ ping=ping_in;
+ players=players_in;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: used to average points over a period of time
+//-----------------------------------------------------------------------------
+void CGraphPanel::CGraphsImage::AvgPoint(Points_t p)
+{
+ avgPoint.cpu += p.cpu;
+ avgPoint.fps += p.fps;
+ avgPoint.in += p.in;
+ avgPoint.out += p.out;
+ avgPoint.ping += p.ping;
+ avgPoint.players += p.players;
+ numAvgs++;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: updates the current bounds of the points based on this new point
+//-----------------------------------------------------------------------------
+void CGraphPanel::CGraphsImage::CheckBounds(Points_t p)
+{
+ if(p.in>maxIn)
+ {
+ maxIn=avgPoint.in;
+ }
+ if(p.out>maxOut)
+ {
+ maxOut=avgPoint.out;
+ }
+
+ if(p.in<minIn)
+ {
+ minIn=avgPoint.in;
+ }
+ if(p.out<minOut)
+ {
+ minOut=avgPoint.out;
+ }
+
+ if(p.fps>maxFPS)
+ {
+ maxFPS=avgPoint.fps;
+ }
+ if(p.fps<minFPS)
+ {
+ minFPS=avgPoint.fps;
+ }
+
+ if(p.ping>maxPing)
+ {
+ maxPing=avgPoint.ping;
+ }
+ if(p.ping<minPing)
+ {
+ minPing=avgPoint.ping;
+ }
+
+ if(p.players>maxPlayers)
+ {
+ maxPlayers=avgPoint.players;
+ }
+ if(p.players<minPlayers)
+ {
+ minPlayers=avgPoint.players;
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds a point to the graph image.
+//-----------------------------------------------------------------------------
+bool CGraphPanel::CGraphsImage::AddPoint(Points_t p)
+{
+ int x,y;
+ bool recalcBounds=false;
+
+ GetSize(x,y);
+
+ if(avgPoint.cpu>1) // cpu is a percent !
+ {
+ return false;
+ }
+
+ if(timeBetween==SECONDS) // most recent minute
+ {
+ while(points.Count() && (p.time-points[0].time)>60)
+ {
+ points.Remove(0);
+ }
+ }
+ else if(timeBetween==HOURS) // most recent hour
+ {
+ while(points.Count() && (p.time-points[0].time)>60*60)
+ {
+ points.Remove(0);
+ }
+ }
+ else if ( timeBetween==MINUTES) // most recent day
+ {
+ while(points.Count() && (p.time-points[0].time)>60*60*24)
+ {
+ points.Remove(0);
+ }
+ }
+
+ AvgPoint(p);
+ // now work out the average of all the values
+ avgPoint.cpu /= numAvgs;
+ avgPoint.fps /= numAvgs;
+ avgPoint.in /= numAvgs;
+ avgPoint.out /= numAvgs;
+ avgPoint.ping /= numAvgs;
+ avgPoint.players /= numAvgs;
+ avgPoint.time = p.time;
+ numAvgs=0;
+
+ int k=0;
+
+ if(x!=0 && points.Count()> x/2)
+ // there are more points than pixels so thin them out
+ {
+ while(points.Count()> x/2)
+ {
+ // check that the bounds don't move
+ if(points[0].in==maxIn ||
+ points[0].out==maxOut ||
+ points[0].fps==maxFPS ||
+ points[0].ping==maxPing ||
+ points[0].players==maxPlayers)
+ {
+ recalcBounds=true;
+ }
+ points.Remove(k); // remove the head node
+ k+=2;
+ if(k>points.Count())
+ {
+ k=0;
+ }
+ }
+ }
+
+ if(recalcBounds)
+ {
+ for(int i=0;i<points.Count();i++)
+ {
+ CheckBounds(points[i]);
+ }
+ }
+
+
+ CheckBounds(avgPoint);
+
+ points.AddToTail(avgPoint);
+
+ memset(&avgPoint,0x0,sizeof(Points_t));
+
+ return true;
+}
+
+void CGraphPanel::CGraphsImage::SetScale(intervals time)
+{
+ timeBetween=time;
+
+ // scale is reset so remove all the points
+ points.RemoveAll();
+
+ // and reset the maxes
+ maxIn=maxOut=minIn=minOut=minFPS=maxFPS=minPing=maxPing=maxPlayers=minPlayers=0;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: clear button handler, clears the current points
+//-----------------------------------------------------------------------------
+void CGraphPanel::OnClearButton()
+{
+ m_pGraphs->RemovePoints();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: passes the state of the check buttons (for graph line display) through to the graph image
+//-----------------------------------------------------------------------------
+void CGraphPanel::OnCheckButton()
+{
+ m_pGraphs->SetDraw(m_pCPUButton->IsSelected(), m_pFPSButton->IsSelected(), m_pInButton->IsSelected(), m_pOutButton->IsSelected(), m_pPINGButton->IsSelected(), m_pPlayerButton->IsSelected());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:Handles the scale radio buttons, passes the scale to use through to the graph image
+//-----------------------------------------------------------------------------
+void CGraphPanel::OnTextChanged(Panel *panel, const char *text)
+{
+ if (panel == m_pTimeCombo)
+ {
+ if (strstr(text, "Hour"))
+ {
+ m_pGraphs->SetScale(MINUTES);
+ }
+ else if (strstr(text, "Day"))
+ {
+ m_pGraphs->SetScale(HOURS);
+ }
+ else
+ {
+ m_pGraphs->SetScale(SECONDS);
+ }
+ }
+ else if (panel == m_pVertCombo)
+ {
+ float maxVal, minVal;
+ char minText[20], midText[20], maxText[20];
+
+ if (strstr(text, "CPU"))
+ {
+ SetAxisLabels(m_pGraphs->GetCPUColor(), "100%", "50%", "0%");
+ }
+ else if (strstr(text, "FPS"))
+ {
+ m_pGraphs->GetFPSLimits(maxVal, minVal);
+ sprintf(maxText,"%0.2f", maxVal);
+ sprintf(midText,"%0.2f", (maxVal - minVal) / 2);
+ sprintf(minText,"%0.2f", minVal);
+ SetAxisLabels(m_pGraphs->GetFPSColor(), maxText, midText, minText);
+ }
+ else if (strstr(text, "In"))
+ {
+ m_pGraphs->GetInLimits(maxVal, minVal);
+ sprintf(maxText,"%0.2f", maxVal);
+ sprintf(midText,"%0.2f", (maxVal - minVal) / 2);
+ sprintf(minText,"%0.2f", minVal);
+
+ SetAxisLabels(m_pGraphs->GetInColor(), maxText, midText, minText);
+ }
+ else if (strstr(text, "Out"))
+ {
+ m_pGraphs->GetOutLimits(maxVal, minVal);
+ sprintf(maxText,"%0.2f", maxVal);
+ sprintf(midText,"%0.2f", (maxVal - minVal) / 2);
+ sprintf(minText,"%0.2f", minVal);
+ SetAxisLabels(m_pGraphs->GetOutColor(), maxText, midText, minText);
+ }
+ else if (strstr(text, "Ping"))
+ {
+ m_pGraphs->GetPingLimits(maxVal, minVal);
+ sprintf(maxText,"%0.2f", maxVal);
+ sprintf(midText,"%0.2f", (maxVal - minVal) / 2);
+ sprintf(minText,"%0.2f", minVal);
+ SetAxisLabels(m_pGraphs->GetPingColor(), maxText, midText, minText);
+ }
+ else if (strstr(text, "Players"))
+ {
+ m_pGraphs->GetPlayerLimits(maxVal, minVal);
+ sprintf(maxText,"%0.2f", maxVal);
+ sprintf(midText,"%0.2f", (maxVal - minVal) / 2);
+ sprintf(minText,"%0.2f", minVal);
+
+ SetAxisLabels(m_pGraphs->GetPlayersColor(), maxText, midText, minText);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGraphPanel::SetAxisLabels(Color c, char *max, char *mid, char *min)
+{
+ Label *lab;
+ lab= GetLabel("AxisMax");
+ if(lab)
+ {
+ lab->SetFgColor(c);
+ lab->SetText(max);
+ }
+ lab = GetLabel("AxisMid");
+ if(lab)
+ {
+ lab->SetFgColor(c);
+ lab->SetText(mid);
+ }
+ lab = GetLabel("AxisMin");
+ if(lab)
+ {
+ lab->SetFgColor(c);
+ lab->SetText(min);
+ }
+}
+
+Label *CGraphPanel::GetLabel(const char *name)
+{
+ Label *lab = dynamic_cast<Label *>(FindChildByName(name));
+ return lab;
+}
diff --git a/tracker/AdminServer/GraphPanel.h b/tracker/AdminServer/GraphPanel.h
new file mode 100644
index 0000000..10153f7
--- /dev/null
+++ b/tracker/AdminServer/GraphPanel.h
@@ -0,0 +1,154 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef GRAPHPANEL_H
+#define GRAPHPANEL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <KeyValues.h>
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/PropertyPage.h>
+#include <vgui_controls/Image.h>
+#include <vgui_controls/ImagePanel.h>
+#include <vgui/IScheme.h>
+
+#include "RemoteServer.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CGraphPanel : public vgui::PropertyPage, public IServerDataResponse
+{
+ DECLARE_CLASS_SIMPLE( CGraphPanel, vgui::PropertyPage );
+public:
+ CGraphPanel(vgui::Panel *parent, const char *name);
+ ~CGraphPanel();
+
+ // property page handlers
+ virtual void OnPageShow();
+ virtual void OnPageHide();
+
+ void PerformLayout();
+
+protected:
+ // callback for receiving server data
+ virtual void OnServerDataResponse(const char *value, const char *response);
+
+ // called every frame to update stats page
+ virtual void OnTick();
+
+private:
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ typedef enum { SECONDS, MINUTES, HOURS } intervals;
+ struct Points_t
+ {
+ float cpu; // the percent CPU usage
+ float in; // the ingoing bandwidth in kB/sec
+ float out; // the outgoing bandwidth in kB/sec
+ float time; // the time this was recorded
+ float fps; // the FPS of the server
+ float ping; // the ping of the server
+ float players; // the number of players currently on the server
+ };
+
+ // internal class for holding the graph picture
+ class CGraphsImage: public vgui::Image
+ {
+ public:
+ CGraphsImage();
+ using Image::DrawLine;
+ using Image::SetPos;
+ bool AddPoint(Points_t p);
+ void RemovePoints() { points.RemoveAll(); }
+ void SaveSize(int x1,int y1) { x=x1;y=y1; SetSize(x1,y1);}
+
+ void SetDraw(bool cpu_in,bool fps_in,bool net_in,bool net_out,bool ping_in,bool players_in);
+ void SetScale(intervals time);
+ void SetBgColor(Color col) { bgColor=col; }
+ void SetAxisColor(Color col) { lineColor=col; }
+
+ // return the pre-defined colors of each graph type
+ Color GetCPUColor() { return CPUColor; }
+ Color GetFPSColor() { return FPSColor; }
+ Color GetInColor() { return NetInColor; }
+ Color GetOutColor() { return NetOutColor; }
+ Color GetPlayersColor() { return PlayersColor; }
+ Color GetPingColor() { return PingColor; }
+
+ // return the limits of various graphs
+ void GetFPSLimits(float &max, float &min) { min=minFPS; max=maxFPS; }
+ void GetInLimits(float &max, float &min) { min=minIn; max=maxIn; }
+ void GetOutLimits(float &max, float &min) { min=minOut; max=maxOut; }
+ void GetPingLimits(float &max, float &min) { min=minPing; max=maxPing; }
+ void GetPlayerLimits(float &max, float &min) { min=minPlayers; max=maxPlayers; }
+
+ virtual void Paint();
+
+ private:
+
+ void AvgPoint(Points_t p);
+ void CheckBounds(Points_t p);
+
+ CUtlVector<Points_t> points;
+
+ int x,y; // the size
+ float maxIn,minIn,maxOut,minOut; // max and min bandwidths
+ float maxFPS,minFPS;
+ float minPing,maxPing;
+ float maxPlayers,minPlayers;
+
+ bool cpu,fps,net_i,ping,net_o,players;
+ intervals timeBetween;
+ Points_t avgPoint;
+ int numAvgs;
+ Color bgColor,lineColor;
+
+ // colors for the various graphs, set in graphpanel.cpp
+ static Color CPUColor;
+ static Color FPSColor;
+ static Color NetInColor;
+ static Color NetOutColor;
+ static Color PlayersColor;
+ static Color PingColor;
+ };
+ friend CGraphsImage; // so it can use the intervals enum
+
+ vgui::Label *GetLabel(const char *name);
+ void SetAxisLabels(Color c,char *max,char *mid,char *min);
+
+ // msg handlers
+ MESSAGE_FUNC( OnCheckButton, "CheckButtonChecked" );
+ MESSAGE_FUNC_PTR_CHARPTR( OnTextChanged, "TextChanged", panel, text );
+ MESSAGE_FUNC( OnClearButton, "clear" );
+
+ // GUI elements
+ CGraphsImage *m_pGraphs;
+ vgui::ImagePanel *m_pGraphsPanel;
+
+ vgui::Button *m_pClearButton;
+
+ vgui::CheckButton *m_pInButton;
+ vgui::CheckButton *m_pOutButton;
+ vgui::CheckButton *m_pFPSButton;
+ vgui::CheckButton *m_pCPUButton;
+ vgui::CheckButton *m_pPINGButton;
+ vgui::CheckButton *m_pPlayerButton;
+
+ vgui::ComboBox *m_pTimeCombo;
+ vgui::ComboBox *m_pVertCombo;
+
+ float m_flNextStatsUpdateTime;
+};
+
+#endif // GRAPHPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/HelpText.cpp b/tracker/AdminServer/HelpText.cpp
new file mode 100644
index 0000000..04c2c8a
--- /dev/null
+++ b/tracker/AdminServer/HelpText.cpp
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+
+#include <stdio.h>
+
+#include <VGUI_Controls.h>
+#include "filesystem.h"
+#include "HelpText.h"
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CHelpText::CHelpText(const char *mod)
+{
+
+ char configName[200];
+ _snprintf(configName,200,"Admin\\HelpFile_%s.vdf",mod);
+
+ m_pHelpData = new KeyValues ("Help");
+
+ // always load the basic definiton
+ LoadHelpFile("Admin\\HelpFile.vdf");
+
+ // now load mod specific stuff
+ if( g_pFullFileSystem->FileExists(configName) )
+ {
+ LoadHelpFile(configName);
+ }
+
+ // and load an admin mod page if you can find it
+ if( g_pFullFileSystem->FileExists("Admin\\HelpFile_adminmod.vdf") )
+ {
+ LoadHelpFile("Admin\\HelpFile_adminmod.vdf");
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CHelpText::~CHelpText()
+{
+ m_pHelpData->deleteThis();
+}
+
+
+void CHelpText::LoadHelpFile(const char *filename)
+{
+
+
+ if (!m_pHelpData->LoadFromFile(g_pFullFileSystem, filename, true, "PLATFORM"))
+ {
+ // failed to load...
+ }
+ else
+ {
+
+ }
+
+}
+
+const char *CHelpText::GetHelp(const char *keyname)
+{
+ KeyValues *help = m_pHelpData->FindKey(keyname, true);
+ if(help)
+ {
+ return help->GetString("text");
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+
+
+
diff --git a/tracker/AdminServer/HelpText.h b/tracker/AdminServer/HelpText.h
new file mode 100644
index 0000000..e30e6b3
--- /dev/null
+++ b/tracker/AdminServer/HelpText.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef HELPTEXT_H
+#define HELPTEXT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_KeyValues.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose: parses in a text file and returns help strings about key words
+//-----------------------------------------------------------------------------
+class CHelpText
+{
+public:
+ CHelpText(const char *mod);
+ ~CHelpText();
+
+ void LoadHelpFile(const char *filename);
+ const char *GetHelp(const char *keyname);
+
+private:
+
+ vgui::KeyValues *m_pHelpData;
+
+};
+
+#endif // HELPTEXT_H
diff --git a/tracker/AdminServer/IManageServer.h b/tracker/AdminServer/IManageServer.h
new file mode 100644
index 0000000..b57194d
--- /dev/null
+++ b/tracker/AdminServer/IManageServer.h
@@ -0,0 +1,35 @@
+
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef IMANAGESERVER_H
+#define IMANAGESERVER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <interface.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: basic callback interface for the manage server list, to update status text et al
+//-----------------------------------------------------------------------------
+class IManageServer : public IBaseInterface
+{
+public:
+ // activates the manage page
+ virtual void ShowPage() = 0;
+
+ // sets whether or not the server is remote
+ virtual void SetAsRemoteServer(bool remote) = 0;
+
+ // prints text to the console
+ virtual void AddToConsole(const char *msg) = 0;
+};
+
+#define IMANAGESERVER_INTERFACE_VERSION "IManageServer002"
+
+#endif // IMANAGESERVER_H
diff --git a/tracker/AdminServer/Iresponse.h b/tracker/AdminServer/Iresponse.h
new file mode 100644
index 0000000..88e600f
--- /dev/null
+++ b/tracker/AdminServer/Iresponse.h
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef IRESPONSE_H
+#define IRESPONSE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Callback interface for server updates
+//-----------------------------------------------------------------------------
+class IResponse
+{
+public:
+ // called when the server has successfully responded
+ virtual void ServerResponded() = 0;
+
+ // called when a server response has timed out
+ virtual void ServerFailedToRespond() = 0;
+
+};
+
+
+#endif // IRESPONSE_H
diff --git a/tracker/AdminServer/MOTDPanel.cpp b/tracker/AdminServer/MOTDPanel.cpp
new file mode 100644
index 0000000..1a65209
--- /dev/null
+++ b/tracker/AdminServer/MOTDPanel.cpp
@@ -0,0 +1,171 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+
+#include "MOTDPanel.h"
+
+
+#include <VGUI_Controls.h>
+#include <VGUI_ISystem.h>
+#include <VGUI_ISurface.h>
+#include <VGUI_IVGui.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_Label.h>
+#include <VGUI_TextEntry.h>
+#include <VGUI_Button.h>
+#include <VGUI_ToggleButton.h>
+#include <VGUI_RadioButton.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_ComboBox.h>
+#include <VGUI_PHandle.h>
+#include <VGUI_PropertySheet.h>
+
+using namespace vgui;
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMOTDPanel::CMOTDPanel(vgui::Panel *parent, const char *name) : PropertyPage(parent, name)
+{
+ m_pRcon=NULL;
+
+ m_pMOTDPanel = new TextEntry(this, "ServerMOTDText");
+
+ m_pMOTDPanel->SetMultiline(true);
+ m_pMOTDPanel->SetEnabled(true);
+ m_pMOTDPanel->SetEditable(true);
+ m_pMOTDPanel->SetVerticalScrollbar(true);
+ m_pMOTDPanel->SetRichEdit(false);
+ m_pMOTDPanel->SetCatchEnterKey(true);
+ m_pMOTDPanel->setMaximumCharCount(1024);
+
+ m_pSendMOTDButton = new Button(this, "SendMOTD", "&Send");
+ m_pSendMOTDButton->SetCommand(new KeyValues("SendMOTD"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CMOTDPanel::~CMOTDPanel()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the page
+//-----------------------------------------------------------------------------
+void CMOTDPanel::OnPageShow()
+{
+ m_pMOTDPanel->RequestFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides the page
+//-----------------------------------------------------------------------------
+void CMOTDPanel::OnPageHide()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Relayouts the data
+//-----------------------------------------------------------------------------
+void CMOTDPanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // setup the layout of the panels
+ m_pMOTDPanel->SetBounds(5,5,GetWide()-10,GetTall()-35);
+
+ m_pSendMOTDButton->SetBounds(GetWide()-70,GetTall()-25,60,20);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: inserts a new string into the main chat panel
+//-----------------------------------------------------------------------------
+void CMOTDPanel::DoInsertString(const char *str)
+{
+ m_pMOTDPanel->SetText("");
+ if(strlen(str)>1024)
+ {
+ char *fix = const_cast<char *>(str);
+ fix[1024]='\0';
+ }
+ m_pMOTDPanel->DoInsertString(str);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: passes the rcon class to use
+//-----------------------------------------------------------------------------
+void CMOTDPanel::SetRcon(CRcon *rcon)
+{
+ m_pRcon=rcon;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: run when the send button is pressed, send a rcon "say" to the server
+//-----------------------------------------------------------------------------
+void CMOTDPanel::OnSendMOTD()
+{
+ if(m_pRcon)
+ {
+ char chat_text[2048];
+
+ _snprintf(chat_text,512,"motd_write ");
+ m_pMOTDPanel->GetText(0,chat_text+11,2048-11);
+ if(strlen("motd_write ")!=strlen(chat_text)) // check there is something in the text panel
+ {
+ unsigned int i=0;
+ while(i<strlen(chat_text) && i<2048)
+ {
+ if(chat_text[i]=='\n')
+ {
+ // shift everything up one
+ for(unsigned int k=strlen(chat_text)+1;k>i;k--)
+ {
+ chat_text[k+1]=chat_text[k];
+ }
+
+ // replace the newline with the string "\n"
+ chat_text[i]='\\';
+ chat_text[i+1]='n';
+
+ i++; // skip this insert
+ }
+ i++;
+ }
+
+ m_pRcon->SendRcon(chat_text);
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the game dir combo box is changed
+//-----------------------------------------------------------------------------
+void CMOTDPanel::OnTextChanged(Panel *panel, const char *text)
+{
+// BUG - TextEntry NEVER lets the enter key through... This doesn't work
+
+ if( text[strlen(text)-1]=='\n') // the enter key was just pressed :)
+ {
+ OnSendMOTD();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message map
+//-----------------------------------------------------------------------------
+MessageMapItem_t CMOTDPanel::m_MessageMap[] =
+{
+ MAP_MESSAGE( CMOTDPanel, "SendMOTD", OnSendMOTD ),
+ MAP_MESSAGE( CMOTDPanel, "PageShow", OnPageShow ),
+// MAP_MESSAGE_PTR_CONSTCHARPTR( CMOTDPanel, "TextChanged", OnTextChanged, "panel", "text" ),
+};
+
+IMPLEMENT_PANELMAP( CMOTDPanel, Frame ); \ No newline at end of file
diff --git a/tracker/AdminServer/MOTDPanel.h b/tracker/AdminServer/MOTDPanel.h
new file mode 100644
index 0000000..5e94767
--- /dev/null
+++ b/tracker/AdminServer/MOTDPanel.h
@@ -0,0 +1,71 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef MOTDPANEL_H
+#define MOTDPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Frame.h>
+#include <VGUI_PHandle.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_PropertyPage.h>
+
+#include "rcon.h"
+
+class KeyValues;
+
+namespace vgui
+{
+class Button;
+class ToggleButton;
+class RadioButton;
+class Label;
+class TextEntry;
+class ListPanel;
+class MessageBox;
+class ComboBox;
+class Panel;
+class PropertySheet;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CMOTDPanel:public vgui::PropertyPage
+{
+public:
+ CMOTDPanel(vgui::Panel *parent, const char *name);
+ ~CMOTDPanel();
+
+ // property page handlers
+ virtual void OnPageShow();
+ virtual void OnPageHide();
+ void DoInsertString(const char *str);
+
+ void SetRcon(CRcon *rcon);
+
+ virtual void PerformLayout();
+
+private:
+
+ void OnSendMOTD();
+ void OnTextChanged(vgui::Panel *panel, const char *text);
+
+ vgui::TextEntry *m_pMOTDPanel;
+ vgui::Button *m_pSendMOTDButton;
+
+ CRcon *m_pRcon;
+
+ DECLARE_PANELMAP();
+ typedef vgui::PropertyPage BaseClass;
+};
+
+#endif // MOTDPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/MapCycleEditDialog.cpp b/tracker/AdminServer/MapCycleEditDialog.cpp
new file mode 100644
index 0000000..39e3ecf
--- /dev/null
+++ b/tracker/AdminServer/MapCycleEditDialog.cpp
@@ -0,0 +1,263 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "MapCycleEditDialog.h"
+
+#include <vgui/KeyCode.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ListPanel.h>
+
+#include "RemoteServer.h"
+#include "tier1/utlbuffer.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMapCycleEditDialog::CMapCycleEditDialog(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
+{
+ SetSize(480, 320);
+ SetSizeable(false);
+
+ m_pAvailableMapList = new ListPanel(this, "AvailableMapList");
+ m_pAvailableMapList->AddColumnHeader(0, "Map", "#Available_Maps", 128);
+ m_pAvailableMapList->SetColumnSortable(0, false);
+
+ m_pMapCycleList = new ListPanel(this, "MapCycleList");
+ m_pMapCycleList->AddColumnHeader(0, "Map", "#Map_Cycle", 128);
+ m_pMapCycleList->SetColumnSortable(0, false);
+
+ m_RightArrow = new Button(this, "RightButton", "");
+ m_LeftArrow = new Button(this, "LeftButton", "");
+ m_UpArrow = new Button(this, "UpButton", "");
+ m_DownArrow = new Button(this, "DownButton", "");
+
+ LoadControlSettings("Admin/MapCycleEditDialog.res", "PLATFORM");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CMapCycleEditDialog::~CMapCycleEditDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows the dialog, building the lists from the params
+//-----------------------------------------------------------------------------
+void CMapCycleEditDialog::Activate(vgui::Panel *updateTarget, CUtlVector<CUtlSymbol> &availableMaps, CUtlVector<CUtlSymbol> &mapCycle)
+{
+ // set the action signal target
+ AddActionSignalTarget(updateTarget);
+
+ // clear lists
+ m_pAvailableMapList->DeleteAllItems();
+ m_pMapCycleList->DeleteAllItems();
+
+ // build lists
+ for (int i = 0; i < availableMaps.Count(); i++)
+ {
+ // only add to the available maps list if it's not in mapCycle
+ bool inMapCycle = false;
+ for (int j = 0; j < mapCycle.Count(); j++)
+ {
+ if (!stricmp(mapCycle[j].String(), availableMaps[i].String()))
+ {
+ inMapCycle = true;
+ break;
+ }
+ }
+
+ if (!inMapCycle)
+ {
+ m_pAvailableMapList->AddItem(new KeyValues("MapItem", "Map", availableMaps[i].String()), 0, false, false);
+ }
+ }
+ for (int i = 0; i < mapCycle.Count(); i++)
+ {
+ m_pMapCycleList->AddItem(new KeyValues("MapItem", "Map", mapCycle[i].String()), 0, false, false);
+ }
+
+ // show window
+ SetTitle("Change Map Cycle", false);
+ MoveToCenterOfScreen();
+ BaseClass::Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up button state
+//-----------------------------------------------------------------------------
+void CMapCycleEditDialog::PerformLayout()
+{
+ m_LeftArrow->SetEnabled(false);
+ m_RightArrow->SetEnabled(false);
+ m_UpArrow->SetEnabled(false);
+ m_DownArrow->SetEnabled(false);
+
+ if (m_pMapCycleList->GetSelectedItemsCount() > 0)
+ {
+ m_LeftArrow->SetEnabled(true);
+ m_LeftArrow->SetAsDefaultButton(true);
+
+ if (m_pMapCycleList->GetSelectedItemsCount() == 1)
+ {
+ int row = m_pMapCycleList->GetSelectedItem(0);
+ if (row > 0)
+ {
+ m_UpArrow->SetEnabled(true);
+ }
+ if (row + 1 < m_pMapCycleList->GetItemCount())
+ {
+ m_DownArrow->SetEnabled(true);
+ }
+ }
+ }
+ else if (m_pAvailableMapList->GetSelectedItemsCount() > 0)
+ {
+ m_RightArrow->SetEnabled(true);
+ m_RightArrow->SetAsDefaultButton(true);
+ }
+
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates UI based on which listpanel got selection
+//-----------------------------------------------------------------------------
+void CMapCycleEditDialog::OnItemSelected(vgui::Panel *panel)
+{
+ if (panel == m_pAvailableMapList && m_pAvailableMapList->GetSelectedItemsCount() > 0)
+ {
+ m_pMapCycleList->ClearSelectedItems();
+ }
+ else if (panel == m_pMapCycleList && m_pMapCycleList->GetSelectedItemsCount() > 0)
+ {
+ m_pAvailableMapList->ClearSelectedItems();
+ }
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Button command handler
+//-----------------------------------------------------------------------------
+void CMapCycleEditDialog::OnCommand(const char *command)
+{
+ if (!stricmp(command, "ArrowLeft"))
+ {
+ // move map from mapcycle to available list
+ while (m_pMapCycleList->GetSelectedItemsCount() > 0)
+ {
+ int itemID = m_pMapCycleList->GetSelectedItem(0);
+ KeyValues *data = m_pMapCycleList->GetItem(itemID);
+ if (!data)
+ return;
+
+ const char *map = data->GetString("Map");
+ m_pAvailableMapList->AddItem(new KeyValues("MapItem", "Map", map), 0, true, false);
+ m_pMapCycleList->RemoveItem(itemID);
+ }
+ }
+ else if (!stricmp(command, "ArrowRight"))
+ {
+ // move map from available list to mapcycle
+ while (m_pAvailableMapList->GetSelectedItemsCount() > 0)
+ {
+ int itemID = m_pAvailableMapList->GetSelectedItem(0);
+ KeyValues *data = m_pAvailableMapList->GetItem(itemID);
+ if (!data)
+ return;
+
+ const char *map = data->GetString("Map");
+ m_pMapCycleList->AddItem(new KeyValues("MapItem", "Map", map), 0, true, false);
+ m_pAvailableMapList->RemoveItem(itemID);
+ }
+ }
+ else if (!stricmp(command, "ArrowUp"))
+ {
+ int itemID = m_pMapCycleList->GetSelectedItem(0);
+ int row = m_pMapCycleList->GetItemCurrentRow(itemID);
+ int prevRow = row - 1;
+ if (prevRow < 0)
+ return;
+
+ int prevItemID = m_pMapCycleList->GetItemIDFromRow(prevRow);
+
+ // get the data
+ KeyValues *d1 = m_pMapCycleList->GetItem(itemID);
+ KeyValues *d2 = m_pMapCycleList->GetItem(prevItemID);
+
+ // swap the strings
+ CUtlSymbol tempString = d1->GetString("Map");
+ d1->SetString("Map", d2->GetString("Map"));
+ d2->SetString("Map", tempString.String());
+
+ // update the list
+ m_pMapCycleList->ApplyItemChanges(itemID);
+ m_pMapCycleList->ApplyItemChanges(prevItemID);
+ PostMessage(m_pMapCycleList, new KeyValues("KeyCodePressed", "code", KEY_UP));
+ }
+ else if (!stricmp(command, "ArrowDown"))
+ {
+ int itemID = m_pMapCycleList->GetSelectedItem(0);
+ int row = m_pMapCycleList->GetItemCurrentRow(itemID);
+ int nextRow = row + 1;
+ if (nextRow + 1 > m_pMapCycleList->GetItemCount())
+ return;
+
+ int nextItemID = m_pMapCycleList->GetItemIDFromRow(nextRow);
+
+ // get the data
+ KeyValues *d1 = m_pMapCycleList->GetItem(itemID);
+ KeyValues *d2 = m_pMapCycleList->GetItem(nextItemID);
+
+ // swap the strings
+ CUtlSymbol tempString = d1->GetString("Map");
+ d1->SetString("Map", d2->GetString("Map"));
+ d2->SetString("Map", tempString.String());
+
+ // update the list
+ m_pMapCycleList->ApplyItemChanges(itemID);
+ m_pMapCycleList->ApplyItemChanges(nextItemID);
+ PostMessage(m_pMapCycleList, new KeyValues("KeyCodePressed", "code", KEY_DOWN));
+ }
+ else if (!stricmp(command, "Cancel"))
+ {
+ Close();
+ }
+ else if (!stricmp(command, "OK"))
+ {
+ // write out the data
+ CUtlBuffer msg(0, 1024, CUtlBuffer::TEXT_BUFFER);
+
+ for (int i = 0; i < m_pMapCycleList->GetItemCount(); i++)
+ {
+ int itemID = m_pMapCycleList->GetItemIDFromRow(i);
+ KeyValues *kv = m_pMapCycleList->GetItem(itemID);
+ if ( kv )
+ {
+ msg.PutString(kv->GetString("Map"));
+ msg.PutChar('\n');
+ }
+ }
+
+ msg.PutChar(0);
+ RemoteServer().SetValue("mapcycle", (const char *)msg.Base());
+
+ // post message to tell varlist update
+ PostActionSignal(new KeyValues("VarChanged", "var", "mapcycle"));
+
+ // close
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
diff --git a/tracker/AdminServer/MapCycleEditDialog.h b/tracker/AdminServer/MapCycleEditDialog.h
new file mode 100644
index 0000000..8d97799
--- /dev/null
+++ b/tracker/AdminServer/MapCycleEditDialog.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef MAPCYCLEEDITDIALOG_H
+#define MAPCYCLEEDITDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+#include "utlvector.h"
+#include "utlsymbol.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for editing the game server map cycle list
+//-----------------------------------------------------------------------------
+class CMapCycleEditDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CMapCycleEditDialog, vgui::Frame );
+public:
+ CMapCycleEditDialog(vgui::Panel *parent, const char *name);
+ ~CMapCycleEditDialog();
+ virtual void Activate(vgui::Panel *updateTarget, CUtlVector<CUtlSymbol> &availableMaps, CUtlVector<CUtlSymbol> &mapCycle);
+
+protected:
+ virtual void OnCommand(const char *command);
+ virtual void PerformLayout();
+
+private:
+ MESSAGE_FUNC_PTR( OnItemSelected, "ItemSelected", panel );
+
+ vgui::ListPanel *m_pAvailableMapList;
+ vgui::ListPanel *m_pMapCycleList;
+ vgui::Button *m_RightArrow;
+ vgui::Button *m_LeftArrow;
+ vgui::Button *m_UpArrow;
+ vgui::Button *m_DownArrow;
+};
+
+
+#endif // MAPCYCLEEDITDIALOG_H
diff --git a/tracker/AdminServer/MasterMsgHandler.cpp b/tracker/AdminServer/MasterMsgHandler.cpp
new file mode 100644
index 0000000..cf42029
--- /dev/null
+++ b/tracker/AdminServer/MasterMsgHandler.cpp
@@ -0,0 +1,76 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "MasterMsgHandler.h"
+
+#include "IGameList.h"
+#include "serverpage.h"
+
+#include <VGUI_Controls.h>
+#include <VGUI_IVGui.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMasterMsgHandler::CMasterMsgHandler( IGameList *baseobject, HANDLERTYPE type, void *typeinfo /*= NULL*/ )
+ : CMsgHandler( type, typeinfo )
+{
+ m_pGameList = baseobject;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Process cracked message
+//-----------------------------------------------------------------------------
+bool CMasterMsgHandler::Process( netadr_t *from, CMsgBuffer *msg )
+{
+ // Skip the control character
+ msg->ReadByte();
+ // Skip the return character
+ msg->ReadByte();
+
+ // Get the batch ID
+ int unique = msg->ReadLong();
+
+ // Remainder of message length is 6 byte IP addresses
+ int nNumAddresses = msg->GetCurSize() - msg->GetReadCount();
+ assert( !( nNumAddresses % 6 ) );
+ // Each address is 6 bytes long
+ nNumAddresses /= 6;
+
+ while (nNumAddresses-- > 0)
+ {
+ serveritem_t server;
+ memset(&server, 0, sizeof(server));
+ for (int i = 0; i < 4; i++)
+ {
+ server.ip[i] = msg->ReadByte();
+ }
+ server.port = msg->ReadShort();
+ server.port = (server.port & 0xff) << 8 | (server.port & 0xff00) >> 8; // roll your own ntohs
+ server.received = 0;
+ server.listEntry = NULL;
+ server.doNotRefresh = false;
+ server.hadSuccessfulResponse = false;
+ server.map[0] = 0;
+ server.gameDir[0] = 0;
+
+ m_pGameList->AddNewServer(server);
+ }
+
+ if (!unique)
+ {
+ m_pGameList->ListReceived(false, 0);
+ }
+ else
+ {
+ // wait until we've refreshed the list before getting next batch of servers
+ m_pGameList->ListReceived(true, unique);
+ }
+
+ return true;
+}
+
diff --git a/tracker/AdminServer/Player.h b/tracker/AdminServer/Player.h
new file mode 100644
index 0000000..85652fa
--- /dev/null
+++ b/tracker/AdminServer/Player.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef PLAYER_H
+#define PLAYER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_ListPanel.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Data describing a single player
+//-----------------------------------------------------------------------------
+typedef struct
+{
+
+ char name[100];
+ int ping;
+ int userid;
+ char authid[20];
+ int loss;
+ int frags;
+ float time;
+ char addr[4];
+} Players_t;
+
+
+#endif // PLAYER_H
diff --git a/tracker/AdminServer/PlayerContextMenu.cpp b/tracker/AdminServer/PlayerContextMenu.cpp
new file mode 100644
index 0000000..e91fbd0
--- /dev/null
+++ b/tracker/AdminServer/PlayerContextMenu.cpp
@@ -0,0 +1,51 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "PlayerContextMenu.h"
+
+#include <vgui/IInput.h>
+#include <vgui/IPanel.h>
+#include <vgui/ISurface.h>
+#include <KeyValues.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CPlayerContextMenu::CPlayerContextMenu(Panel *parent) : Menu(parent, "ServerContextMenu")
+{
+ CPlayerContextMenu::parent=parent;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CPlayerContextMenu::~CPlayerContextMenu()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the menu
+//-----------------------------------------------------------------------------
+void CPlayerContextMenu::ShowMenu(Panel *target, unsigned int playerID)
+{
+ DeleteAllItems();
+
+ AddMenuItem("Kick", "#Player_Menu_Kick", new KeyValues("Kick", "playerID", playerID), CPlayerContextMenu::parent);
+ AddMenuItem("Ban", "#Player_Menu_Ban", new KeyValues("Ban", "playerID", playerID), CPlayerContextMenu::parent);
+ //addMenuItem("Status", "&Player Status", new KeyValues("Status", "playerID", playerID), CPlayerContextMenu::parent);
+
+ MakePopup();
+ int x, y, gx, gy;
+ input()->GetCursorPos(x, y);
+ ipanel()->GetPos(surface()->GetEmbeddedPanel(), gx, gy);
+ SetPos(x - gx, y - gy);
+ MoveToFront();
+ RequestFocus();
+ SetVisible(true);
+}
diff --git a/tracker/AdminServer/PlayerContextMenu.h b/tracker/AdminServer/PlayerContextMenu.h
new file mode 100644
index 0000000..94c6a7b
--- /dev/null
+++ b/tracker/AdminServer/PlayerContextMenu.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef PLAYERCONTEXTMENU_H
+#define PLAYERCONTEXTMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Menu.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic right-click context menu for servers
+//-----------------------------------------------------------------------------
+class CPlayerContextMenu : public vgui::Menu
+{
+public:
+ CPlayerContextMenu(vgui::Panel *parent);
+ ~CPlayerContextMenu();
+
+ // call this to activate the menu
+ void ShowMenu(vgui::Panel *target, unsigned int serverID);
+private:
+ vgui::Panel *parent; // so we can send it messages
+};
+
+
+#endif // PLAYERCONTEXTMENU_H
diff --git a/tracker/AdminServer/PlayerListCompare.cpp b/tracker/AdminServer/PlayerListCompare.cpp
new file mode 100644
index 0000000..27d1d1d
--- /dev/null
+++ b/tracker/AdminServer/PlayerListCompare.cpp
@@ -0,0 +1,191 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+
+#include <KeyValues.h>
+#include <vgui_controls/ListPanel.h>
+
+
+int __cdecl PlayerNameCompare(const KeyValues *elem1, const KeyValues *elem2 )
+{
+
+ if ( !elem1 || !elem2 ) // No meaningful comparison
+ {
+ return 0;
+ }
+
+/* const char *name1 = elem1->GetString("name");
+ const char *name2 = elem2->GetString("name");
+
+ return stricmp(name1,name2);
+ */
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Ping comparison function
+//-----------------------------------------------------------------------------
+int __cdecl PlayerPingCompare(const KeyValues *elem1, const KeyValues *elem2 )
+{
+ vgui::ListPanelItem *p1, *p2;
+ p1 = *(vgui::ListPanelItem **)elem1;
+ p2 = *(vgui::ListPanelItem **)elem2;
+
+ if ( !p1 || !p2 ) // No meaningful comparison
+ {
+ return 0;
+ }
+
+ int ping1 = p1->kv->GetInt("ping");
+ int ping2 = p2->kv->GetInt("ping");
+
+ if ( ping1 < ping2 )
+ return -1;
+ else if ( ping1 > ping2 )
+ return 1;
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Ping comparison function
+//-----------------------------------------------------------------------------
+int __cdecl PlayerAuthCompare(const void *elem1, const void *elem2 )
+{
+ vgui::ListPanelItem *p1, *p2;
+ p1 = *(vgui::ListPanelItem **)elem1;
+ p2 = *(vgui::ListPanelItem **)elem2;
+
+ if ( !p1 || !p2 ) // No meaningful comparison
+ {
+ return 0;
+ }
+
+ const char *authid1 = p1->kv->GetString("authid");
+ const char *authid2 = p2->kv->GetString("authid");
+
+ return stricmp(authid1,authid2);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Loss comparison function
+//-----------------------------------------------------------------------------
+int __cdecl PlayerLossCompare(const void *elem1, const void *elem2 )
+{
+ vgui::ListPanelItem *p1, *p2;
+ p1 = *(vgui::ListPanelItem **)elem1;
+ p2 = *(vgui::ListPanelItem **)elem2;
+
+ if ( !p1 || !p2 ) // No meaningful comparison
+ {
+ return 0;
+ }
+
+ int loss1 = p1->kv->GetInt("loss");
+ int loss2 = p2->kv->GetInt("loss");
+
+
+ if ( loss1 < loss2 )
+ return -1;
+ else if ( loss1 > loss2 )
+ return 1;
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Frags comparison function
+//-----------------------------------------------------------------------------
+int __cdecl PlayerFragsCompare(const void *elem1, const void *elem2 )
+{
+ vgui::ListPanelItem *p1, *p2;
+ p1 = *(vgui::ListPanelItem **)elem1;
+ p2 = *(vgui::ListPanelItem **)elem2;
+
+ if ( !p1 || !p2 ) // No meaningful comparison
+ {
+ return 0;
+ }
+
+ int frags1 = p1->kv->GetInt("frags");
+ int frags2 = p2->kv->GetInt("frags");
+
+
+ if ( frags1 < frags2 )
+ return -1;
+ else if ( frags1 > frags2 )
+ return 1;
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Player connection time comparison function
+//-----------------------------------------------------------------------------
+int __cdecl PlayerTimeCompare( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ int h1 = 0, h2 = 0, m1 = 0, m2 = 0, s1 = 0, s2 = 0;
+ float t1=0,t2=0;
+
+ const char *time1 = item1.kv->GetString("time");
+ const char *time2 = item2.kv->GetString("time");
+
+ int numFields1 = sscanf(time1,"%i:%i:%i",&h1,&m1,&s1);
+ int numFields2 = sscanf(time2,"%i:%i:%i",&h2,&m2,&s2);
+
+ switch ( numFields1 )
+ {
+ case 2:
+ s1 = m1;
+ m1 = h1;
+ h1 = 0;
+ break;
+ case 1:
+ s1 = h1;
+ m1 = 0;
+ h1 = 0;
+ break;
+ case 0:
+ s1 = 0;
+ m1 = 0;
+ h1 = 0;
+ }
+
+ switch ( numFields2 )
+ {
+ case 2:
+ s2 = m2;
+ m2 = h2;
+ h2 = 0;
+ break;
+ case 1:
+ s2 = h2;
+ m2 = 0;
+ h2 = 0;
+ break;
+ case 0:
+ s2 = 0;
+ m2 = 0;
+ h2 = 0;
+ }
+
+ t1=(float)(h1*3600+m1*60+s1);
+ t2=(float)(h2*3600+m2*60+s2);
+
+ if ( t1 < t2 )
+ return -1;
+ else if ( t1 > t2 )
+ return 1;
+
+ return 0;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/PlayerListCompare.h b/tracker/AdminServer/PlayerListCompare.h
new file mode 100644
index 0000000..7690483
--- /dev/null
+++ b/tracker/AdminServer/PlayerListCompare.h
@@ -0,0 +1,25 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef PLAYERLISTCOMPARE_H
+#define PLAYERLISTCOMPARE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/ListPanel.h>
+
+// these functions are common to most server lists in sorts
+int __cdecl PlayerNameCompare(const void *elem1, const void *elem2 );
+int __cdecl PlayerAuthCompare(const void *elem1, const void *elem2 );
+int __cdecl PlayerPingCompare(const void *elem1, const void *elem2 );
+int __cdecl PlayerLossCompare(const void *elem1, const void *elem2 );
+int __cdecl PlayerTimeCompare( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 );
+int __cdecl PlayerFragsCompare(const void *elem1, const void *elem2 );
+
+
+#endif // PLAYERLISTCOMPARE_H
diff --git a/tracker/AdminServer/PlayerPanel.cpp b/tracker/AdminServer/PlayerPanel.cpp
new file mode 100644
index 0000000..9a7eba0
--- /dev/null
+++ b/tracker/AdminServer/PlayerPanel.cpp
@@ -0,0 +1,401 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+
+#include "PlayerPanel.h"
+#include "PlayerContextMenu.h"
+#include "PlayerListCompare.h"
+#include "DialogAddBan.h"
+
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+#include <vgui/IVGui.h>
+#include <vgui/KeyCode.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/QueryBox.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CPlayerPanel::CPlayerPanel(vgui::Panel *parent, const char *name) : vgui::PropertyPage(parent, name)
+{
+ m_pPlayerListPanel = new vgui::ListPanel(this, "Players list");
+
+ m_pPlayerListPanel->AddColumnHeader(0, "name", "#Player_Panel_Name", 200, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pPlayerListPanel->AddColumnHeader(1, "authid", "#Player_Panel_ID", 100);
+ m_pPlayerListPanel->AddColumnHeader(2, "ping", "#Player_Panel_Ping", 50);
+ m_pPlayerListPanel->AddColumnHeader(3, "loss", "#Player_Panel_Loss", 50);
+ m_pPlayerListPanel->AddColumnHeader(4, "frags", "#Player_Panel_Frags", 50);
+ m_pPlayerListPanel->AddColumnHeader(5, "time", "#Player_Panel_Time", 75);
+
+/*
+ // TODO: update me!!
+ m_pPlayerListPanel->SetSortFunc(0, PlayerNameCompare);
+ m_pPlayerListPanel->SetSortFunc(1, PlayerAuthCompare);
+ m_pPlayerListPanel->SetSortFunc(2, PlayerPingCompare);
+ m_pPlayerListPanel->SetSortFunc(3, PlayerLossCompare);
+ m_pPlayerListPanel->SetSortFunc(4, PlayerFragsCompare);
+*/
+ m_pPlayerListPanel->SetSortFunc(5, PlayerTimeCompare);
+ m_pPlayerListPanel->SetEmptyListText("#Player_Panel_No_Players");
+ // Sort by ping time by default
+ m_pPlayerListPanel->SetSortColumn(0);
+
+ m_pKickButton = new Button(this, "Kick", "#Player_Panel_Kick");
+ m_pBanButton = new Button(this, "Ban", "#Player_Panel_Ban");
+
+ m_pPlayerContextMenu = new CPlayerContextMenu(this);
+ m_pPlayerContextMenu->SetVisible(false);
+
+ LoadControlSettings("Admin/PlayerPanel.res", "PLATFORM");
+
+ m_pKickButton->SetCommand(new KeyValues("KickPlayer"));
+ m_pBanButton->SetCommand(new KeyValues("BanPlayer"));
+
+ OnItemSelected(); // disable the buttons
+
+ m_flUpdateTime = 0.0f;
+ RemoteServer().AddServerMessageHandler(this, "UpdatePlayers");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CPlayerPanel::~CPlayerPanel()
+{
+ RemoteServer().RemoveServerDataResponseTarget(this);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Rebuilds player info
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnResetData()
+{
+ RemoteServer().RequestValue(this, "playerlist");
+
+ // update once every minute
+ m_flUpdateTime = (float)system()->GetFrameTime() + (60 * 1.0f);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if we should update player info
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnThink()
+{
+ if (m_flUpdateTime < vgui::system()->GetFrameTime())
+ {
+ OnResetData();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Refreshes page if user hits F5
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnKeyCodeTyped(vgui::KeyCode code)
+{
+ if (code == KEY_F5)
+ {
+ OnResetData();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns data on the player who is currently selected in the list
+//-----------------------------------------------------------------------------
+KeyValues *CPlayerPanel::GetSelected()
+{
+ return m_pPlayerListPanel->GetItem(m_pPlayerListPanel->GetSelectedItem(0));
+}
+
+static const char *FormatSeconds( int seconds )
+{
+ static char string[64];
+
+ int hours = 0;
+ int minutes = seconds / 60;
+
+ if ( minutes > 0 )
+ {
+ seconds -= (minutes * 60);
+ hours = minutes / 60;
+
+ if ( hours > 0 )
+ {
+ minutes -= (hours * 60);
+ }
+ }
+
+ if ( hours > 0 )
+ {
+ Q_snprintf( string, sizeof(string), "%2i:%02i:%02i", hours, minutes, seconds );
+ }
+ else
+ {
+ Q_snprintf( string, sizeof(string), "%02i:%02i", minutes, seconds );
+ }
+
+ return string;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the server has returned a requested value
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnServerDataResponse(const char *value, const char *response)
+{
+ if (!stricmp(value, "UpdatePlayers"))
+ {
+ // server has indicated a change, force an update
+ m_flUpdateTime = 0.0f;
+ }
+ else if (!stricmp(value, "playerlist"))
+ {
+ // new list of players
+ m_pPlayerListPanel->DeleteAllItems();
+
+ // parse response
+ const char *parse = response;
+ while (parse && *parse)
+ {
+ // first should be the size of the player name
+ char name[64];
+ name[0] = '\0';
+ char authID[64];
+ authID[0] = '\0';
+ char netAdr[32];
+ netAdr[0] = '\0';
+ int ping = 0, packetLoss = 0, frags = 0, connectTime = 0;
+
+ ivgui()->DPrintf2("orig: %s\n", parse);
+
+ // parse out the name, which is quoted
+ Assert(*parse == '\"');
+ if (*parse != '\"')
+ break;
+ ++parse; // move past start quote
+ int pos = 0;
+ while (*parse && *parse != '\"')
+ {
+ name[pos++] = *parse;
+ parse++;
+ }
+ name[pos] = 0;
+ parse++; // move past end quote
+
+ if (6 != sscanf(parse, " %s %s %d %d %d %d\n", authID, netAdr, &ping, &packetLoss, &frags, &connectTime))
+ break;
+
+ const char *timeStr = FormatSeconds(connectTime);
+
+ ivgui()->DPrintf2("pars: \"%s\" %s %s %d %d %d %s\n", name, authID, netAdr, ping, packetLoss, frags, timeStr);
+
+ // add to list
+ KeyValues *player = new KeyValues("Player");
+ player->SetString("name", name);
+ player->SetString("authID", authID);
+ player->SetString("netAdr", netAdr);
+ player->SetInt("ping", ping);
+ player->SetInt("loss", packetLoss);
+ player->SetInt("frags", frags);
+ player->SetString("time", timeStr);
+ m_pPlayerListPanel->AddItem(player, 0, false, false);
+
+ // move to next line
+ parse = strchr(parse, '\n');
+ if (parse)
+ {
+ parse++;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Buttom command handlers
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnCommand(const char *command)
+{
+ BaseClass::OnCommand(command);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles the UI for kicking a player from the server
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnKickButtonPressed()
+{
+ if (m_pPlayerListPanel->GetSelectedItemsCount() < 1)
+ return;
+
+ // open a message box to ask the user if they want to follow through on this
+ QueryBox *box;
+ if (m_pPlayerListPanel->GetSelectedItemsCount() > 1)
+ {
+ box = new QueryBox("#Kick_Multiple_Players_Title", "#Kick_Multiple_Players_Question");
+ }
+ else
+ {
+ // show the player name in the message box if only one player is being booted
+ KeyValues *kv = m_pPlayerListPanel->GetItem(m_pPlayerListPanel->GetSelectedItem(0));
+ Assert(kv != NULL);
+ if (!kv)
+ return;
+
+ wchar_t playerName[64];
+ g_pVGuiLocalize->ConvertANSIToUnicode( kv->GetString("name"), playerName, sizeof(playerName) );
+
+ wchar_t msg[512];
+ g_pVGuiLocalize->ConstructString( msg, sizeof(msg), g_pVGuiLocalize->Find("Kick_Single_Player_Question"), 1, playerName );
+ box = new QueryBox(g_pVGuiLocalize->Find("#Kick_Single_Player_Title"), msg);
+ }
+ box->AddActionSignalTarget(this);
+ box->SetOKCommand(new KeyValues("KickSelectedPlayers"));
+ box->ShowWindow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Prompts a user to be banned
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnBanButtonPressed()
+{
+ if (m_pPlayerListPanel->GetSelectedItemsCount() != 1)
+ return;
+
+ // open a message box to ask the user if they want to follow through on this
+ KeyValues *kv = m_pPlayerListPanel->GetItem(m_pPlayerListPanel->GetSelectedItem(0));
+ Assert(kv != NULL);
+ if (!kv)
+ return;
+
+ const char *player = kv->GetString("name");
+ const char *authid = kv->GetString("authid");
+ const char *netAdr = kv->GetString("netAdr");
+
+ char buf[64];
+ if ( !strcmp( authid, "UNKNOWN" ) )
+ {
+ int s1, s2, s3, s4;
+ if (4 == sscanf(netAdr, "%d.%d.%d.%d", &s1, &s2, &s3, &s4))
+ {
+ Q_snprintf( buf, sizeof(buf), "%d.%d.%d.%d", s1, s2, s3, s4 );
+ authid = buf;
+ }
+ }
+
+ CDialogAddBan *box = new CDialogAddBan(this);
+ box->AddActionSignalTarget(this);
+ box->Activate("addban", player, authid);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Kicks all the players currently selected
+//-----------------------------------------------------------------------------
+void CPlayerPanel::KickSelectedPlayers()
+{
+ for (int i = 0; i < m_pPlayerListPanel->GetSelectedItemsCount(); i++)
+ {
+ // get the player info
+ int row = m_pPlayerListPanel->GetSelectedItem(i);
+ KeyValues *pl = m_pPlayerListPanel->GetItem(row);
+ if (!pl)
+ continue;
+
+ // kick 'em
+ char cmd[512];
+ _snprintf(cmd, sizeof(cmd), "kick \"%s\"", pl->GetString("name"));
+ RemoteServer().SendCommand(cmd);
+ }
+
+ m_pPlayerListPanel->ClearSelectedItems();
+ m_pKickButton->SetEnabled(false);
+ m_pBanButton->SetEnabled(false);
+ OnResetData();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a new ban
+//-----------------------------------------------------------------------------
+void CPlayerPanel::AddBanByID(const char *id, const char *newtime)
+{
+ Assert(id && *id);
+ if (!id || !*id)
+ return;
+
+ // if the newtime string is not valid, then set it to 0 (permanent ban)
+ if (!newtime || atof(newtime) < 0.001)
+ {
+ newtime = "0";
+ }
+
+ const char *banCmd = "banid";
+ const char *saveCmd = "writeip";
+ int s1, s2, s3, s4;
+ if (4 == sscanf(id, "%d.%d.%d.%d", &s1, &s2, &s3, &s4))
+ {
+ banCmd = "addip";
+ saveCmd = "writeid";
+ }
+
+ // send down the ban command
+ char cmd[512];
+ _snprintf(cmd, sizeof(cmd) -1, "%s %s %s\n", banCmd, newtime, id);
+ RemoteServer().SendCommand(cmd);
+
+ // force the file to update
+ RemoteServer().SendCommand(saveCmd);
+
+ // refresh
+ OnResetData();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: opens context menu (user right clicked on a server)
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnOpenContextMenu(int itemID)
+{
+/* CODE DISABLED UNTIL VERIFIED AS WORKING
+ // show the player menus only if the cursor is over it
+ if (IsCursorOver() && m_pPlayerListPanel->GetNumSelectedRows())
+ {
+ // get the server
+ unsigned int playerID = m_pPlayerListPanel->GetDataItem(m_pPlayerListPanel->GetSelectedRow(0))->userData;
+
+ // activate context menu
+ m_pPlayerContextMenu->ShowMenu(this, playerID);
+ }
+*/
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when an item on the list panel is selected.
+//-----------------------------------------------------------------------------
+void CPlayerPanel::OnItemSelected()
+{
+ bool state = true;
+
+ if ( m_pPlayerListPanel->GetSelectedItemsCount() == 0 )
+ {
+ state = false;
+ }
+
+ m_pKickButton->SetEnabled(state);
+ m_pBanButton->SetEnabled(state);
+
+ if ( m_pPlayerListPanel->GetSelectedItemsCount() > 1 )
+ {
+ m_pBanButton->SetEnabled(false);
+ }
+}
diff --git a/tracker/AdminServer/PlayerPanel.h b/tracker/AdminServer/PlayerPanel.h
new file mode 100644
index 0000000..2cf9f91
--- /dev/null
+++ b/tracker/AdminServer/PlayerPanel.h
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef PLAYERPANEL_H
+#define PLAYERPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <KeyValues.h>
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/PropertyPage.h>
+
+#include "PlayerContextMenu.h"
+#include "RemoteServer.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CPlayerPanel : public vgui::PropertyPage, public IServerDataResponse
+{
+ DECLARE_CLASS_SIMPLE( CPlayerPanel, vgui::PropertyPage );
+public:
+ CPlayerPanel(vgui::Panel *parent, const char *name);
+ ~CPlayerPanel();
+
+ // returns the keyvalues for the currently selected row
+ KeyValues *GetSelected();
+
+protected:
+ // property page handlers
+ virtual void OnResetData();
+ virtual void OnThink();
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+
+ // called when the server has returned a requested value
+ virtual void OnServerDataResponse(const char *value, const char *response);
+
+private:
+ // vgui overrides
+ virtual void OnCommand(const char *command);
+
+ // msg handlers
+ MESSAGE_FUNC_INT( OnOpenContextMenu, "OpenContextMenu", itemID );
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+
+ MESSAGE_FUNC( OnKickButtonPressed, "KickPlayer" );
+ MESSAGE_FUNC( OnBanButtonPressed, "BanPlayer" );
+ MESSAGE_FUNC( KickSelectedPlayers, "KickSelectedPlayers" );
+ MESSAGE_FUNC_CHARPTR_CHARPTR( AddBanByID, "AddBanValue", id, time );
+
+ vgui::ListPanel *m_pPlayerListPanel;
+ vgui::Button *m_pKickButton;
+ vgui::Button *m_pBanButton;
+
+ CPlayerContextMenu *m_pPlayerContextMenu;
+
+ float m_flUpdateTime;
+};
+
+#endif // PLAYERPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/RawLogPanel.cpp b/tracker/AdminServer/RawLogPanel.cpp
new file mode 100644
index 0000000..8dc8252
--- /dev/null
+++ b/tracker/AdminServer/RawLogPanel.cpp
@@ -0,0 +1,87 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+
+#include "RawLogPanel.h"
+
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/ILocalize.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui_controls/RichText.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ToggleButton.h>
+#include <vgui_controls/RadioButton.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/PHandle.h>
+#include <vgui_controls/PropertySheet.h>
+#include "vgui_controls/ConsoleDialog.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CRawLogPanel::CRawLogPanel(vgui::Panel *parent, const char *name) : vgui::PropertyPage(parent, name)
+{
+ SetSize(200, 100);
+ m_pConsole = new CConsolePanel( this, "Console", false );
+
+ LoadControlSettings("Admin\\RawLogPanel.res", "PLATFORM");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CRawLogPanel::~CRawLogPanel()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the page
+//-----------------------------------------------------------------------------
+void CRawLogPanel::OnPageShow()
+{
+ BaseClass::OnPageShow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides the page
+//-----------------------------------------------------------------------------
+void CRawLogPanel::OnPageHide()
+{
+ BaseClass::OnPageHide();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: inserts a new string into the main chat panel
+//-----------------------------------------------------------------------------
+void CRawLogPanel::DoInsertString(const char *str)
+{
+ if ( str )
+ {
+ m_pConsole->Print( str );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: run when the send button is pressed, execs a command on the server
+//-----------------------------------------------------------------------------
+void CRawLogPanel::OnCommandSubmitted( char const *pchCommand )
+{
+ if ( !pchCommand || !*pchCommand )
+ return;
+
+ // execute the typed command
+ RemoteServer().SendCommand( pchCommand );
+}
diff --git a/tracker/AdminServer/RawLogPanel.h b/tracker/AdminServer/RawLogPanel.h
new file mode 100644
index 0000000..5843931
--- /dev/null
+++ b/tracker/AdminServer/RawLogPanel.h
@@ -0,0 +1,43 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef RAWLOGPANEL_H
+#define RAWLOGPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+
+#include "RemoteServer.h"
+
+namespace vgui
+{
+ class CConsolePanel;
+}
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CRawLogPanel : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( CRawLogPanel, vgui::PropertyPage );
+public:
+ CRawLogPanel(vgui::Panel *parent, const char *name);
+ ~CRawLogPanel();
+
+ // property page handlers
+ virtual void OnPageShow();
+ virtual void OnPageHide();
+ void DoInsertString(const char *str);
+
+private:
+ MESSAGE_FUNC_CHARPTR( OnCommandSubmitted, "CommandSubmitted", command );
+
+ vgui::CConsolePanel *m_pConsole;
+};
+
+#endif // RAWLOGPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/RemoteServer.cpp b/tracker/AdminServer/RemoteServer.cpp
new file mode 100644
index 0000000..138a6f5
--- /dev/null
+++ b/tracker/AdminServer/RemoteServer.cpp
@@ -0,0 +1,256 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "RemoteServer.h"
+#include <assert.h>
+#include <stdio.h>
+
+#include "tier1/utlbuffer.h"
+#include "IGameServerData.h"
+extern IGameServerData *g_pGameServerData;
+
+//-----------------------------------------------------------------------------
+// Purpose: singleton accessor
+//-----------------------------------------------------------------------------
+CRemoteServer &RemoteServer()
+{
+ static CRemoteServer s_RemoteServer;
+ return s_RemoteServer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CRemoteServer::CRemoteServer()
+{
+ m_iCurrentRequestID = 0;
+ m_ListenerID = INVALID_LISTENER_ID;
+ m_bInitialized = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CRemoteServer::~CRemoteServer()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+void CRemoteServer::Initialize()
+{
+ m_bInitialized = true;
+ Assert( g_pGameServerData );
+ m_ListenerID = g_pGameServerData->GetNextListenerID( false ); // don't require auth on this connection
+ g_pGameServerData->RegisterAdminUIID( m_ListenerID );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: connects to a remote game server
+//-----------------------------------------------------------------------------
+void CRemoteServer::ConnectRemoteGameServer(unsigned int ip, unsigned short port, const char *password)
+{
+ assert(!("CRemoteServer::ConnectRemoteGameServer() not yet implemented"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: request a cvar/data from the server
+//-----------------------------------------------------------------------------
+void CRemoteServer::RequestValue(IServerDataResponse *requester, const char *variable)
+{
+ Assert( m_bInitialized );
+ // add to the response handling table
+ int i = m_ResponseHandlers.AddToTail();
+ m_ResponseHandlers[i].requestID = m_iCurrentRequestID;
+ m_ResponseHandlers[i].handler = requester;
+
+ // build the command
+ char buf[512];
+ CUtlBuffer cmd(buf, sizeof(buf));
+
+ cmd.PutInt(m_iCurrentRequestID++);
+ cmd.PutInt(SERVERDATA_REQUESTVALUE);
+ cmd.PutString(variable);
+ cmd.PutString("");
+
+ // send to server
+ g_pGameServerData->WriteDataRequest(m_ListenerID, cmd.Base(), cmd.TellPut());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets a value
+//-----------------------------------------------------------------------------
+void CRemoteServer::SetValue(const char *variable, const char *value)
+{
+ Assert( m_bInitialized );
+ // build the command
+ char buf[512];
+ CUtlBuffer cmd(buf, sizeof(buf));
+
+ cmd.PutInt(m_iCurrentRequestID++);
+ cmd.PutInt(SERVERDATA_SETVALUE);
+ cmd.PutString(variable);
+ cmd.PutString(value);
+
+ // send to server
+ g_pGameServerData->WriteDataRequest(m_ListenerID, cmd.Base(), cmd.TellPut());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a custom command
+//-----------------------------------------------------------------------------
+void CRemoteServer::SendCommand(const char *commandString)
+{
+ Assert( m_bInitialized );
+ // build the command
+ char buf[512];
+ CUtlBuffer cmd(buf, sizeof(buf));
+
+ cmd.PutInt(m_iCurrentRequestID++);
+ cmd.PutInt(SERVERDATA_EXECCOMMAND);
+ cmd.PutString(commandString);
+ cmd.PutString("");
+
+ g_pGameServerData->WriteDataRequest(m_ListenerID, cmd.Base(), cmd.TellPut());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: changes the current password on the server
+// responds with "PasswordChange" "true" or "PasswordChange" "false"
+//-----------------------------------------------------------------------------
+void CRemoteServer::ChangeAccessPassword(IServerDataResponse *requester, const char *newPassword)
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: process any return values, firing any IServerDataResponse items
+// Output : returns true if any items were fired
+//-----------------------------------------------------------------------------
+bool CRemoteServer::ProcessServerResponse()
+{
+ Assert(g_pGameServerData != NULL);
+ Assert( m_bInitialized );
+
+ char charbuf[4096];
+ bool bProcessedAnyPackets = false;
+ while (1)
+ {
+ // get packet from networking
+ int bytesRead = g_pGameServerData->ReadDataResponse(m_ListenerID, charbuf, sizeof(charbuf));
+ if (bytesRead < 1)
+ break;
+ bProcessedAnyPackets = true;
+
+ // parse response
+ CUtlBuffer buf(charbuf, bytesRead, CUtlBuffer::READ_ONLY);
+ int requestID = buf.GetInt();
+ int responseType = buf.GetInt();
+ char variable[64];
+ buf.GetString(variable);
+
+ switch (responseType)
+ {
+ case SERVERDATA_RESPONSE_VALUE:
+ {
+ int valueSize = buf.GetInt();
+ Assert(valueSize > 0);
+ CUtlBuffer value(0, valueSize);
+ if (valueSize > 0)
+ {
+ value.Put(buf.PeekGet(), valueSize);
+ }
+ else
+ {
+ // null terminate
+ value.PutChar(0);
+ }
+
+ // find callback (usually will be the first one in the list)
+ for (int i = m_ResponseHandlers.Head(); m_ResponseHandlers.IsValidIndex(i); i = m_ResponseHandlers.Next(i))
+ {
+ if (m_ResponseHandlers[i].requestID == requestID)
+ {
+ // found, call
+ m_ResponseHandlers[i].handler->OnServerDataResponse(variable, (const char *)value.Base());
+
+ // remove from list
+ m_ResponseHandlers.Remove(i);
+
+ // there is only ever one handler for a message
+ break;
+ }
+ }
+ }
+ break;
+
+ case SERVERDATA_UPDATE:
+ {
+ // find all the people watching for this message
+ for (int i = m_MessageHandlers.Head(); m_MessageHandlers.IsValidIndex(i); i = m_MessageHandlers.Next(i))
+ {
+ if (!stricmp(m_MessageHandlers[i].messageName, variable))
+ {
+ // found, call
+ m_MessageHandlers[i].handler->OnServerDataResponse(variable, "");
+
+ // keep looking, there can be more than one handler for a message
+ }
+ }
+ }
+ break;
+ default:
+ Assert(responseType == SERVERDATA_RESPONSE_VALUE || responseType == SERVERDATA_UPDATE);
+ break;
+ }
+ }
+
+ return bProcessedAnyPackets;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds a constant watches for a particular message
+//-----------------------------------------------------------------------------
+void CRemoteServer::AddServerMessageHandler(IServerDataResponse *handler, const char *watch)
+{
+ // add to the server message handling table
+ int i = m_MessageHandlers.AddToTail();
+ strncpy(m_MessageHandlers[i].messageName, watch, sizeof(m_MessageHandlers[i].messageName) - 1);
+ m_MessageHandlers[i].messageName[sizeof(m_MessageHandlers[i].messageName) - 1] = 0;
+ m_MessageHandlers[i].handler = handler;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: removes a requester from the list to guarantee the pointer won't be used
+//-----------------------------------------------------------------------------
+void CRemoteServer::RemoveServerDataResponseTarget(IServerDataResponse *invalidRequester)
+{
+ // iterate the responses
+ for (int i = 0; i < m_ResponseHandlers.MaxElementIndex(); i++)
+ {
+ if (m_ResponseHandlers.IsValidIndex(i))
+ {
+ if (m_ResponseHandlers[i].handler == invalidRequester)
+ {
+ // found invalid handler, remove from list
+ m_ResponseHandlers.Remove(i);
+ }
+ }
+ }
+ // iterate the message handlers
+ for (int i = 0; i < m_MessageHandlers.MaxElementIndex(); i++)
+ {
+ if (m_MessageHandlers.IsValidIndex(i))
+ {
+ if (m_MessageHandlers[i].handler == invalidRequester)
+ {
+ // found invalid handler, remove from list
+ m_MessageHandlers.Remove(i);
+ }
+ }
+ }
+}
diff --git a/tracker/AdminServer/RemoteServer.h b/tracker/AdminServer/RemoteServer.h
new file mode 100644
index 0000000..a5c31e3
--- /dev/null
+++ b/tracker/AdminServer/RemoteServer.h
@@ -0,0 +1,95 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef REMOTESERVER_H
+#define REMOTESERVER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "UtlLinkedList.h"
+#include "igameserverdata.h"
+
+class IServerDataResponse;
+
+//-----------------------------------------------------------------------------
+// Purpose: Configures and installs the connection to the game server (remote or local)
+//-----------------------------------------------------------------------------
+class CRemoteServer
+{
+public:
+ CRemoteServer();
+ ~CRemoteServer();
+
+ // setup this object
+ void Initialize();
+
+ // remote connection
+ void ConnectRemoteGameServer(unsigned int ip, unsigned short port, const char *password);
+
+ // request a cvar/data from the server
+ void RequestValue(IServerDataResponse *requester, const char *variable);
+
+ // sets a value
+ void SetValue(const char *variable, const char *value);
+
+ // sends a custom command
+ void SendCommand(const char *commandString);
+
+ // changes the current password on the server
+ // responds with "PasswordChange" "true" or "PasswordChange" "false"
+ void ChangeAccessPassword(IServerDataResponse *requester, const char *newPassword);
+
+ // process any return values, firing any IServerDataResponse items
+ // returns true if any items were fired
+ bool ProcessServerResponse();
+
+ // Adds a constant watches for a particular message. Used to handle
+ // information channels from the server->client (map changed, player joined, etc.)
+ void AddServerMessageHandler(IServerDataResponse *handler, const char *watch);
+
+ // removes a requester from the list to guarantee the pointer won't be used
+ void RemoveServerDataResponseTarget(IServerDataResponse *invalidRequester);
+
+private:
+ int m_iCurrentRequestID;
+ ra_listener_id m_ListenerID;
+ bool m_bInitialized;
+
+ // list of all the currently waiting response handlers
+ struct ResponseHandler_t
+ {
+ int requestID;
+ IServerDataResponse *handler;
+ };
+ CUtlLinkedList<ResponseHandler_t, int> m_ResponseHandlers;
+
+ // list of constant response handlers
+ struct MessageHandler_t
+ {
+ char messageName[32];
+ IServerDataResponse *handler;
+ };
+ CUtlLinkedList<MessageHandler_t, int> m_MessageHandlers;
+
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: callback interface
+//-----------------------------------------------------------------------------
+class IServerDataResponse
+{
+public:
+ // called when the server has returned a requested value
+ virtual void OnServerDataResponse(const char *value, const char *response) = 0;
+};
+
+// singleton accessor
+extern CRemoteServer &RemoteServer();
+
+
+#endif // REMOTESERVER_H
diff --git a/tracker/AdminServer/RulesContextMenu.cpp b/tracker/AdminServer/RulesContextMenu.cpp
new file mode 100644
index 0000000..3e1a4e6
--- /dev/null
+++ b/tracker/AdminServer/RulesContextMenu.cpp
@@ -0,0 +1,51 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "RulesContextMenu.h"
+
+#include <VGUI_Controls.h>
+#include <VGUI_IInput.h>
+#include <VGUI_IPanel.h>
+#include <VGUI_ISurface.h>
+#include <VGUI_KeyValues.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CRulesContextMenu::CRulesContextMenu(Panel *parent) : Menu(parent, "RulesContextMenu")
+{
+ CRulesContextMenu::parent=parent;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CRulesContextMenu::~CRulesContextMenu()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the menu
+//-----------------------------------------------------------------------------
+void CRulesContextMenu::ShowMenu(Panel *target, unsigned int cvarID)
+{
+ ClearMenu();
+
+ AddMenuItem("cvar", "&Change Value", new KeyValues("cvar", "cvarID", cvarID), CRulesContextMenu::parent);
+
+
+ MakePopup();
+ int x, y, gx, gy;
+ input()->GetCursorPos(x, y);
+ ipanel()->GetPos(surface()->GetEmbeddedPanel(), gx, gy);
+ SetPos(x - gx, y - gy);
+ MoveToFront();
+ RequestFocus();
+ SetVisible(true);
+}
diff --git a/tracker/AdminServer/RulesContextMenu.h b/tracker/AdminServer/RulesContextMenu.h
new file mode 100644
index 0000000..b79ccc2
--- /dev/null
+++ b/tracker/AdminServer/RulesContextMenu.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef RULESCONTEXTMENU_H
+#define RULESCONTEXTMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Menu.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic right-click context menu for servers
+//-----------------------------------------------------------------------------
+class CRulesContextMenu : public vgui::Menu
+{
+public:
+ CRulesContextMenu(vgui::Panel *parent);
+ ~CRulesContextMenu();
+
+ // call this to activate the menu
+ void ShowMenu(vgui::Panel *target, unsigned int cvarID);
+private:
+ vgui::Panel *parent; // so we can send it messages
+};
+
+
+#endif // RULESCONTEXTMENU_H
diff --git a/tracker/AdminServer/ServerConfigPanel.cpp b/tracker/AdminServer/ServerConfigPanel.cpp
new file mode 100644
index 0000000..4f389d6
--- /dev/null
+++ b/tracker/AdminServer/ServerConfigPanel.cpp
@@ -0,0 +1,61 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <stdio.h>
+
+#include "ServerConfigPanel.h"
+
+#include <vgui/ISystem.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CServerConfigPanel::CServerConfigPanel(vgui::Panel *parent, const char *name, const char *mod) : CVarListPropertyPage(parent, name)
+{
+ SetBounds(0, 0, 500, 170);
+ LoadControlSettings("Admin\\ServerConfigPanel.res", "PLATFORM");
+
+ // load our rules
+ if (!LoadVarList("scripts/GameServerConfig.vdf"))
+ {
+ //!! no local mod info, need to load from server
+ //!! always load from server if on a remote connection
+ }
+
+ m_flUpdateTime = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CServerConfigPanel::~CServerConfigPanel()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reset data
+//-----------------------------------------------------------------------------
+void CServerConfigPanel::OnResetData()
+{
+ RefreshVarList();
+ // update every minute
+ m_flUpdateTime = (float)system()->GetFrameTime() + (60 * 1.0f);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if data needs to be refreshed
+//-----------------------------------------------------------------------------
+void CServerConfigPanel::OnThink()
+{
+ if (m_flUpdateTime < system()->GetFrameTime())
+ {
+ OnResetData();
+ }
+}
diff --git a/tracker/AdminServer/ServerConfigPanel.h b/tracker/AdminServer/ServerConfigPanel.h
new file mode 100644
index 0000000..4701104
--- /dev/null
+++ b/tracker/AdminServer/ServerConfigPanel.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERCONFIGPANEL_H
+#define SERVERCONFIGPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "VarListPropertyPage.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays and allows modification to variable specific to the game
+//-----------------------------------------------------------------------------
+class CServerConfigPanel : public CVarListPropertyPage
+{
+public:
+ CServerConfigPanel(vgui::Panel *parent, const char *name, const char *mod);
+ ~CServerConfigPanel();
+
+protected:
+ // variable updates
+ virtual void OnResetData();
+ virtual void OnThink();
+
+private:
+ float m_flUpdateTime;
+ typedef CVarListPropertyPage BaseClass;
+};
+
+#endif // SERVERCONFIGPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/ServerContextMenu.cpp b/tracker/AdminServer/ServerContextMenu.cpp
new file mode 100644
index 0000000..a7b015c
--- /dev/null
+++ b/tracker/AdminServer/ServerContextMenu.cpp
@@ -0,0 +1,104 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ServerContextMenu.h"
+
+#include <VGUI_Controls.h>
+#include <VGUI_IInput.h>
+#include <VGUI_IPanel.h>
+#include <VGUI_ISurface.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_PropertySheet.h>
+#include <stdio.h>
+
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CServerContextMenu::CServerContextMenu(CServerPage *parent) : Menu(parent, "ServerContextMenu")
+{
+ CServerContextMenu::parent=parent;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CServerContextMenu::~CServerContextMenu()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the menu
+//-----------------------------------------------------------------------------
+void CServerContextMenu::ShowMenu(Panel *target, unsigned int serverID, bool showConnect, bool showRefresh, bool showAddToFavorites,bool manage)
+{
+ ClearMenu();
+
+
+ // by default show the menu
+ bool displayed=false;
+
+ if(serverID==-1)
+ {
+ displayed=true; // no server selected, clicking on an empty area :)
+ }
+
+ if (showConnect)
+ {
+ displayed=true;
+ AddMenuItem("ConnectToServer", "&Connect to server", new KeyValues("ConnectToServer", "serverID", serverID), target);
+ AddMenuItem("ViewGameInfo", "&View server info", new KeyValues("ViewGameInfo", "serverID", serverID), target);
+ }
+
+ if (showRefresh)
+ {
+ displayed=true;
+ AddMenuItem("RefreshServer", "&Refresh server", new KeyValues("RefreshServer", "serverID", serverID), target);
+ }
+
+ if (showAddToFavorites)
+ {
+ displayed=true;
+ AddMenuItem("AddToFavorites", "&Add server to favorites", new KeyValues("AddToFavorites", "serverID", serverID), target);
+ }
+
+ if(manage)
+ {
+ displayed=true;
+ AddMenuItem("Manage", "&Manage Server", new KeyValues("Manage", "serverID", serverID), CServerContextMenu::parent);
+ }
+
+/* if (parent->IsCursorOver() ) // if the cursor is over the tabs
+ {
+ displayed=false;
+ if((int) parent->GetTabPanel()->GetActivePageNum()!=0) // don't let the first tab be deleted, its our servers tab :)
+ {
+ char name[100];
+ displayed=true;
+
+ strncpy(name,"&Delete ",100);
+ parent->GetTabPanel()->GetActiveTabTitle(name+8,100-8);
+
+ AddMenuItem("Delete", name,new KeyValues("DeleteServer", "panelid",(int) parent->GetTabPanel()->GetActivePageNum()), CServerContextMenu::parent);
+ }
+ } */
+
+
+ if(displayed)
+ {
+ MakePopup();
+ int x, y, gx, gy;
+ input()->GetCursorPos(x, y);
+ ipanel()->GetPos(surface()->GetEmbeddedPanel(), gx, gy);
+ SetPos(x - gx, y - gy);
+ MoveToFront();
+ RequestFocus();
+ SetVisible(true);
+ }
+}
diff --git a/tracker/AdminServer/ServerContextMenu.h b/tracker/AdminServer/ServerContextMenu.h
new file mode 100644
index 0000000..c9bf2ea
--- /dev/null
+++ b/tracker/AdminServer/ServerContextMenu.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERCONTEXTMENU_H
+#define SERVERCONTEXTMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Menu.h>
+#include "serverpage.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic right-click context menu for servers
+//-----------------------------------------------------------------------------
+class CServerContextMenu : public vgui::Menu
+{
+public:
+ CServerContextMenu(CServerPage /*vgui::Panel*/ *parent);
+ ~CServerContextMenu();
+
+ // call this to activate the menu
+ void ShowMenu(vgui::Panel *target, unsigned int serverID, bool showConnect, bool showRefresh, bool showAddToFavorites,bool manage);
+private:
+ CServerPage /*vgui::Panel*/ *parent; // so we can send it messages
+};
+
+
+#endif // SERVERCONTEXTMENU_H
diff --git a/tracker/AdminServer/ServerList.cpp b/tracker/AdminServer/ServerList.cpp
new file mode 100644
index 0000000..741e852
--- /dev/null
+++ b/tracker/AdminServer/ServerList.cpp
@@ -0,0 +1,446 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "IServerRefreshResponse.h"
+#include "ServerList.h"
+//#include "ServerMsgHandlerDetails.h"
+#include "Socket.h"
+#include "proto_oob.h"
+
+// for debugging
+#include <VGUI_Controls.h>
+#include <VGUI_ISystem.h>
+#include <VGUI_IVGui.h>
+
+typedef enum
+{
+ NONE = 0,
+ INFO_REQUESTED,
+ INFO_RECEIVED
+} QUERYSTATUS;
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+//-----------------------------------------------------------------------------
+// Purpose: Comparison function used in query redblack tree
+//-----------------------------------------------------------------------------
+bool QueryLessFunc( const query_t &item1, const query_t &item2 )
+{
+ // compare port then ip
+ if (item1.addr.port < item2.addr.port)
+ return true;
+ else if (item1.addr.port > item2.addr.port)
+ return false;
+
+ int ip1 = *(int *)&item1.addr.ip;
+ int ip2 = *(int *)&item2.addr.ip;
+
+ return ip1 < ip2;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CServerList::CServerList(IServerRefreshResponse *target) : m_Queries(0, MAX_QUERY_SOCKETS, QueryLessFunc)
+{
+ m_pResponseTarget = target;
+ m_iUpdateSerialNumber = 1;
+
+ // calculate max sockets based on users' rate
+ char speedBuf[32];
+ int internetSpeed;
+ if (!vgui::system()->GetRegistryString("HKEY_CURRENT_USER\\Software\\Valve\\Tracker\\Rate", speedBuf, sizeof(speedBuf)-1))
+ {
+ // default to DSL speed if no reg key found (an unlikely occurance)
+ strcpy(speedBuf, "7500");
+ }
+ internetSpeed = atoi(speedBuf);
+ int maxSockets = (MAX_QUERY_SOCKETS * internetSpeed) / 10000;
+ if (internetSpeed < 6000)
+ {
+ // reduce the number of active queries again for slow internet speeds
+ maxSockets /= 2;
+ }
+ m_nMaxActive = maxSockets;
+
+ m_nRampUpSpeed = 1;
+ m_bQuerying = false;
+ m_nMaxRampUp = 1;
+
+ m_nInvalidServers = 0;
+ m_nRefreshedServers = 0;
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CServerList::~CServerList()
+{
+// delete m_pQuery;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerList::RunFrame()
+{
+
+ for(int i=0;i<m_Servers.Count();i++) {
+ m_Servers[i]->RunFrame();
+ }
+
+ QueryFrame();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets a server from the list by id, range [0, ServerCount)
+//-----------------------------------------------------------------------------
+serveritem_t &CServerList::GetServer(unsigned int serverID)
+{
+ if (m_Servers.IsValidIndex(serverID))
+ {
+ return m_Servers[serverID]->GetServer();
+ }
+
+ // return a dummy
+ static serveritem_t dummyServer;
+ memset(&dummyServer, 0, sizeof(dummyServer));
+ return dummyServer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the number of servers
+//-----------------------------------------------------------------------------
+int CServerList::ServerCount()
+{
+ return m_Servers.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the number of servers not yet pinged
+//-----------------------------------------------------------------------------
+int CServerList::RefreshListRemaining()
+{
+ return m_RefreshList.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the server list is still in the process of talking to servers
+//-----------------------------------------------------------------------------
+bool CServerList::IsRefreshing()
+{
+ return m_bQuerying;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds a new server to the list
+//-----------------------------------------------------------------------------
+unsigned int CServerList::AddNewServer(serveritem_t &server)
+{
+
+ unsigned int serverID = m_Servers.AddToTail(new CServerInfo(this ,server));
+ m_Servers[serverID]->serverID = serverID;
+ return serverID;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clears all servers from the list
+//-----------------------------------------------------------------------------
+void CServerList::Clear()
+{
+ StopRefresh();
+
+ m_Servers.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: stops all refreshing
+//-----------------------------------------------------------------------------
+void CServerList::StopRefresh()
+{
+ // Reset query context
+ m_Queries.RemoveAll();
+
+ // reset server received states
+ int count = ServerCount();
+ for (int i = 0; i < count; i++)
+ {
+ m_Servers[i]->received = 0;
+ }
+
+ m_RefreshList.RemoveAll();
+
+ // up the serial number so previous results don't interfere
+ m_iUpdateSerialNumber++;
+
+ m_nInvalidServers = 0;
+ m_nRefreshedServers = 0;
+ m_bQuerying = false;
+ m_nMaxRampUp = m_nRampUpSpeed;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: marks a server to be refreshed
+//-----------------------------------------------------------------------------
+void CServerList::AddServerToRefreshList(unsigned int serverID)
+{
+ if (!m_Servers.IsValidIndex(serverID))
+ return;
+
+ serveritem_t &server = m_Servers[serverID]->GetServer();
+ server.received = NONE;
+
+ m_RefreshList.AddToTail(serverID);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerList::StartRefresh()
+{
+ if (m_RefreshList.Count() > 0)
+ {
+ m_bQuerying = true;
+ }
+}
+
+
+void CServerList::ServerResponded()
+{
+ for(int i=0;i<m_Servers.Count();i++) {
+ if ( m_Servers[i]->Refreshed() ) {
+
+ serveritem_t &server = m_Servers[i]->GetServer();
+ // copy in data necessary for filters
+
+ // add to ping times list
+ server.pings[0] = server.pings[1];
+ server.pings[1] = server.pings[2];
+ server.pings[2] = server.ping;
+
+ // calculate ping
+ int ping = CalculateAveragePing(server);
+
+ // make sure the ping changes each time so the user can see the server has updated
+ if (server.ping == ping && ping>0)
+ {
+ ping--;
+ }
+ server.ping = ping;
+ server.received = INFO_RECEIVED;
+
+ netadr_t adr;
+ adr.ip[0] = server.ip[0];
+ adr.ip[1] = server.ip[1];
+ adr.ip[2] = server.ip[2];
+ adr.ip[3] = server.ip[3];
+ adr.port = (server.port & 0xff) << 8 | (server.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+
+ query_t finder;
+ finder.addr = adr;
+
+ m_Queries.Remove(finder);
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded(server);
+ }
+
+ }
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when a server response has timed out
+//-----------------------------------------------------------------------------
+void CServerList::ServerFailedToRespond()
+{
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: recalculates a servers ping, from the last few ping times
+//-----------------------------------------------------------------------------
+int CServerList::CalculateAveragePing(serveritem_t &server)
+{
+ if (server.pings[0])
+ {
+ // three pings, throw away any the most extreme and average the other two
+ int middlePing = 0, lowPing = 1, highPing = 2;
+ if (server.pings[0] < server.pings[1])
+ {
+ if (server.pings[0] > server.pings[2])
+ {
+ lowPing = 2;
+ middlePing = 0;
+ highPing = 1;
+ }
+ else if (server.pings[1] < server.pings[2])
+ {
+ lowPing = 0;
+ middlePing = 1;
+ highPing = 2;
+ }
+ else
+ {
+ lowPing = 0;
+ middlePing = 2;
+ highPing = 1;
+ }
+ }
+ else
+ {
+ if (server.pings[1] > server.pings[2])
+ {
+ lowPing = 2;
+ middlePing = 1;
+ highPing = 0;
+ }
+ else if (server.pings[0] < server.pings[2])
+ {
+ lowPing = 1;
+ middlePing = 0;
+ highPing = 2;
+ }
+ else
+ {
+ lowPing = 1;
+ middlePing = 2;
+ highPing = 0;
+ }
+ }
+
+ // we have the middle ping, see which it's closest to
+ if ((server.pings[middlePing] - server.pings[lowPing]) < (server.pings[highPing] - server.pings[middlePing]))
+ {
+ return (server.pings[middlePing] + server.pings[lowPing]) / 2;
+ }
+ else
+ {
+ return (server.pings[middlePing] + server.pings[highPing]) / 2;
+ }
+ }
+ else if (server.pings[1])
+ {
+ // two pings received, average them
+ return (server.pings[1] + server.pings[2]) / 2;
+ }
+ else
+ {
+ // only one ping received so far, use that
+ return server.pings[2];
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every frame to check queries
+//-----------------------------------------------------------------------------
+void CServerList::QueryFrame()
+{
+ if (!m_bQuerying)
+ return;
+
+ float curtime = CSocket::GetClock();
+
+ // walk the query list, looking for any server timeouts
+ unsigned short idx = m_Queries.FirstInorder();
+ while (m_Queries.IsValidIndex(idx))
+ {
+ query_t &query = m_Queries[idx];
+ if ((curtime - query.sendTime) > 1.2f)
+ {
+ // server has timed out
+ serveritem_t &item = m_Servers[query.serverID]->GetServer();
+
+ // mark the server
+ item.pings[0] = item.pings[1];
+ item.pings[1] = item.pings[2];
+ item.pings[2] = 1200;
+ item.ping = CalculateAveragePing(item);
+ if (!item.hadSuccessfulResponse)
+ {
+ // remove the server if it has never responded before
+ item.doNotRefresh = true;
+ m_nInvalidServers++;
+ }
+ // respond to the game list notifying of the lack of response
+ m_pResponseTarget->ServerFailedToRespond(item);
+ item.received = false;
+
+ // get the next server now, since we're about to delete it from query list
+ unsigned short nextidx = m_Queries.NextInorder(idx);
+
+ // delete the query
+ m_Queries.RemoveAt(idx);
+
+ // move to next item
+ idx = nextidx;
+ }
+ else
+ {
+ // still waiting for server result
+ idx = m_Queries.NextInorder(idx);
+ }
+ }
+
+
+ // increment the number of sockets to use
+ m_nMaxRampUp = min(m_nMaxActive, m_nMaxRampUp + m_nRampUpSpeed);
+
+ // see if we should send more queries
+ while (m_RefreshList.Count() > 0 && (int)m_Queries.Count() < m_nMaxRampUp)
+ {
+ // get the first item from the list to refresh
+ int currentServer = m_RefreshList[0];
+ if (!m_Servers.IsValidIndex(currentServer))
+ break;
+ serveritem_t &item = m_Servers[currentServer]->GetServer();
+
+ item.time = curtime;
+
+ //QueryServer(m_pQuery, currentServer);
+ m_Servers[currentServer]->Query();
+
+ query_t query;
+
+ netadr_t adr;
+ adr.ip[0] = item.ip[0];
+ adr.ip[1] = item.ip[1];
+ adr.ip[2] = item.ip[2];
+ adr.ip[3] = item.ip[3];
+ adr.port = (item.port & 0xff) << 8 | (item.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+
+ query.addr =adr;
+ query.sendTime=curtime;
+ query.serverID=item.serverID;
+
+ m_Queries.Insert(query);
+
+ // remove the server from the refresh list
+ m_RefreshList.Remove((int)0);
+ }
+
+ // Done querying?
+ if (m_Queries.Count() < 1)
+ {
+ m_bQuerying = false;
+ m_pResponseTarget->RefreshComplete();
+
+ // up the serial number, so that we ignore any late results
+ m_iUpdateSerialNumber++;
+ }
+}
+
+
+
+
diff --git a/tracker/AdminServer/ServerList.h b/tracker/AdminServer/ServerList.h
new file mode 100644
index 0000000..accbd20
--- /dev/null
+++ b/tracker/AdminServer/ServerList.h
@@ -0,0 +1,112 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERLIST_H
+#define SERVERLIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+#include "serverinfo.h"
+#include "iresponse.h"
+
+
+#include "utlrbtree.h"
+
+class CSocket;
+class IServerRefreshResponse;
+
+// holds a single query - definition needs to be public
+struct query_t
+{
+ netadr_t addr;
+ int serverID;
+ float sendTime;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles a list of servers, and can refresh them
+//-----------------------------------------------------------------------------
+class CServerList: public IResponse
+{
+public:
+ CServerList(IServerRefreshResponse *gameList);
+ ~CServerList();
+
+ // Handles a frame of networking
+ void RunFrame();
+
+ // gets a server from the list by id, range [0, ServerCount)
+ serveritem_t &GetServer(unsigned int serverID);
+
+ // returns the number of servers
+ int ServerCount();
+
+ // adds a new server to the list, returning a handle to the server
+ unsigned int AddNewServer(serveritem_t &server);
+
+ // starts a refresh
+ void StartRefresh();
+
+ // stops all refreshing
+ void StopRefresh();
+
+ // clears all servers from the list
+ void Clear();
+
+ // marks a server to be refreshed
+ void AddServerToRefreshList(unsigned int serverID);
+
+ // returns true if servers are currently being refreshed
+ bool IsRefreshing();
+
+ // returns the number of servers not yet pinged
+ int RefreshListRemaining();
+
+ // implementation of IRconResponse interface
+ // called when the server has successfully responded to an info command
+ virtual void ServerResponded();
+
+ // called when a server response has timed out
+ virtual void ServerFailedToRespond();
+
+
+private:
+ // Run query logic for this frame
+ void QueryFrame();
+ // recalculates a servers ping, from the last few ping times
+ int CalculateAveragePing(serveritem_t &server);
+
+ IServerRefreshResponse *m_pResponseTarget;
+
+ enum
+ {
+ MAX_QUERY_SOCKETS = 255,
+ };
+
+
+ // holds the list of all the currently active queries
+ CUtlRBTree<query_t, unsigned short> m_Queries;
+
+ // list of all known servers
+ CUtlVector<CServerInfo *> m_Servers;
+
+ // list of servers to be refreshed, in order... this would be more optimal as a queue
+ CUtlVector<int> m_RefreshList;
+
+ int m_iUpdateSerialNumber; // serial number of current update so we don't get results overlapping between different server list updates
+ bool m_bQuerying; // Is refreshing taking place?
+ int m_nMaxActive; // Max # of simultaneous sockets to use for querying
+ int m_nMaxRampUp; // increasing number of sockets to use
+ int m_nRampUpSpeed; // amount to ramp up each frame
+ int m_nInvalidServers; // number of servers marked as 'no not refresh'
+ int m_nRefreshedServers; // count of servers refreshed
+};
+
+#endif // SERVERLIST_H
diff --git a/tracker/AdminServer/ServerListCompare.cpp b/tracker/AdminServer/ServerListCompare.cpp
new file mode 100644
index 0000000..938a1fe
--- /dev/null
+++ b/tracker/AdminServer/ServerListCompare.cpp
@@ -0,0 +1,115 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ServerListCompare.h"
+#include "server.h"
+#include "serverpage.h"
+
+#include <VGUI_ListPanel.h>
+#include <VGUI_KeyValues.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose: List password column sort function
+//-----------------------------------------------------------------------------
+int __cdecl PasswordCompare(vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ serveritem_t &s1 = CServerPage::GetInstance()->GetServer(item1.userData);
+ serveritem_t &s2 = CServerPage::GetInstance()->GetServer(item2.userData);
+
+ if (s1.password < s2.password)
+ return 1;
+ else if (s1.password > s2.password)
+ return -1;
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Ping comparison function
+//-----------------------------------------------------------------------------
+int __cdecl PingCompare(vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ serveritem_t &s1 = CServerPage::GetInstance()->GetServer(item1.userData);
+ serveritem_t &s2 = CServerPage::GetInstance()->GetServer(item2.userData);
+
+ int ping1 = s1.ping;
+ int ping2 = s2.ping;
+
+ if ( ping1 < ping2 )
+ return -1;
+ else if ( ping1 > ping2 )
+ return 1;
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Map comparison function
+//-----------------------------------------------------------------------------
+int __cdecl MapCompare(vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ serveritem_t &s1 = CServerPage::GetInstance()->GetServer(item1.userData);
+ serveritem_t &s2 = CServerPage::GetInstance()->GetServer(item2.userData);
+
+ return stricmp(s1.map, s2.map);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Game dir comparison function
+//-----------------------------------------------------------------------------
+int __cdecl GameCompare(vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ serveritem_t &s1 = CServerPage::GetInstance()->GetServer(item1.userData);
+ serveritem_t &s2 = CServerPage::GetInstance()->GetServer(item2.userData);
+
+ // make sure we haven't added the same server to the list twice
+ assert(p1->userData != p2->userData);
+
+ return stricmp(s1.gameDescription, s2.gameDescription);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Server name comparison function
+//-----------------------------------------------------------------------------
+int __cdecl ServerNameCompare(vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ serveritem_t &s1 = CServerPage::GetInstance()->GetServer(item1.userData);
+ serveritem_t &s2 = CServerPage::GetInstance()->GetServer(item2.userData);
+
+ return stricmp(s1.name, s2.name);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Player number comparison function
+//-----------------------------------------------------------------------------
+int __cdecl PlayersCompare(vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ serveritem_t &s1 = CServerPage::GetInstance()->GetServer(item1.userData);
+ serveritem_t &s2 = CServerPage::GetInstance()->GetServer(item2.userData);
+
+ int s1p = s1.players;
+ int s1m = s1.maxPlayers;
+ int s2p = s2.players;
+ int s2m = s2.maxPlayers;
+
+ // compare number of players
+ if (s1p > s2p)
+ return -1;
+ if (s1p < s2p)
+ return 1;
+
+ // compare max players if number of current players is equal
+ if (s1m > s2m)
+ return -1;
+ if (s1m < s2m)
+ return 1;
+
+ return 0;
+}
+
+
diff --git a/tracker/AdminServer/ServerListCompare.h b/tracker/AdminServer/ServerListCompare.h
new file mode 100644
index 0000000..956c1ae
--- /dev/null
+++ b/tracker/AdminServer/ServerListCompare.h
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERLISTCOMPARE_H
+#define SERVERLISTCOMPARE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+// these functions are common to most server lists in sorts
+int __cdecl PasswordCompare(vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 );
+int __cdecl PingCompare(vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 );
+int __cdecl PlayersCompare(vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 );
+int __cdecl MapCompare(vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 );
+int __cdecl GameCompare(vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 );
+int __cdecl ServerNameCompare(vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 );
+
+#endif // SERVERLISTCOMPARE_H
diff --git a/tracker/AdminServer/TokenLine.cpp b/tracker/AdminServer/TokenLine.cpp
new file mode 100644
index 0000000..d4df390
--- /dev/null
+++ b/tracker/AdminServer/TokenLine.cpp
@@ -0,0 +1,150 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+/*
+** The copyright to the contents herein is the property of Valve, L.L.C.
+** The contents may be used and/or copied only with the written permission of
+** Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+** the agreement/contract under which the contents have been supplied.
+**
+*******************************************************************************
+**
+** Contents:
+**
+** TokenLine.cpp: implementation of the TokenLine class.
+**
+******************************************************************************/
+
+#include "TokenLine.h"
+#include <string.h>
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+
+TokenLine::~TokenLine()
+{
+
+}
+
+
+bool TokenLine::SetLine(const char * newLine)
+{
+ m_tokenNumber = 0;
+
+ if (!newLine || ( strlen(newLine) >= (MAX_LINE_CHARS-1) ) )
+ {
+ memset( m_fullLine, 0, MAX_LINE_CHARS );
+ memset( m_tokenBuffer, 0, MAX_LINE_CHARS );
+ return false;
+ }
+
+ strncpy( m_fullLine, newLine, MAX_LINE_CHARS-1 );
+ m_fullLine[ MAX_LINE_CHARS-1 ] = '\0';
+
+ strncpy( m_tokenBuffer, newLine, MAX_LINE_CHARS-1 );
+ m_tokenBuffer[ MAX_LINE_CHARS-1 ] = '\0';
+
+ // parse tokens
+ char * charPointer = m_tokenBuffer;
+
+ while (*charPointer && (m_tokenNumber < MAX_LINE_TOKENS))
+ {
+ while (*charPointer && ((*charPointer <= 32) || (*charPointer > 126)))
+ charPointer++;
+
+ if (*charPointer)
+ {
+ m_token[m_tokenNumber] = charPointer;
+
+ // special treatment for quotes
+ if (*charPointer == '\"')
+ {
+ charPointer++;
+ m_token[m_tokenNumber] = charPointer;
+ while (*charPointer && (*charPointer != '\"') )
+ charPointer++;
+
+ }
+ else
+ {
+ m_token[m_tokenNumber] = charPointer;
+ while (*charPointer && ((*charPointer > 32) && (*charPointer <= 126)))
+ charPointer++;
+ }
+
+ m_tokenNumber++;
+
+ if (*charPointer)
+ {
+ *charPointer=0;
+ charPointer++;
+ }
+ }
+ }
+
+ return (m_tokenNumber != MAX_LINE_TOKENS);
+}
+
+char * TokenLine::GetLine()
+{
+ return m_fullLine;
+}
+
+char * TokenLine::GetToken(int i)
+{
+ if (i >= m_tokenNumber)
+ return NULL;
+ return m_token[i];
+
+}
+
+// if the given parm is not present return NULL
+// otherwise return the address of the following token, or an empty string
+char* TokenLine::CheckToken(char * parm)
+{
+ for (int i = 0 ; i < m_tokenNumber; i ++)
+ {
+ if (!m_token[i])
+ continue;
+ if ( !strcmp (parm,m_token[i]) )
+ {
+ char * ret = m_token[i+1];
+ // if this token doesn't exist, since index i was the last
+ // return an empty string
+ if ( (i+1) == m_tokenNumber ) ret = "";
+ return ret;
+ }
+
+ }
+
+ return NULL;
+}
+
+int TokenLine::CountToken()
+{
+ int c = 0;
+ for (int i = 0 ; i < m_tokenNumber; i ++)
+ {
+ if (m_token[i])
+ c++;
+ }
+ return c;
+}
+
+char* TokenLine::GetRestOfLine(int i)
+{
+ if (i >= m_tokenNumber)
+ return NULL;
+ return m_fullLine + (m_token[i] - m_tokenBuffer);
+}
+
+TokenLine::TokenLine(char * string)
+{
+ SetLine(string);
+}
+
+TokenLine::TokenLine()
+{
+
+}
diff --git a/tracker/AdminServer/TokenLine.h b/tracker/AdminServer/TokenLine.h
new file mode 100644
index 0000000..0096f05
--- /dev/null
+++ b/tracker/AdminServer/TokenLine.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// TokenLine.h: interface for the CommandLine class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TOKENLINE_H
+#define TOKENLINE_H
+
+#pragma once
+
+#define MAX_LINE_TOKENS 128
+#define MAX_LINE_CHARS 2048
+
+class TokenLine
+{
+
+public:
+ TokenLine();
+ TokenLine( char * string);
+ virtual ~TokenLine();
+
+ char * GetRestOfLine(int i); // returns all chars after token i
+ int CountToken(); // returns number of token
+ char * CheckToken(char * parm);// returns token after token parm or ""
+ char * GetToken(int i); // returns token i
+ char * GetLine(); // returns full line
+ bool SetLine (const char * newLine); // set new token line and parses it
+
+ char m_tokenBuffer[MAX_LINE_CHARS];
+ char m_fullLine[MAX_LINE_CHARS];
+ char * m_token[MAX_LINE_TOKENS];
+ int m_tokenNumber;
+
+};
+
+#endif // !defined TOKENLINE_H
diff --git a/tracker/AdminServer/VarEditDialog.cpp b/tracker/AdminServer/VarEditDialog.cpp
new file mode 100644
index 0000000..bb118f5
--- /dev/null
+++ b/tracker/AdminServer/VarEditDialog.cpp
@@ -0,0 +1,203 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "VarEditDialog.h"
+#include "RemoteServer.h"
+
+#include <stdio.h>
+
+#include <vgui/IInput.h>
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/TextEntry.h>
+#include <KeyValues.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CVarEditDialog::CVarEditDialog(vgui::Panel *parent, const char *name) : Frame(parent, name)
+{
+ SetSize(280, 180);
+ SetSizeable(false);
+ m_pOKButton = new Button(this, "OKButton", "OK");
+ m_pCancelButton = new Button(this, "CancelButton", "Cancel");
+ m_pStringEdit = new TextEntry(this, "StringEdit");
+ m_pComboEdit = new ComboBox(this, "ComboEdit", 12, false);
+ m_pRules = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CVarEditDialog::~CVarEditDialog()
+{
+// input()->ReleaseAppModalSurface();
+ if (m_pRules)
+ {
+ m_pRules->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Configures and shows the var edit dialog
+//-----------------------------------------------------------------------------
+void CVarEditDialog::Activate(vgui::Panel *actionSignalTarget, KeyValues *rules)
+{
+ // configure
+ AddActionSignalTarget(actionSignalTarget);
+ m_pRules = rules->MakeCopy();
+
+ const char *type = m_pRules->GetString("type");
+ if (!stricmp(type, "enumeration"))
+ {
+ LoadControlSettings("Admin/VarEditDialog_ComboBox.res", "PLATFORM");
+ m_pStringEdit->SetVisible(false);
+
+ // fill in the combo box
+ for (KeyValues *kv = m_pRules->FindKey("list", true)->GetFirstSubKey(); kv != NULL; kv = kv->GetNextKey())
+ {
+ Assert( 0 );
+ // FIXME: This Assert doesn't compile
+// Assert(index++ == atoi(kv->GetName()));
+ m_pComboEdit->AddItem(kv->GetString(), NULL);
+ }
+
+ // activate the current item
+ m_pComboEdit->ActivateItemByRow(m_pRules->GetInt("enum"));
+ }
+ else if (!stricmp(type, "customlist"))
+ {
+ LoadControlSettings("Admin/VarEditDialog_ComboBox.res", "PLATFORM");
+ m_pStringEdit->SetVisible(false);
+
+ // fill in the combo box
+ int index = 0;
+ const char *currentValue = m_pRules->GetString("value");
+ const char *parse = m_pRules->GetString("stringlist");
+ while (*parse)
+ {
+ // newline-seperated map list
+ if (*parse == '\n')
+ {
+ parse++;
+ continue;
+ }
+
+ // pull out the map name
+ const char *end = strstr(parse, "\n");
+ if (!end)
+ break;
+
+ char customString[64];
+ int nameSize = end - parse;
+ if (nameSize >= sizeof(customString))
+ {
+ nameSize = sizeof(customString) - 1;
+ }
+
+ // copy in the name
+ strncpy(customString, parse, nameSize);
+ customString[nameSize] = 0;
+ parse = end;
+
+ // add to dropdown
+ int itemID = m_pComboEdit->AddItem(customString, NULL);
+ index++;
+
+ // activate the current item
+ if (!stricmp(customString, currentValue))
+ {
+ m_pComboEdit->ActivateItem(itemID);
+ }
+ }
+ }
+ else
+ {
+ // normal string edit
+ LoadControlSettings("Admin/VarEditDialog_String.res", "PLATFORM");
+ m_pComboEdit->SetVisible(false);
+ m_pStringEdit->SelectAllOnFirstFocus(true);
+ m_pStringEdit->SetText(m_pRules->GetString("value"));
+ }
+
+ // set value
+ char title[256];
+ _snprintf(title, sizeof(title) - 1, "Change %s", m_pRules->GetString("name"));
+ SetTitle(title, false);
+
+ // bring to front
+// input()->SetAppModalSurface(GetVPanel());
+ MoveToCenterOfScreen();
+ BaseClass::Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: button command handler
+//-----------------------------------------------------------------------------
+void CVarEditDialog::OnCommand(const char *command)
+{
+ if (!stricmp(command, "OK"))
+ {
+ // change the value
+ ApplyChanges();
+ Close();
+ }
+ else if (!stricmp(command, "Cancel"))
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Applies changes
+//-----------------------------------------------------------------------------
+void CVarEditDialog::ApplyChanges()
+{
+ const char *type = m_pRules->GetString("type");
+ if (!stricmp(type, "enumeration"))
+ {
+ // get the enumeration position from the combo box
+ int iVal = m_pComboEdit->GetActiveItem();
+ char value[32];
+ _snprintf(value, sizeof(value) - 1, "%d", iVal);
+ RemoteServer().SetValue(m_pRules->GetName(), value);
+
+ }
+ else if (!stricmp(type, "customlist"))
+ {
+ char value[512];
+ m_pComboEdit->GetText(value, sizeof(value));
+ RemoteServer().SetValue(m_pRules->GetName(), value);
+ }
+ else
+ {
+ // normal string
+ char value[512];
+ m_pStringEdit->GetText(value, sizeof(value));
+ RemoteServer().SetValue(m_pRules->GetName(), value);
+ }
+
+ // tell the caller the var changed
+ PostActionSignal(new KeyValues("VarChanged", "var", m_pRules->GetName()));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes on close
+//-----------------------------------------------------------------------------
+void CVarEditDialog::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
diff --git a/tracker/AdminServer/VarEditDialog.h b/tracker/AdminServer/VarEditDialog.h
new file mode 100644
index 0000000..bca993c
--- /dev/null
+++ b/tracker/AdminServer/VarEditDialog.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef VAREDITDIALOG_H
+#define VAREDITDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles editing of cvars
+//-----------------------------------------------------------------------------
+class CVarEditDialog : public vgui::Frame
+{
+public:
+ CVarEditDialog(vgui::Panel *parent, const char *name);
+ ~CVarEditDialog();
+
+ void Activate(vgui::Panel *actionSignalTarget, KeyValues *rules);
+
+protected:
+ virtual void OnCommand(const char *command);
+ virtual void OnClose();
+
+ void ApplyChanges();
+
+private:
+ vgui::Button *m_pOKButton;
+ vgui::Button *m_pCancelButton;
+ vgui::TextEntry *m_pStringEdit;
+ vgui::ComboBox *m_pComboEdit;
+
+ KeyValues *m_pRules;
+
+ typedef vgui::Frame BaseClass;
+};
+
+
+#endif // VAREDITDIALOG_H
diff --git a/tracker/AdminServer/VarListPropertyPage.cpp b/tracker/AdminServer/VarListPropertyPage.cpp
new file mode 100644
index 0000000..15ee3f4
--- /dev/null
+++ b/tracker/AdminServer/VarListPropertyPage.cpp
@@ -0,0 +1,225 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "VarListPropertyPage.h"
+#include "RemoteServer.h"
+#include "VarEditDialog.h"
+
+#include <KeyValues.h>
+#include <vgui/KeyCode.h>
+
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/Button.h>
+
+#include "filesystem.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CVarListPropertyPage::CVarListPropertyPage(vgui::Panel *parent, const char *name) : vgui::PropertyPage(parent, name)
+{
+ m_pRulesList = new ListPanel(this, "RulesList");
+ m_pRulesList->AddColumnHeader(0, "name", "Variable", 256);
+ m_pRulesList->AddColumnHeader(1, "value", "Value", 256);
+
+ m_pEditButton = new Button(this, "EditButton", "Edit...");
+ m_pEditButton->SetCommand(new KeyValues("EditVariable"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CVarListPropertyPage::~CVarListPropertyPage()
+{
+ // remove from callback list
+ RemoteServer().RemoveServerDataResponseTarget(this);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads a list of variables from the file
+//-----------------------------------------------------------------------------
+bool CVarListPropertyPage::LoadVarList(const char *varfile)
+{
+ bool bSuccess = false;
+ // clear the current list
+ m_pRulesList->DeleteAllItems();
+
+ // load list from file
+ KeyValues *dat = new KeyValues("VarList");
+ if (dat->LoadFromFile( g_pFullFileSystem, varfile, NULL))
+ {
+ // enter into list
+ for (KeyValues *rule = dat->GetFirstSubKey(); rule != NULL; rule = rule->GetNextKey())
+ {
+ m_pRulesList->AddItem(rule, 0, false, false);
+ }
+ bSuccess = true;
+ }
+
+ dat->deleteThis();
+ return bSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: configures layout
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::PerformLayout()
+{
+ BaseClass::PerformLayout();
+ OnItemSelected();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles edit button press
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::EditVariable()
+{
+ // get rule from the list
+ int itemID = m_pRulesList->GetSelectedItem(0);
+ KeyValues *rule = m_pRulesList->GetItem(itemID);
+ if (!rule)
+ return;
+
+ OnEditVariable(rule);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Edits var
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::OnEditVariable(KeyValues *rule)
+{
+ // open an edit box appropriate
+ CVarEditDialog *box = new CVarEditDialog(this, "VarEditDialog");
+ box->Activate(this, rule);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: refreshes all the values of cvars in the list
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::RefreshVarList()
+{
+ // iterate the vars
+ for (int i = 0; i < m_pRulesList->GetItemCount(); i++)
+ {
+ KeyValues *row = m_pRulesList->GetItem(i);
+ if (!row)
+ continue;
+
+ // request the info from the server on each one of them
+ RemoteServer().RequestValue(this, row->GetName());
+ }
+
+ RemoteServer().ProcessServerResponse();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the value of a variable in the list
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::SetVarString(const char *varName, const char *value)
+{
+ // find the item by name
+ int itemID = m_pRulesList->GetItem(varName);
+ KeyValues *rule = m_pRulesList->GetItem(itemID);
+ if (!rule)
+ return;
+
+ // parse the rule
+ const char *type = rule->GetString("type");
+ if (!stricmp(type, "enumeration"))
+ {
+ // look up the value in the enumeration
+ int iValue = atoi(value);
+ const char *result = rule->FindKey("list", true)->GetString(value, "");
+ rule->SetString("value", result);
+ rule->SetInt("enum", iValue);
+ }
+ else
+ {
+ // no special type, treat it as a string
+ rule->SetString("value", value);
+ }
+
+ m_pRulesList->ApplyItemChanges(itemID);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets a custom string list
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::SetCustomStringList(const char *varName, const char *stringList)
+{
+ // find the item by name
+ int itemID = m_pRulesList->GetItem(varName);
+ KeyValues *rule = m_pRulesList->GetItem(itemID);
+ if (!rule)
+ return;
+
+ rule->SetString("stringlist", stringList);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets back the value of a variable
+//-----------------------------------------------------------------------------
+const char *CVarListPropertyPage::GetVarString(const char *varName)
+{
+ int itemID = m_pRulesList->GetItem(varName);
+ KeyValues *rule = m_pRulesList->GetItem(itemID);
+ if (!rule)
+ return "";
+
+ return rule->GetString("value");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Causes values to refresh on the user hitting F5
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::OnKeyCodeTyped(KeyCode code)
+{
+ if (code == KEY_F5)
+ {
+ OnResetData();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Enables the edit button if any rows in the list are selected
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::OnItemSelected()
+{
+ if (m_pRulesList->GetSelectedItemsCount() > 0)
+ {
+ m_pEditButton->SetEnabled(true);
+ }
+ else
+ {
+ m_pEditButton->SetEnabled(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when a var gets edited
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::OnVarChanged(const char *var)
+{
+ // request new value from server
+ RemoteServer().RequestValue(this, var);
+ // process the queue immediately, since if we're running a local server there will already be a reply
+ RemoteServer().ProcessServerResponse();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles responses from the server
+//-----------------------------------------------------------------------------
+void CVarListPropertyPage::OnServerDataResponse(const char *value, const char *response)
+{
+ SetVarString(value, response);
+}
diff --git a/tracker/AdminServer/VarListPropertyPage.h b/tracker/AdminServer/VarListPropertyPage.h
new file mode 100644
index 0000000..4553f80
--- /dev/null
+++ b/tracker/AdminServer/VarListPropertyPage.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef VARLISTPROPERTYPAGE_H
+#define VARLISTPROPERTYPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <KeyValues.h>
+#include <vgui_controls/PropertyPage.h>
+
+#include "utlvector.h"
+#include "RemoteServer.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Property page for use in the server admin tool
+// holds a list of variables and manages the editing of them
+//-----------------------------------------------------------------------------
+class CVarListPropertyPage : public vgui::PropertyPage, public IServerDataResponse
+{
+ DECLARE_CLASS_SIMPLE( CVarListPropertyPage, vgui::PropertyPage );
+public:
+ CVarListPropertyPage(vgui::Panel *parent, const char *name);
+ ~CVarListPropertyPage();
+
+ // loads the var list description from the specified file
+ bool LoadVarList(const char *varfile);
+
+ // sets the value of a variable
+ void SetVarString(const char *varName, const char *value);
+
+ // gets back the value of a variable
+ const char *GetVarString(const char *varName);
+
+ // refreshes all the values of cvars in the list
+ virtual void RefreshVarList();
+
+ // sets a custom string list for a combobox edit
+ // stringList is a newline-delimited set of strings
+ void SetCustomStringList(const char *varName, const char *stringList);
+
+protected:
+ // override to change how a variable is edited
+ virtual void OnEditVariable(KeyValues *rule);
+ // handles responses from the server
+ virtual void OnServerDataResponse(const char *value, const char *response);
+
+ // vgui overrides
+ virtual void PerformLayout();
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+ MESSAGE_FUNC_CHARPTR( OnVarChanged, "VarChanged", var );
+
+private:
+ MESSAGE_FUNC( EditVariable, "EditVariable" );
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+
+ vgui::ListPanel *m_pRulesList;
+ vgui::Button *m_pEditButton;
+};
+
+
+#endif // VARLISTPROPERTYPAGE_H
diff --git a/tracker/AdminServer/ban.h b/tracker/AdminServer/ban.h
new file mode 100644
index 0000000..0b9befc
--- /dev/null
+++ b/tracker/AdminServer/ban.h
@@ -0,0 +1,28 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef BAN_H
+#define BAN_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+enum Bans { ID, WONID,AUTHID,IP };
+
+//-----------------------------------------------------------------------------
+// Purpose: Data describing a single player
+//-----------------------------------------------------------------------------
+typedef struct
+{
+
+ char name[20]; // id of the band
+ float time;
+ Bans type;
+} Bans_t;
+
+
+#endif // BAN_H
diff --git a/tracker/AdminServer/banlist.cpp b/tracker/AdminServer/banlist.cpp
new file mode 100644
index 0000000..bbd6929
--- /dev/null
+++ b/tracker/AdminServer/banlist.cpp
@@ -0,0 +1,241 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "banlist.h"
+#include "Iresponse.h"
+
+#include "PlayerMsgHandler.h"
+#include "Socket.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+#include "inetapi.h"
+#include "TokenLine.h"
+#include "dialogkickplayer.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+typedef enum
+{
+ NONE = 0,
+ INFO_REQUESTED,
+ INFO_RECEIVED
+} RCONSTATUS;
+
+CBanList::CBanList(IResponse *target,serveritem_t &server, const char *rconPassword) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+ m_pResponseTarget=target;
+
+ m_bIsRefreshing=false;
+ m_bNewBanList=false;
+ m_bRconFailed=false;
+ m_bGotIPs = false;
+
+ v_strncpy(m_szRconPassword,rconPassword,100);
+
+ m_pRcon = new CRcon(this , server,rconPassword);
+ m_BanList=NULL;
+}
+
+CBanList::~CBanList() {
+ delete m_pRcon;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a status query packet to a single server
+//-----------------------------------------------------------------------------
+void CBanList::SendQuery()
+{
+ // now use "rcon status" to pull the list of bans
+ m_pRcon->SendRcon("listid");
+ m_bGotIPs=false;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBanList::RunFrame()
+{
+ if(m_pRcon)
+ {
+ m_pRcon->RunFrame();
+ }
+
+}
+
+
+void CBanList::ServerResponded()
+{
+
+ if(m_bGotIPs == false)
+ {
+ m_BanList.RemoveAll();
+
+ const char *rconResp = m_pRcon->RconResponse();
+ const char *cur = strstr(rconResp,"UserID filter list:")
+ + strlen("UserID filter list:");
+
+ if( (unsigned int)cur == strlen("UserID filter list:"))
+ // if strstr returned NULL and we added a strlen to it...
+ {
+ cur=NULL;
+ }
+ // listid format:
+ // UserID filter list:
+ // 1 23434 : 20.000 min
+
+ // and on empty it produces:
+ // IP filter list: empty
+
+ while(cur!=NULL)
+ {
+
+ TokenLine banLine;
+ cur++; // dodge the newline
+ banLine.SetLine(cur); // need to add one here, to remove the "\n"
+ if(banLine.CountToken() >= 4 )
+ {
+ Bans_t ban;
+
+ memset(&ban,0x0,sizeof(Bans_t));
+
+ v_strncpy(ban.name,banLine.GetToken(1),20);
+ sscanf(banLine.GetToken(3),"%f",&ban.time);
+ ban.type= ID;
+ m_BanList.AddToTail(ban);
+
+ }
+ cur=strchr(cur,'\n');
+
+ }
+
+ m_bGotIPs=true;
+
+ // now find out the list of banned ips
+ m_pRcon->SendRcon("listip");
+ }
+ else
+ {
+
+ // listip format:
+ // IP filter list:
+ //192.168. 1. 66 : 20.000 min
+
+ const char *rconResp = m_pRcon->RconResponse();
+ const char *cur = strstr(rconResp,"IP filter list:")
+ + strlen("IP filter list:");
+
+ if( (unsigned int)cur == strlen("IP filter list:"))
+ // if strstr returned NULL and we added a strlen to it...
+ {
+ cur=NULL;
+ }
+
+
+ while(cur!=NULL)
+ {
+
+ char tmpStr[512];
+ Bans_t ban;
+
+ cur++; // dodge past the newline
+ v_strncpy(tmpStr,cur,512);
+
+ memset(&ban,0x0,sizeof(Bans_t));
+
+ if( strchr(tmpStr,':') != NULL )
+ {
+ char *time;
+ time = strchr(tmpStr,':')+1;
+ tmpStr[strchr(tmpStr,':')-tmpStr]=0;
+
+ v_strncpy(ban.name,tmpStr,20);
+ unsigned int i=0;
+ while(i<strlen(ban.name)) // strip all the white space out...
+ {
+ if( ban.name[i]==' ')
+ {
+ strcpy(&ban.name[i],&ban.name[i+1]);
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ sscanf(time,"%f",&ban.time);
+ ban.type= IP;
+ m_BanList.AddToTail(ban);
+
+ }
+ cur=strchr(cur,'\n');
+
+ }
+
+ m_bNewBanList=true;
+ m_bIsRefreshing=false;
+
+
+
+
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded();
+ }
+
+}
+
+void CBanList::ServerFailedToRespond()
+{
+ m_bNewBanList=true;
+ m_bIsRefreshing=false;
+
+ if(m_bRconFailed==false)
+ {
+ m_bRconFailed=true;
+ // CDialogKickPlayer *box = new CDialogKickPlayer();
+ //box->addActionSignalTarget(this);
+ // box->Activate("","Bad Rcon Password","badrcon");
+ }
+
+// m_pResponseTarget->ServerFailedToRespond();
+}
+
+void CBanList::Refresh()
+{
+ SendQuery();
+}
+
+bool CBanList::IsRefreshing()
+{
+ return m_bIsRefreshing;
+}
+
+serveritem_t &CBanList::GetServer()
+{
+ return m_Server;
+}
+
+
+bool CBanList::NewBanList()
+{
+ return m_bNewBanList;
+}
+
+CUtlVector<Bans_t> *CBanList::GetBanList()
+{
+ m_bNewBanList=false;
+ return &m_BanList;
+}
+
+void CBanList::SetPassword(const char *newPass)
+{
+ m_pRcon->SetPassword(newPass);
+ m_bRconFailed=false;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/banlist.h b/tracker/AdminServer/banlist.h
new file mode 100644
index 0000000..a47ec52
--- /dev/null
+++ b/tracker/AdminServer/banlist.h
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef BANLIST_H
+#define BANLIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "ban.h"
+#include "netadr.h"
+#include "utlvector.h"
+#include "playermsghandler.h"
+#include "Iresponse.h"
+
+class CSocket;
+class IResponse;
+
+
+class CBanList: public IResponse
+{
+public:
+
+ CBanList(IResponse *target,serveritem_t &server, const char *rconPassword);
+ ~CBanList();
+
+ // send an rcon command to a server
+ void SendQuery();
+
+ void Refresh();
+
+ bool IsRefreshing();
+ serveritem_t &GetServer();
+ void RunFrame();
+
+ CUtlVector<Bans_t> *GetBanList();
+ bool NewBanList();
+
+ void ServerResponded();
+
+ // called when a server response has timed out
+ void ServerFailedToRespond();
+
+ void SetPassword(const char *newPass);
+
+
+private:
+
+ serveritem_t m_Server;
+ CUtlVector<Bans_t> m_BanList;
+
+ IResponse *m_pResponseTarget;
+ CRcon *m_pRcon;
+
+ bool m_bIsRefreshing;
+ bool m_bGotIPs;
+ bool m_bNewBanList;
+ bool m_bRconFailed;
+ char m_szRconPassword[100];
+
+};
+
+
+#endif // BANLIST_H \ No newline at end of file
diff --git a/tracker/AdminServer/cmdlist.cpp b/tracker/AdminServer/cmdlist.cpp
new file mode 100644
index 0000000..b1d578c
--- /dev/null
+++ b/tracker/AdminServer/cmdlist.cpp
@@ -0,0 +1,177 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: queries server for the command list, and then use QueryCommand() to see
+// if the server supports this command.
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include <ctype.h> // isspace() define
+#include <string.h>
+
+#include "CMDList.h"
+#include "Iresponse.h"
+
+#include "Socket.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+#include "inetapi.h"
+#include "TokenLine.h"
+#include "dialogkickplayer.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+typedef enum
+{
+ NONE = 0,
+ INFO_REQUESTED,
+ INFO_RECEIVED
+} RCONSTATUS;
+
+
+typedef enum
+{
+ FS,
+ PAK
+} MAP_TYPES;
+
+CCMDList::CCMDList(IResponse *target,serveritem_t &server, const char *rconPassword) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+
+ m_bGotCommands = false;
+ m_pResponseTarget=target;
+
+ v_strncpy(m_szRconPassword,rconPassword,100);
+
+ m_pRcon = new CRcon(this , server,rconPassword);
+ m_pRcon->SendRcon("cmdlist");
+ m_CMDList.RemoveAll();
+}
+
+CCMDList::~CCMDList() {
+ delete m_pRcon;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCMDList::RunFrame()
+{
+ if(m_pRcon)
+ {
+ m_pRcon->RunFrame();
+ }
+}
+
+
+void CCMDList::ServerResponded()
+{
+ char store[2048];
+ strcpy(store, m_pRcon->RconResponse());
+ char *cur=store;
+ char *next=NULL;
+ char *cmd=NULL;
+ bool cmd_end=false;
+
+// response format:
+//Command List
+//--------------
+//_unloadmodule
+// ...
+// writeip
+//--------------
+//125 Total Commands
+//CmdList ? for syntax
+
+ while(cur!=NULL)
+ {
+ if(next!=NULL)
+ {
+ cur++;
+ }
+ next=strchr(cur,'\n');
+ if(next!=NULL)
+ {
+ *next='\0';
+ }
+ if( strncmp(cur,"Command List",12) && strncmp(cur,"-------------",13)
+ && strncmp(cur,"Total Commands",14) && strncmp(cur,"CmdList ? for syntax",20) )
+ {
+ char *removeWhiteSpace=cur;
+ while(!isspace(*removeWhiteSpace) && removeWhiteSpace<next)
+ {
+ removeWhiteSpace++;
+ }
+ *removeWhiteSpace='\0';
+
+ cmd = new char[strlen(cur)];
+ if(cmd)
+ {
+ strcpy(cmd,cur);
+ m_CMDList.AddToTail(cmd);
+ }
+ }
+ else if ( ! strncmp(cur,"CmdList ? for syntax",20))
+ {
+ cmd_end=true;
+ }
+ cur=next;
+ }
+
+ if( cmd_end )
+ {
+ m_bGotCommands = true;
+ m_pResponseTarget->ServerResponded();
+
+ }
+
+}
+
+void CCMDList::ServerFailedToRespond()
+{
+ //m_pResponseTarget->ServerFailedToRespond();
+}
+
+
+serveritem_t &CCMDList::GetServer()
+{
+ return m_Server;
+}
+
+
+bool CCMDList::QueryCommand(char *cmd)
+{
+ if(!m_bGotCommands)
+ return false;
+
+
+ for(int i=0;i<m_CMDList.Count();i++)
+ {
+ char *cmd_in = m_CMDList[i];
+ if(!stricmp(cmd,m_CMDList[i]))
+ break;
+ }
+ if(i!=m_CMDList.Count())
+ {
+ return true;
+ }
+ else
+ return false;
+
+}
+
+bool CCMDList::GotCommands()
+{
+ return m_bGotCommands;
+}
+
+void CCMDList::SetPassword(const char *newPass)
+{
+ m_pRcon->SetPassword(newPass);
+ m_bGotCommands = false;
+ m_CMDList.RemoveAll();
+
+ m_pRcon->SendRcon("cmdlist");
+} \ No newline at end of file
diff --git a/tracker/AdminServer/cmdlist.h b/tracker/AdminServer/cmdlist.h
new file mode 100644
index 0000000..1566e7d
--- /dev/null
+++ b/tracker/AdminServer/cmdlist.h
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef CMDLIST_H
+#define CMDLIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+#include "maps.h"
+#include "rcon.h"
+#include "utlvector.h"
+#include "Iresponse.h"
+
+class CSocket;
+class IResponse;
+
+class CCMDList: public IResponse
+{
+public:
+
+ CCMDList(IResponse *target,serveritem_t &server, const char *rconPassword);
+ ~CCMDList();
+
+ serveritem_t &GetServer();
+ void RunFrame();
+ bool QueryCommand(char *cmd);
+ bool GotCommands();
+
+ void SetPassword(const char *newPass);
+
+ virtual void ServerResponded();
+ virtual void ServerFailedToRespond();
+
+
+private:
+
+ serveritem_t m_Server;
+ CUtlVector<char *> m_CMDList;
+ IResponse *m_pResponseTarget;
+
+ CRcon *m_pRcon;
+
+ bool m_bGotCommands;
+ char m_szRconPassword[100];
+
+};
+
+
+#endif // CMDLIST_H \ No newline at end of file
diff --git a/tracker/AdminServer/logmsghandler.cpp b/tracker/AdminServer/logmsghandler.cpp
new file mode 100644
index 0000000..62de869
--- /dev/null
+++ b/tracker/AdminServer/logmsghandler.cpp
@@ -0,0 +1,66 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "LogMsgHandler.h"
+
+#include "info.h"
+#include "proto_oob.h"
+
+#include "inetapi.h"
+#include "DialogGameInfo.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CLogMsgHandlerDetails::CLogMsgHandlerDetails(IResponse *baseobject, HANDLERTYPE type, void *typeinfo )
+ : CMsgHandler( type, typeinfo )
+{
+ m_pLogList = baseobject;
+ m_bNewMessage=false;
+}
+
+CLogMsgHandlerDetails::~CLogMsgHandlerDetails()
+{
+}
+
+
+//-------------------------------------------------------------------------
+// Purpose: Process cracked message
+//-----------------------------------------------------------------------------
+bool CLogMsgHandlerDetails::Process( netadr_t *from, CMsgBuffer *msg )
+{
+
+ m_bNewMessage=true;
+ v_strncpy(message,msg->ReadString(),512);
+ message[strlen(message)-1]='\n';
+ message[strlen(message)]='\0';
+
+ // now tell the UI we have this new message
+ m_pLogList->ServerResponded();
+
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// Purpose: returns if a new message is waiting
+//-----------------------------------------------------------------------------
+bool CLogMsgHandlerDetails::NewMessage()
+{
+ bool val=m_bNewMessage;
+ m_bNewMessage=false;
+ return val;
+}
+
+//-------------------------------------------------------------------------
+// Purpose: returns the text contained in the last message recieved
+//-----------------------------------------------------------------------------
+const char *CLogMsgHandlerDetails::GetBuf()
+{
+ return message;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/logmsghandler.h b/tracker/AdminServer/logmsghandler.h
new file mode 100644
index 0000000..a7b1761
--- /dev/null
+++ b/tracker/AdminServer/logmsghandler.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef LOGMSGHANDLER_H
+#define LOGMSGHANDLER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "Socket.h"
+#include "utlvector.h"
+#include "player.h"
+#include "rcon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Socket handler for pinging internet servers
+//-----------------------------------------------------------------------------
+class CLogMsgHandlerDetails : public CMsgHandler
+{
+public:
+ CLogMsgHandlerDetails(IResponse *baseobject, HANDLERTYPE type, void *typeinfo = NULL);
+ ~CLogMsgHandlerDetails();
+
+ virtual bool Process(netadr_t *from, CMsgBuffer *msg);
+
+ // indicates if a new message has arrived
+ bool NewMessage();
+
+ // returns the text of the last message recieved
+ const char *GetBuf();
+
+
+private:
+
+ IResponse *m_pLogList;
+ bool m_bNewMessage;
+ char message[512];
+};
+
+#endif // LOGMSGHANDLER_H
diff --git a/tracker/AdminServer/maps.h b/tracker/AdminServer/maps.h
new file mode 100644
index 0000000..2fc87f5
--- /dev/null
+++ b/tracker/AdminServer/maps.h
@@ -0,0 +1,26 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef MAPS_H
+#define MAPS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Data describing a single map
+//-----------------------------------------------------------------------------
+typedef struct
+{
+
+ char name[100];
+ int type;
+} Maps_t;
+
+
+#endif // MAPS_H
diff --git a/tracker/AdminServer/mapslist.cpp b/tracker/AdminServer/mapslist.cpp
new file mode 100644
index 0000000..0681a65
--- /dev/null
+++ b/tracker/AdminServer/mapslist.cpp
@@ -0,0 +1,230 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "mapslist.h"
+#include "Iresponse.h"
+
+#include "Socket.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+#include "inetapi.h"
+#include "TokenLine.h"
+#include "dialogkickplayer.h"
+#include <string.h>
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+typedef enum
+{
+ NONE = 0,
+ INFO_REQUESTED,
+ INFO_RECEIVED
+} RCONSTATUS;
+
+
+typedef enum
+{
+ FS,
+ PAK
+} MAP_TYPES;
+
+CMapsList::CMapsList(IResponse *target,serveritem_t &server, const char *rconPassword,const char *mod) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+ m_pResponseTarget=target;
+
+ if(strcmp(mod,"valve") )
+ {
+ v_strncpy(m_sMod,mod,64);
+ }
+ else
+ {
+ m_sMod[0]=0; // its the "valve" default mod, list all maps
+ }
+
+ m_bIsRefreshing=false;
+ m_bNewMapsList=false;
+ m_bRconFailed=false;
+
+ v_strncpy(m_szRconPassword,rconPassword,100);
+
+ m_pRcon = new CRcon(this , server,rconPassword);
+}
+
+CMapsList::~CMapsList() {
+ delete m_pRcon;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a status query packet to a single server
+//-----------------------------------------------------------------------------
+void CMapsList::SendQuery()
+{
+ m_bIsRefreshing=true;
+ m_pRcon->SendRcon("maps *");
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMapsList::RunFrame()
+{
+ if(m_pRcon)
+ {
+ m_pRcon->RunFrame();
+ }
+}
+
+
+void CMapsList::ServerResponded()
+{
+ char store[2048];
+ strcpy(store, m_pRcon->RconResponse());
+ char *cur=store;
+ char *next=NULL;
+ int i=0,k=0;
+ bool checkDir=false;
+
+// maps format:
+// Dir: valve
+//-------------
+//(fs) rapidcore.bsp
+//(fs) frenzy.bsp
+//(fs) crossfire.bsp
+//
+//Dir: valve
+//-------------
+//(pak) boot_camp.bsp
+//(pak) bounce.bsp
+
+ m_MapsList.RemoveAll();
+
+ char check[21];
+ _snprintf(check,21,"%s/",m_sMod);
+ if(strstr(store,check))
+ { // if the name of the mod dir is in the return list its old style format
+ checkDir=true;
+ }
+
+
+ while(cur!=NULL)
+ {
+ cur++;
+ next=strchr(cur,'\n');
+ if(next!=NULL)
+ {
+ *next='\0';
+ }
+
+ if( strncmp(cur,"Dir:",4) && strncmp(cur,"-------------",13) )
+ {
+ TokenLine mapsLine;
+ mapsLine.SetLine(cur);
+
+ if(mapsLine.CountToken() >= 2 )
+ {
+ char tmpMap[100];
+ v_strncpy(tmpMap,mapsLine.GetToken(1),100); // type
+ char *end = strstr(tmpMap,".bsp"); // cull the .bsp
+ if(end != NULL)
+ {
+ *end='\0';
+ }
+ if(checkDir==true && strstr(tmpMap,m_sMod)==NULL )
+ // if the map name doesn't have the mod dir in it
+ // and its not running the "valve" mod continue
+ {
+ cur=next;
+ continue;
+ }
+
+ if ( strchr(tmpMap,'/') ) // remove the directory part of the map name
+ {
+ strcpy(tmpMap,strrchr(tmpMap,'/')+1);
+ }
+
+ for(k=0;k<m_MapsList.Count();k++) // now check it doesn't already exist inside the map list...
+ {
+ if(!strncmp(tmpMap,m_MapsList[k].name,strlen(tmpMap)) )
+ {
+ break;
+ }
+ }
+ if(k==m_MapsList.Count() // the map wasn't found
+ && !(tmpMap[0]=='c' && (tmpMap[1]>='1' && tmpMap[1]<='5')) // a heuristic to remove single player maps
+ && !(tmpMap[0]=='t' && tmpMap[1]=='0') ) // from the list
+ {
+ Maps_t map;
+ // this map wasn't found already
+ v_strncpy(map.name,tmpMap,strlen(tmpMap)+1);
+ if( !strcmp("(fs)",mapsLine.GetToken(0)) )
+ { // name
+ map.type=FS;
+ }
+ else
+ {
+ map.type=PAK;
+ }
+ m_MapsList.AddToTail(map);
+ i++;
+ } // if k == Count
+
+ } // CountToken
+ } // if not a Dir: or "----------"
+ cur=next;
+ }
+
+ m_bNewMapsList=true;
+ m_bIsRefreshing=false;
+
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded();
+
+}
+
+void CMapsList::ServerFailedToRespond()
+{
+ // rcon failed
+ //m_pResponseTarget->ServerFailedToRespond();
+}
+
+void CMapsList::Refresh()
+{
+ SendQuery();
+}
+
+bool CMapsList::IsRefreshing()
+{
+
+ return m_bIsRefreshing;
+}
+
+serveritem_t &CMapsList::GetServer()
+{
+ return m_Server;
+}
+
+
+bool CMapsList::NewMapsList()
+{
+ return m_bNewMapsList;
+}
+
+CUtlVector<Maps_t> *CMapsList::GetMapsList()
+{
+ m_bNewMapsList=false;
+ return &m_MapsList;
+}
+
+void CMapsList::SetPassword(const char *newPass)
+{
+ m_pRcon->SetPassword(newPass);
+ m_bRconFailed=false;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/mapslist.h b/tracker/AdminServer/mapslist.h
new file mode 100644
index 0000000..511fe23
--- /dev/null
+++ b/tracker/AdminServer/mapslist.h
@@ -0,0 +1,70 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef MAPSLIST_H
+#define MAPSLIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+#include "maps.h"
+#include "rcon.h"
+#include "utlvector.h"
+#include "Iresponse.h"
+
+class CSocket;
+class IResponse;
+
+
+class CMapsList: public IResponse
+{
+public:
+
+ CMapsList(IResponse *target,serveritem_t &server, const char *rconPassword,const char *mod);
+ ~CMapsList();
+
+ // send an rcon command to a server
+ void SendQuery();
+
+ void Refresh();
+
+ bool IsRefreshing();
+ serveritem_t &GetServer();
+ void RunFrame();
+
+ void UpdateServer();
+ CUtlVector<Maps_t> *GetMapsList();
+ bool NewMapsList();
+
+ void ServerResponded();
+
+ // called when a server response has timed out
+ void ServerFailedToRespond();
+
+ void SetPassword(const char *newPass);
+
+
+private:
+
+ serveritem_t m_Server;
+ CUtlVector<Maps_t> m_MapsList;
+
+ IResponse *m_pResponseTarget;
+ CRcon *m_pRcon;
+ char m_sMod[64];
+
+ bool m_bIsRefreshing;
+ bool m_bNewMapsList;
+ bool m_bRconFailed;
+ char m_szRconPassword[100];
+
+};
+
+
+#endif // MAPSLIST_H \ No newline at end of file
diff --git a/tracker/AdminServer/playerlist.cpp b/tracker/AdminServer/playerlist.cpp
new file mode 100644
index 0000000..f710c2a
--- /dev/null
+++ b/tracker/AdminServer/playerlist.cpp
@@ -0,0 +1,227 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "playerlist.h"
+#include "Iresponse.h"
+
+#include "PlayerMsgHandler.h"
+#include "Socket.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+#include "inetapi.h"
+#include "TokenLine.h"
+#include "dialogkickplayer.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+typedef enum
+{
+ NONE = 0,
+ INFO_REQUESTED,
+ INFO_RECEIVED
+} RCONSTATUS;
+
+CPlayerList::CPlayerList(IResponse *target,serveritem_t &server, const char *rconPassword) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+ m_pResponseTarget=target;
+
+ m_bIsRefreshing=false;
+ m_bNewPlayerList=false;
+ m_bRconFailed=false;
+
+ v_strncpy(m_szRconPassword,rconPassword,100);
+
+ m_pRcon = new CRcon(this , server,rconPassword);
+ m_PlayerList=NULL;
+ m_pPlayerInfoMsg=NULL;
+
+ m_pQuery = new CSocket("internet player query", -1);
+
+}
+
+CPlayerList::~CPlayerList() {
+ delete m_pQuery;
+ delete m_pRcon;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a status query packet to a single server
+//-----------------------------------------------------------------------------
+void CPlayerList::SendQuery()
+{
+ CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
+ assert( buffer );
+
+ if ( !buffer )
+ {
+ return;
+ }
+
+ int bytecode = S2A_PLAYER;
+ if ( m_pPlayerInfoMsg != NULL )
+ {
+ delete m_pPlayerInfoMsg;
+ }
+ m_pPlayerInfoMsg=new CPlayerMsgHandlerDetails(this, &m_PlayerList,CMsgHandler::MSGHANDLER_ALL, &bytecode);
+ m_pQuery->AddMessageHandler(m_pPlayerInfoMsg);
+
+ m_bIsRefreshing=true;
+
+ netadr_t adr;
+
+ adr.ip[0] = m_Server.ip[0];
+ adr.ip[1] = m_Server.ip[1];
+ adr.ip[2] = m_Server.ip[2];
+ adr.ip[3] = m_Server.ip[3];
+ adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+
+ // Set state
+ m_Server.received = (int)INFO_REQUESTED;
+
+ // Create query message
+ buffer->Clear();
+ // Write control sequence
+ buffer->WriteLong(0xffffffff);
+
+ // Write query string
+ buffer->WriteString("players");
+
+ // Sendmessage
+ m_pQuery->SendMessage( &adr );
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPlayerList::RunFrame()
+{
+ if (m_pQuery && m_bIsRefreshing)
+ {
+ m_pQuery->Frame();
+ }
+ if(m_pRcon)
+ {
+ m_pRcon->RunFrame();
+ }
+
+}
+
+
+void CPlayerList::ServerResponded()
+{
+ const char *rconResp = m_pRcon->RconResponse();
+ const char *cur = strstr(rconResp,"name userid uniqueid frag time ping loss adr\n")
+ + strlen("name userid uniqueid frag time ping loss adr\n");
+
+// status format:
+// # name userid uniqueid frag time ping loss adr
+// # 1 "Player" 1 4294967295 0 30:56 22 0 192.168.3.64:27005
+
+
+ for(int i=0;i<m_PlayerList.Count();i++)
+ {
+ if(cur!=NULL)
+ {
+ TokenLine playerLine;
+ playerLine.SetLine(cur);
+
+ if(playerLine.CountToken() >= 9 )
+ {
+ // playerLine.GetToken(1); // count
+ // playerLine.GetToken(2); // player name
+ // char *player= playerLine.GetToken(2);
+
+ m_PlayerList[i].userid=atoi(playerLine.GetToken(3)); // userid
+ v_strncpy(m_PlayerList[i].authid,playerLine.GetToken(4),20); // authid
+ //playerLine.GetToken(5); // frag
+ // playerLine.GetToken(6); // time
+ m_PlayerList[i].ping=atoi(playerLine.GetToken(7)); //ping
+ m_PlayerList[i].loss=atoi(playerLine.GetToken(8)); // loss
+ // playerLine.GetToken(9); // adr
+ }
+ cur=strchr(cur,'\n')+1;
+
+ }
+ }
+
+ m_bNewPlayerList=true;
+ m_bIsRefreshing=false;
+
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded();
+
+}
+
+void CPlayerList::ServerFailedToRespond()
+{
+ m_bNewPlayerList=true;
+ m_bIsRefreshing=false;
+
+ if(m_bRconFailed==false)
+ {
+ m_bRconFailed=true;
+ // CDialogKickPlayer *box = new CDialogKickPlayer();
+ //box->addActionSignalTarget(this);
+ // box->Activate("","Bad Rcon Password","badrcon");
+ }
+
+ // rcon failed BUT we still have some valid data :)
+ m_pResponseTarget->ServerResponded();
+}
+
+
+void CPlayerList::UpdateServer()
+{
+
+ m_pQuery->RemoveMessageHandler(m_pPlayerInfoMsg);
+ // you CANNOT delete this handler because we are inside of it at the moment... (yes, this was an ugly bug)
+ // delete m_pPlayerInfoMsg;
+
+ // now use "rcon status" to pull extra info about the players
+ m_pRcon->SendRcon("status");
+
+}
+
+void CPlayerList::Refresh()
+{
+ SendQuery();
+}
+
+bool CPlayerList::IsRefreshing()
+{
+
+ return m_bIsRefreshing;
+}
+
+serveritem_t &CPlayerList::GetServer()
+{
+ return m_Server;
+}
+
+
+bool CPlayerList::NewPlayerList()
+{
+ return m_bNewPlayerList;
+}
+
+CUtlVector<Players_t> *CPlayerList::GetPlayerList()
+{
+ m_bNewPlayerList=false;
+ return &m_PlayerList;
+}
+
+void CPlayerList::SetPassword(const char *newPass)
+{
+ m_pRcon->SetPassword(newPass);
+ m_bRconFailed=false;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/playerlist.h b/tracker/AdminServer/playerlist.h
new file mode 100644
index 0000000..473ea6a
--- /dev/null
+++ b/tracker/AdminServer/playerlist.h
@@ -0,0 +1,70 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef PLAYERLIST_H
+#define PLAYERLIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+#include "utlvector.h"
+#include "playermsghandler.h"
+#include "Iresponse.h"
+
+class CSocket;
+class IResponse;
+
+
+class CPlayerList: public IResponse
+{
+public:
+
+ CPlayerList(IResponse *target,serveritem_t &server, const char *rconPassword);
+ ~CPlayerList();
+
+ // send an rcon command to a server
+ void SendQuery();
+
+ void Refresh();
+
+ bool IsRefreshing();
+ serveritem_t &GetServer();
+ void RunFrame();
+
+ void UpdateServer();
+ CUtlVector<Players_t> *GetPlayerList();
+ bool NewPlayerList();
+
+ void ServerResponded();
+
+ // called when a server response has timed out
+ void ServerFailedToRespond();
+
+ void SetPassword(const char *newPass);
+
+
+private:
+
+ serveritem_t m_Server;
+ CSocket *m_pQuery; // Game server query socket
+ CUtlVector<Players_t> m_PlayerList;
+
+ IResponse *m_pResponseTarget;
+ CRcon *m_pRcon;
+ CPlayerMsgHandlerDetails *m_pPlayerInfoMsg;
+
+ bool m_bIsRefreshing;
+ bool m_bNewPlayerList;
+ bool m_bRconFailed;
+ char m_szRconPassword[100];
+
+};
+
+
+#endif // PLAYERLIST_H \ No newline at end of file
diff --git a/tracker/AdminServer/playermsghandler.cpp b/tracker/AdminServer/playermsghandler.cpp
new file mode 100644
index 0000000..b77ca41
--- /dev/null
+++ b/tracker/AdminServer/playermsghandler.cpp
@@ -0,0 +1,93 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "PlayerMsgHandler.h"
+
+#include "playerlist.h"
+#include "info.h"
+#include "proto_oob.h"
+
+#include "inetapi.h"
+#include "DialogGameInfo.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CPlayerMsgHandlerDetails::CPlayerMsgHandlerDetails( CPlayerList *baseobject, CUtlVector<Players_t> *players,HANDLERTYPE type, void *typeinfo /*= NULL*/ )
+ : CMsgHandler( type, typeinfo )
+{
+ m_pPlayerList = baseobject;
+ m_pPlayerNames=players;
+}
+
+CPlayerMsgHandlerDetails::~CPlayerMsgHandlerDetails()
+{
+// delete m_pPlayerNames;
+}
+
+
+//-------------------------------------------------------------------------
+// Purpose: Process cracked message
+//-----------------------------------------------------------------------------
+bool CPlayerMsgHandlerDetails::Process( netadr_t *from, CMsgBuffer *msg )
+{
+
+ m_pPlayerNames->RemoveAll();
+ m_pPlayerNames->Purge();
+
+
+ // Check type of data.
+ if (msg->ReadByte() != S2A_PLAYER)
+ return false;
+
+ int pNumber;
+ pNumber = msg->ReadByte();
+
+
+ if (pNumber <= 0 || pNumber > 32) // you still need to update the player vector if this happens, the server could be empty
+ {
+ m_pPlayerList->UpdateServer();
+ return false;
+ }
+
+ // Read the data
+ for (int i = 0; i < pNumber; i++)
+ {
+ Players_t player;
+
+ memset(&player,0x0,sizeof(Players_t));
+ player.userid = msg->ReadByte();
+ v_strncpy(player.name ,msg->ReadString(),100);
+ player.frags = msg->ReadLong();
+ player.time = msg->ReadFloat();
+
+ m_pPlayerNames->AddToTail(player);
+ }
+
+
+/* serveritem_t server;
+ memset(&server, 0, sizeof(server));
+ netadr_t netaddr;
+ if (net->StringToAdr("192.168.1.66", &netaddr))
+ {
+ memcpy(server.ip,netaddr.ip,4);
+ }
+
+ server.port = 27015;
+
+ CDialogGameInfo *gameDialog = new CDialogGameInfo(NULL, 0,*((int *)server.ip),pNumber);
+ gameDialog->Run("Stuff");
+*/
+
+ m_pPlayerList->UpdateServer();
+
+ return true;
+}
+
+
diff --git a/tracker/AdminServer/playermsghandler.h b/tracker/AdminServer/playermsghandler.h
new file mode 100644
index 0000000..b0b963b
--- /dev/null
+++ b/tracker/AdminServer/playermsghandler.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef PLAYERMSGHANDLER_H
+#define PLAYERMSGHANDLER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "Socket.h"
+#include "utlvector.h"
+#include "player.h"
+#include "rcon.h"
+
+class CPlayerList;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Socket handler for pinging internet servers
+//-----------------------------------------------------------------------------
+class CPlayerMsgHandlerDetails : public CMsgHandler
+{
+public:
+ CPlayerMsgHandlerDetails(CPlayerList *baseobject, CUtlVector<Players_t> *players,HANDLERTYPE type, void *typeinfo = NULL);
+ ~CPlayerMsgHandlerDetails();
+
+ virtual bool Process(netadr_t *from, CMsgBuffer *msg);
+
+
+private:
+ // the parent class that we push info back to
+ CPlayerList *m_pPlayerList;
+ CUtlVector<Players_t> *m_pPlayerNames;
+
+};
+
+#endif // PLAYERMSGHANDLER_H
diff --git a/tracker/AdminServer/point.h b/tracker/AdminServer/point.h
new file mode 100644
index 0000000..968c63e
--- /dev/null
+++ b/tracker/AdminServer/point.h
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef POINT_H
+#define POINT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Data describing a point used on the graph, dervied from the "stats" rcon command
+//-----------------------------------------------------------------------------
+
+typedef struct {
+ float cpu; // the percent CPU usage
+ float in; // the ingoing bandwidth in kB/sec
+ float out; // the outgoing bandwidth in kB/sec
+ float time; // the time this was recorded
+ float fps; // the FPS of the server
+ float ping; // the ping of the server
+} Points_t;
+
+
+#endif // POINT_H
diff --git a/tracker/AdminServer/rcon.cpp b/tracker/AdminServer/rcon.cpp
new file mode 100644
index 0000000..6cd31e7
--- /dev/null
+++ b/tracker/AdminServer/rcon.cpp
@@ -0,0 +1,343 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "rcon.h"
+#include "Iresponse.h"
+
+#include "RconMsgHandler.h"
+#include "Socket.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+#include "inetapi.h"
+#include "dialogkickplayer.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+typedef enum
+{
+ NONE = 0,
+ INFO_REQUESTED,
+ INFO_RECEIVED
+} RCONSTATUS;
+
+
+CRcon::CRcon(IResponse *target,serveritem_t &server,const char *password) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+ m_pResponseTarget=target;
+
+ m_bIsRefreshing = false;
+ m_bChallenge = false;
+ m_bNewRcon = false;
+ m_bPasswordFail = false;
+ m_bDisable = false;
+ m_bGotChallenge = false;
+ m_iChallenge = 0;
+ m_fQuerySendTime= 0;
+
+ v_strncpy(m_sPassword,password,100);
+
+ int bytecode = S2A_INFO_DETAILED;
+ m_pQuery = new CSocket("internet rcon query", -1);
+ m_pQuery->AddMessageHandler(new CRconMsgHandlerDetails(this, CMsgHandler::MSGHANDLER_ALL, &bytecode));
+}
+
+CRcon::~CRcon() {
+ delete m_pQuery;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: resets the state of the rcon object back to startup conditions (i.e get challenge again)
+//-----------------------------------------------------------------------------
+void CRcon::Reset()
+{
+ m_bIsRefreshing = false;
+ m_bChallenge = false;
+ m_bNewRcon = false;
+ m_bPasswordFail = false;
+ m_bDisable = false;
+ m_bGotChallenge = false;
+ m_iChallenge = 0;
+ m_fQuerySendTime= 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a challenge request to the server if we have yet to get one,
+// else it sends the rcon itself
+//-----------------------------------------------------------------------------
+void CRcon::SendRcon(const char *command)
+{
+
+ if(m_bDisable==true) // rcon is disabled because it has failed.
+ {
+ m_pResponseTarget->ServerFailedToRespond();
+ return;
+ }
+
+ if(m_bIsRefreshing)
+ { // we are already processing a request, lets queue this
+ queue_requests_t queue;
+ strncpy(queue.queued,command,1024);
+
+ if(requests.Count()>10) // to many request already...
+ return;
+
+ requests.AddToTail(queue);
+ return;
+ }
+
+ m_bIsRefreshing=true;
+ m_bPasswordFail=false;
+
+ if(m_bGotChallenge==false) // haven't got the challenge id yet
+ {
+ GetChallenge();
+ v_strncpy(m_sCmd,command,1024); // store away the command for later :)
+ m_bChallenge=true; // note that we are requesting a challenge and need to still run this command
+ }
+ else
+ {
+ RconRequest(command,m_iChallenge);
+ }
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: runs a frame of the net handler
+//-----------------------------------------------------------------------------
+void CRcon::RunFrame()
+{
+ // only the "ping" command has a timeout
+/* float curtime = CSocket::GetClock();
+ if(m_fQuerySendTime!=0 && (curtime-m_fQuerySendTime)> 10.0f) // 10 seconds
+ {
+ m_fQuerySendTime= 0;
+ m_pResponseTarget->ServerFailedToRespond();
+ }
+ */
+
+ if (m_pQuery)
+ {
+ m_pQuery->Frame();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: emits a challenge request
+//-----------------------------------------------------------------------------
+void CRcon::GetChallenge()
+{
+ CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
+ assert( buffer );
+
+ if ( !buffer )
+ {
+ return;
+ }
+ netadr_t adr;
+ adr.ip[0] = m_Server.ip[0];
+ adr.ip[1] = m_Server.ip[1];
+ adr.ip[2] = m_Server.ip[2];
+ adr.ip[3] = m_Server.ip[3];
+ adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+ // Set state
+ m_Server.received = (int)INFO_REQUESTED;
+ // Create query message
+ buffer->Clear();
+ // Write control sequence
+ buffer->WriteLong(0xffffffff);
+ // Write query string
+ buffer->WriteString("challenge rcon");
+ // Sendmessage
+ m_pQuery->SendMessage( &adr );
+
+ // set the clock for this send
+ m_fQuerySendTime = CSocket::GetClock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: emits a valid rcon request, the challenge id has already been found
+//-----------------------------------------------------------------------------
+void CRcon::RconRequest(const char *command, int challenge)
+{
+ CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
+ assert( buffer );
+
+ if ( !buffer )
+ {
+ return;
+ }
+
+ netadr_t adr;
+ adr.ip[0] = m_Server.ip[0];
+ adr.ip[1] = m_Server.ip[1];
+ adr.ip[2] = m_Server.ip[2];
+ adr.ip[3] = m_Server.ip[3];
+ adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+
+ // Set state
+ m_Server.received = (int)INFO_REQUESTED;
+ // Create query message
+ buffer->Clear();
+ // Write control sequence
+ buffer->WriteLong(0xffffffff);
+
+ // Write query string
+ char rcon_cmd[600];
+ _snprintf(rcon_cmd,600,"rcon %u \"%s\" %s",challenge,m_sPassword,command);
+
+ buffer->WriteString(rcon_cmd);
+ // Sendmessage
+ m_pQuery->SendMessage( &adr );
+ // set the clock for this send
+ m_fQuerySendTime = CSocket::GetClock();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when an rcon responds
+//-----------------------------------------------------------------------------
+void CRcon::UpdateServer(netadr_t *adr, int challenge, const char *resp)
+{
+
+ m_fQuerySendTime= 0;
+ if(m_bChallenge==true) // now send the RCON request itself
+ {
+ m_bChallenge=false; // m_bChallenge is set to say we just requested the challenge value
+ m_iChallenge=challenge;
+ m_bGotChallenge=true;
+ RconRequest(m_sCmd,m_iChallenge);
+ }
+ else // this is the result of the RCON request
+ {
+ m_bNewRcon=true;
+ v_strncpy(m_sRconResponse,resp,2048);
+ m_bIsRefreshing=false;
+
+ // this must be before the SeverResponded() :)
+ if(requests.Count()>0)
+ { // we have queued requests
+ SendRcon(requests[0].queued);
+ requests.Remove(0); // now delete this element
+ }
+
+
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded();
+
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: run when a refresh is asked for
+//-----------------------------------------------------------------------------
+void CRcon::Refresh()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns if a rcon is currently being performed
+//-----------------------------------------------------------------------------
+bool CRcon::IsRefreshing()
+{
+
+ return m_bIsRefreshing;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: the server to which this rcon class is bound
+//-----------------------------------------------------------------------------
+serveritem_t &CRcon::GetServer()
+{
+ return m_Server;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: the challenge id used in rcons
+//-----------------------------------------------------------------------------
+bool CRcon::Challenge()
+{
+ return m_bChallenge;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns if a new rcon result is available
+//-----------------------------------------------------------------------------
+bool CRcon::NewRcon()
+{
+ bool val = m_bNewRcon;
+ m_bNewRcon=false;
+
+ return val;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the response of the last rcon
+//-----------------------------------------------------------------------------
+const char *CRcon::RconResponse()
+{
+ return (const char *)m_sRconResponse;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the wrong password is used, when a ServerFailed is called
+//-----------------------------------------------------------------------------
+bool CRcon::PasswordFail()
+{
+ bool val=m_bPasswordFail;
+ m_bPasswordFail=false;
+ return val;
+ //m_pResponseTarget->ServerFailedToRespond();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called by the rcon message handler to denote a bad password
+//-----------------------------------------------------------------------------
+void CRcon::BadPassword(const char *info)
+{
+ strncpy(m_sRconResponse,info,100);
+ m_bPasswordFail=true;
+ m_bDisable=true;
+ m_fQuerySendTime= 0;
+
+ m_bIsRefreshing=false;
+
+/* // this must be before the ServerFailedToRespond() :)
+ if(requests.Count()>0)
+ { // we have queued requests
+ SendRcon(requests[0].queued);
+ requests.Remove(0); // now delete this element
+ }
+*/
+
+ m_pResponseTarget->ServerFailedToRespond();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: return whether rcon has been disabled (due to bad passwords)
+//-----------------------------------------------------------------------------
+bool CRcon::Disabled()
+{
+ return m_bDisable;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the password to use for rcons
+//-----------------------------------------------------------------------------
+void CRcon::SetPassword(const char *newPass)
+{
+ strncpy(m_sPassword,newPass,100);
+ m_bDisable=false; // new password, so we can try again
+}
+
diff --git a/tracker/AdminServer/rcon.h b/tracker/AdminServer/rcon.h
new file mode 100644
index 0000000..9e9fe6e
--- /dev/null
+++ b/tracker/AdminServer/rcon.h
@@ -0,0 +1,100 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef RCON_H
+#define RCON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+
+class CSocket;
+class IResponse;
+
+typedef struct
+{
+ char queued[1024];
+} queue_requests_t;
+
+
+class CRcon
+{
+
+public:
+
+ CRcon(IResponse *target,serveritem_t &server, const char *password);
+ ~CRcon();
+
+ // resets the state of the object, will cause it to get the challenge id again
+ void Reset();
+
+ // send an rcon command to a server
+ void SendRcon(const char *cmd);
+
+ // does nothing
+ void Refresh();
+
+ bool IsRefreshing();
+ serveritem_t &GetServer();
+ void RunFrame();
+
+ // return the response from the server
+ const char *RconResponse();
+
+ // called when the message handler gets a packet back
+ void UpdateServer(netadr_t *adr, int challenge,const char *resp);
+
+ // returns the challenge id
+ bool Challenge();
+
+ // returns if a new rcon result is waiting
+ bool NewRcon();
+
+ // returns if the password failed
+ bool PasswordFail();
+
+ // called when a bad password is used
+ void BadPassword(const char *info);
+
+ // returns whether this rcon is disabled (due to bad passwords)
+ bool Disabled();
+
+ //set the password to use in the rcon request
+ void SetPassword(const char *newPass);
+
+private:
+
+ // sends the actual request
+ void RconRequest(const char *command, int challenge);
+ // requests a challenge value from the server
+ void GetChallenge();
+
+ serveritem_t m_Server;
+ CSocket *m_pQuery; // Game server query socket
+
+ IResponse *m_pResponseTarget;
+
+ bool m_bIsRefreshing; // whether we are currently performing an rcon command
+ bool m_bChallenge; // whether we are currently GETTING a challenge id
+ bool m_bNewRcon; // whether an rcon response is waiting to be picked up
+ bool m_bPasswordFail; // whether the password failed
+ bool m_bDisable; // whether rcon is disabled due to password failures
+ bool m_bGotChallenge; // whether we have a valid challenge id stored away
+
+ CUtlVector<queue_requests_t> requests;
+
+ char m_sPassword[100];
+ char m_sCmd[1024];
+ char m_sRconResponse[2048];
+ int m_iChallenge;
+ float m_fQuerySendTime;
+};
+
+
+#endif // RCON_H \ No newline at end of file
diff --git a/tracker/AdminServer/rconmsghandler.cpp b/tracker/AdminServer/rconmsghandler.cpp
new file mode 100644
index 0000000..d898838
--- /dev/null
+++ b/tracker/AdminServer/rconmsghandler.cpp
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "RconMsgHandler.h"
+
+#include "rcon.h"
+#include "info.h"
+
+#include "DialogGameInfo.h"
+#include "inetapi.h"
+#include "proto_oob.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CRconMsgHandlerDetails::CRconMsgHandlerDetails( CRcon *baseobject, HANDLERTYPE type, void *typeinfo /*= NULL*/ )
+ : CMsgHandler( type, typeinfo )
+{
+ m_pRcon = baseobject;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Process cracked message
+//-----------------------------------------------------------------------------
+bool CRconMsgHandlerDetails::Process( netadr_t *from, CMsgBuffer *msg )
+{
+ // Skip the control character
+ //if (!m_pRcon->Challenge() && msg->ReadByte()!=A2C_PRINT)
+ // return false;
+
+ // get response name
+ const char *str = msg->ReadString();
+ if ( !str || !str[0] )
+ return false;
+
+ char info[ 2048 ];
+ v_strncpy( info, str, 2047 );
+ info[2047] = 0;
+
+ if(!_strnicmp(info,"lBad rcon_password",18) )
+ {
+ m_pRcon->BadPassword(info+1);
+ return true;
+ }
+
+
+ if(m_pRcon->Challenge() )
+ { // if we know the challenge value pass it to UpdateServer
+
+ int challenge = atoi(info+strlen("challenge rcon"));
+ m_pRcon->UpdateServer(from, challenge, NULL);
+ }
+ else // else pass a default value
+ {
+ m_pRcon->UpdateServer(from, -1, info+1 );
+ }
+
+ return true;
+}
+
+
diff --git a/tracker/AdminServer/rconmsghandler.h b/tracker/AdminServer/rconmsghandler.h
new file mode 100644
index 0000000..0d5efb7
--- /dev/null
+++ b/tracker/AdminServer/rconmsghandler.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef RCONMSGHANDLERDETAILS_H
+#define RCONMSGHANDLERDETAILS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "Socket.h"
+
+class CRcon;
+
+//-----------------------------------------------------------------------------
+// Purpose: Socket handler for pinging internet servers
+//-----------------------------------------------------------------------------
+class CRconMsgHandlerDetails : public CMsgHandler
+{
+public:
+ CRconMsgHandlerDetails(CRcon *baseobject, HANDLERTYPE type, void *typeinfo = NULL);
+
+ virtual bool Process(netadr_t *from, CMsgBuffer *msg);
+
+private:
+ // the parent class that we push info back to
+ CRcon *m_pRcon;
+};
+
+
+
+
+#endif // RCONMSGHANDLERDETAILS_H
diff --git a/tracker/AdminServer/rulesinfo.cpp b/tracker/AdminServer/rulesinfo.cpp
new file mode 100644
index 0000000..2db058e
--- /dev/null
+++ b/tracker/AdminServer/rulesinfo.cpp
@@ -0,0 +1,132 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "rulesinfo.h"
+#include "Iresponse.h"
+
+#include "RulesInfoMsgHandler.h"
+#include "Socket.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+CRulesInfo::CRulesInfo(IResponse *target,serveritem_t &server) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+ m_pResponseTarget=target;
+
+ m_bIsRefreshing=false;
+
+ m_vRules=NULL;
+
+ int bytecode = S2A_RULES;
+ m_pQuery = new CSocket("internet rules query", -1);
+ m_pQuery->AddMessageHandler(new CRulesInfoMsgHandlerDetails(this, CMsgHandler::MSGHANDLER_ALL, &bytecode));
+}
+
+CRulesInfo::~CRulesInfo() {
+ delete m_pQuery;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a status query packet to a single server
+//-----------------------------------------------------------------------------
+void CRulesInfo::Query()
+{
+ CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
+ assert( buffer );
+
+ if ( !buffer )
+ {
+ return;
+ }
+
+ m_bIsRefreshing=true;
+ m_bRefreshed=false;
+
+ netadr_t adr;
+
+ adr.ip[0] = m_Server.ip[0];
+ adr.ip[1] = m_Server.ip[1];
+ adr.ip[2] = m_Server.ip[2];
+ adr.ip[3] = m_Server.ip[3];
+ adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+
+
+ // Create query message
+ buffer->Clear();
+ // Write control sequence
+ buffer->WriteLong(0xffffffff);
+
+ // Write query string
+ buffer->WriteString("rules");
+
+ // Sendmessage
+ m_pQuery->SendMessage( &adr, buffer );
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CRulesInfo::RunFrame()
+{
+ if (m_pQuery)
+ {
+ m_pQuery->Frame();
+ }
+
+}
+
+void CRulesInfo::UpdateServer(netadr_t *adr, CUtlVector<vgui::KeyValues *> *Rules)
+{
+
+ m_Server.hadSuccessfulResponse = true;
+
+ m_vRules=Rules;
+
+ m_bIsRefreshing=false;
+ m_bRefreshed=true;
+
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded();
+
+}
+
+void CRulesInfo::Refresh()
+{
+ Query();
+}
+
+bool CRulesInfo::IsRefreshing()
+{
+ return m_bIsRefreshing;
+}
+
+serveritem_t &CRulesInfo::GetServer()
+{
+ return m_Server;
+}
+
+bool CRulesInfo::Refreshed()
+{
+ bool val = m_bRefreshed;
+ m_bRefreshed=false;
+
+ return val;
+}
+
+CUtlVector<vgui::KeyValues *> *CRulesInfo::Rules()
+{
+ return m_vRules;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/rulesinfo.h b/tracker/AdminServer/rulesinfo.h
new file mode 100644
index 0000000..d7d33ee
--- /dev/null
+++ b/tracker/AdminServer/rulesinfo.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef RULESINFO_H
+#define RULESINFO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+
+class CSocket;
+class IResponse;
+
+#include <VGUI_PropertyPage.h>
+#include <VGUI_Frame.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_KeyValues.h>
+
+
+class CRulesInfo
+{
+
+public:
+
+ CRulesInfo(IResponse *target,serveritem_t &server);
+ ~CRulesInfo();
+
+ // send an rcon command to a server
+ void Query();
+
+ void Refresh();
+
+ bool IsRefreshing();
+ serveritem_t &GetServer();
+ void RunFrame();
+ bool Refreshed();
+
+ void UpdateServer(netadr_t *adr, CUtlVector<vgui::KeyValues *> *Rules);
+
+ CUtlVector<vgui::KeyValues *> *Rules();
+
+ int serverID;
+ int received;
+
+private:
+
+ serveritem_t m_Server;
+ CSocket *m_pQuery; // Game server query socket
+
+ IResponse *m_pResponseTarget;
+
+ bool m_bIsRefreshing;
+ float m_fSendTime;
+ bool m_bRefreshed;
+
+ CUtlVector<vgui::KeyValues *> *m_vRules;
+
+};
+
+
+#endif // RULESINFO_H \ No newline at end of file
diff --git a/tracker/AdminServer/rulesinfomsghandler.cpp b/tracker/AdminServer/rulesinfomsghandler.cpp
new file mode 100644
index 0000000..da1336c
--- /dev/null
+++ b/tracker/AdminServer/rulesinfomsghandler.cpp
@@ -0,0 +1,89 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "RulesInfoMsgHandler.h"
+
+#include "rulesinfo.h"
+#include "info.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+#include "inetapi.h"
+
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CRulesInfoMsgHandlerDetails::CRulesInfoMsgHandlerDetails( CRulesInfo *baseobject, HANDLERTYPE type, void *typeinfo /*= NULL*/ )
+ : CMsgHandler( type, typeinfo )
+{
+ m_pRulesInfo = baseobject;
+ m_vRules = new CUtlVector<vgui::KeyValues *>();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Process cracked message
+//-----------------------------------------------------------------------------
+bool CRulesInfoMsgHandlerDetails::Process( netadr_t *from, CMsgBuffer *msg )
+{
+ m_vRules->RemoveAll();
+ m_vRules->Purge();
+
+
+ // Check type of data.
+ if (msg->ReadByte() != S2A_RULES)
+ return false;
+
+
+ int pNumber;
+ pNumber = msg->ReadByte();
+
+ // there is a null string at the start of the rules...
+ msg->ReadString();
+
+
+ // Read the data
+ for (int i = 0; i < pNumber; i++)
+ {
+ vgui::KeyValues *kv=new vgui::KeyValues("rules");
+ char *cvar,*value;
+ cvar = new char[50];
+ value = new char[50];
+ v_strncpy(cvar,msg->ReadString(),50);
+ v_strncpy(value,msg->ReadString(),50);
+
+
+ kv->SetString("cvar",cvar);
+ kv->SetString("value",value);
+
+ m_vRules->AddToTail(kv);
+ }
+
+/* serveritem_t server;
+ memset(&server, 0, sizeof(server));
+ netadr_t netaddr;
+ if (net->StringToAdr("192.168.1.66", &netaddr))
+ {
+ memcpy(server.ip,netaddr.ip,4);
+ }
+
+ server.port = 27015;
+
+ CDialogGameInfo *gameDialog = new CDialogGameInfo(NULL, 0,*((int *)server.ip),pNumber);
+ gameDialog->Run("Stuff");
+
+*/
+
+
+ m_pRulesInfo->UpdateServer(from, m_vRules);
+
+
+ return true;
+}
+
+
diff --git a/tracker/AdminServer/rulesinfomsghandler.h b/tracker/AdminServer/rulesinfomsghandler.h
new file mode 100644
index 0000000..3b40b1e
--- /dev/null
+++ b/tracker/AdminServer/rulesinfomsghandler.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef RULESINFOMSGHANDLERDETAILS_H
+#define RULESINFOMSGHANDLERDETAILS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "Socket.h"
+#include "utlvector.h"
+
+class CRulesInfo;
+
+#include <VGUI_PropertyPage.h>
+#include <VGUI_Frame.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_KeyValues.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Socket handler for pinging internet servers
+//-----------------------------------------------------------------------------
+class CRulesInfoMsgHandlerDetails : public CMsgHandler
+{
+public:
+ CRulesInfoMsgHandlerDetails(CRulesInfo *baseobject, HANDLERTYPE type, void *typeinfo = NULL);
+
+ virtual bool Process(netadr_t *from, CMsgBuffer *msg);
+
+private:
+ // the parent class that we push info back to
+ CRulesInfo *m_pRulesInfo;
+ CUtlVector<vgui::KeyValues *> *m_vRules;
+};
+
+
+
+
+#endif // RULESINFOMSGHANDLERDETAILS_H
diff --git a/tracker/AdminServer/serverinfo.cpp b/tracker/AdminServer/serverinfo.cpp
new file mode 100644
index 0000000..860f349
--- /dev/null
+++ b/tracker/AdminServer/serverinfo.cpp
@@ -0,0 +1,187 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "serverinfo.h"
+#include "Iresponse.h"
+
+#include "ServerInfoMsgHandler.h"
+#include "Socket.h"
+#include "proto_oob.h"
+#include "DialogGameInfo.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+namespace
+{
+ const float SERVER_TIMEOUT =5.0f; // timeout before failing
+}
+
+typedef enum
+{
+ NONE = 0,
+ INFO_REQUESTED,
+ INFO_RECEIVED
+} RCONSTATUS;
+
+CServerInfo::CServerInfo(IResponse *target,serveritem_t &server) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+ m_pResponseTarget=target;
+
+ m_bIsRefreshing=false;
+
+ int bytecode = S2A_INFO_DETAILED;
+ m_pQuery = new CSocket("internet server query", -1);
+ m_pQuery->AddMessageHandler(new CServerInfoMsgHandlerDetails(this, CMsgHandler::MSGHANDLER_ALL, &bytecode));
+
+ m_fSendTime= 0;
+}
+
+CServerInfo::~CServerInfo() {
+ delete m_pQuery;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a status query packet to a single server
+//-----------------------------------------------------------------------------
+void CServerInfo::Query()
+{
+ CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
+ assert( buffer );
+
+ if ( !buffer )
+ {
+ return;
+ }
+
+ m_bIsRefreshing=true;
+ m_bRefreshed=false;
+
+ netadr_t adr;
+
+ adr.ip[0] = m_Server.ip[0];
+ adr.ip[1] = m_Server.ip[1];
+ adr.ip[2] = m_Server.ip[2];
+ adr.ip[3] = m_Server.ip[3];
+ adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+
+ // Set state
+ m_Server.received = (int)INFO_REQUESTED;
+
+ // Create query message
+ buffer->Clear();
+ // Write control sequence
+ buffer->WriteLong(0xffffffff);
+
+ // Write query string
+ buffer->WriteString("infostring");
+
+ // Sendmessage
+ m_pQuery->SendMessage( &adr );
+
+ m_fSendTime = CSocket::GetClock();
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerInfo::RunFrame()
+{
+
+ float curtime = CSocket::GetClock();
+ if(m_fSendTime!=0 && (curtime-m_fSendTime)> 5.0f) // 10 seconds timeout
+ {
+ m_fSendTime = 0;
+ m_pResponseTarget->ServerFailedToRespond();
+ }
+
+
+ if (m_pQuery)
+ {
+ m_pQuery->Frame();
+ }
+
+}
+
+void CServerInfo::UpdateServer(netadr_t *adr, bool proxy, const char *serverName, const char *map,
+ const char *gamedir, const char *gameDescription, int players,
+ int maxPlayers, float recvTime, bool password)
+{
+
+ m_Server.received = INFO_RECEIVED;
+
+ m_Server.hadSuccessfulResponse = true;
+
+ // copy in data necessary for filters
+ v_strncpy(m_Server.gameDir, gamedir, sizeof(m_Server.gameDir) - 1);
+ v_strncpy(m_Server.map, map, sizeof(m_Server.map) - 1);
+ v_strncpy(m_Server.name, serverName, sizeof(m_Server.name) - 1);
+ v_strncpy(m_Server.gameDescription, gameDescription, sizeof(m_Server.gameDescription) - 1);
+ m_Server.players = players;
+ m_Server.maxPlayers = maxPlayers;
+ m_Server.proxy = proxy;
+ m_Server.password = password;
+
+
+ int ping = (int)((recvTime - m_fSendTime) * 1000);
+
+
+ if (ping > 3000 || ping < 0)
+ {
+ // make sure ping is valid
+ ping = 1200;
+ }
+
+ // add to ping times list
+// server.pings[0] = server.pings[1];
+// server.pings[1] = server.pings[2];
+// server.pings[2] = ping;
+
+ // calculate ping
+// ping = CalculateAveragePing(server);
+
+ m_Server.ping = ping;
+
+
+ m_bIsRefreshing=false;
+ m_bRefreshed=true;
+ m_fSendTime = 0;
+
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded();
+
+}
+
+void CServerInfo::Refresh()
+{
+ Query();
+}
+
+bool CServerInfo::IsRefreshing()
+{
+
+ return m_bIsRefreshing;
+}
+
+serveritem_t &CServerInfo::GetServer()
+{
+ return m_Server;
+}
+
+bool CServerInfo::Refreshed()
+{
+ bool val = m_bRefreshed;
+ m_bRefreshed=false;
+
+ return val;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/serverinfo.h b/tracker/AdminServer/serverinfo.h
new file mode 100644
index 0000000..35036f0
--- /dev/null
+++ b/tracker/AdminServer/serverinfo.h
@@ -0,0 +1,60 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERINFO_H
+#define SERVERINFO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+
+class CSocket;
+class IResponse;
+
+
+class CServerInfo
+{
+
+public:
+
+ CServerInfo(IResponse *target,serveritem_t &server);
+ ~CServerInfo();
+
+ // send an rcon command to a server
+ void Query();
+
+ void Refresh();
+
+ bool IsRefreshing();
+ serveritem_t &GetServer();
+ void RunFrame();
+ bool Refreshed();
+
+ void UpdateServer(netadr_t *adr, bool proxy, const char *serverName, const char *map,
+ const char *gamedir, const char *gameDescription, int players,
+ int maxPlayers, float recvTime, bool password);
+
+ int serverID;
+ int received;
+
+private:
+
+ serveritem_t m_Server;
+ CSocket *m_pQuery; // Game server query socket
+
+ IResponse *m_pResponseTarget;
+
+ bool m_bIsRefreshing;
+ float m_fSendTime;
+ bool m_bRefreshed;
+
+};
+
+
+#endif // SERVERINFO_H \ No newline at end of file
diff --git a/tracker/AdminServer/serverinfomsghandler.cpp b/tracker/AdminServer/serverinfomsghandler.cpp
new file mode 100644
index 0000000..9b9a47f
--- /dev/null
+++ b/tracker/AdminServer/serverinfomsghandler.cpp
@@ -0,0 +1,74 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ServerInfoMsgHandler.h"
+
+#include "serverinfo.h"
+#include "info.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CServerInfoMsgHandlerDetails::CServerInfoMsgHandlerDetails( CServerInfo *baseobject, HANDLERTYPE type, void *typeinfo /*= NULL*/ )
+ : CMsgHandler( type, typeinfo )
+{
+ m_pServerInfo = baseobject;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Process cracked message
+//-----------------------------------------------------------------------------
+bool CServerInfoMsgHandlerDetails::Process( netadr_t *from, CMsgBuffer *msg )
+{
+ // Skip the control character
+ msg->ReadByte();
+
+ // get response name
+ const char *str = msg->ReadString();
+ if ( !str || !str[0] )
+ return false;
+
+ // get infostring
+ str = msg->ReadString();
+ if ( !str || !str[0] )
+ return false;
+
+ char info[ 2048 ];
+ strncpy( info, str, 2047 );
+ info[2047] = 0;
+
+ char name[256], map[256], gamedir[256], desc[256];
+
+ v_strncpy(name, Info_ValueForKey(info, "hostname"), 255);
+ v_strncpy(map, Info_ValueForKey(info, "map"), 255);
+ v_strncpy(gamedir, Info_ValueForKey(info, "gamedir"), 255);
+ strlwr(gamedir);
+ v_strncpy(desc, Info_ValueForKey(info, "description"), 255);
+ int players = atoi(Info_ValueForKey(info, "players"));
+ int maxplayers = atoi(Info_ValueForKey(info, "max"));
+ char serverType = *Info_ValueForKey(info, "type");
+ bool password = atoi(Info_ValueForKey(info, "password"));
+
+ m_pServerInfo->UpdateServer(from, // index of server
+ (serverType == 'p'),
+ name,
+ map,
+ gamedir,
+ desc,
+ players,
+ maxplayers,
+ msg->GetTime(), // receive time
+ password
+ );
+
+
+ return true;
+}
+
+
diff --git a/tracker/AdminServer/serverinfomsghandler.h b/tracker/AdminServer/serverinfomsghandler.h
new file mode 100644
index 0000000..09cbe05
--- /dev/null
+++ b/tracker/AdminServer/serverinfomsghandler.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERINFOMSGHANDLERDETAILS_H
+#define SERVERINFOMSGHANDLERDETAILS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "Socket.h"
+
+class CServerInfo;
+
+//-----------------------------------------------------------------------------
+// Purpose: Socket handler for pinging internet servers
+//-----------------------------------------------------------------------------
+class CServerInfoMsgHandlerDetails : public CMsgHandler
+{
+public:
+ CServerInfoMsgHandlerDetails(CServerInfo *baseobject, HANDLERTYPE type, void *typeinfo = NULL);
+
+ virtual bool Process(netadr_t *from, CMsgBuffer *msg);
+
+private:
+ // the parent class that we push info back to
+ CServerInfo *m_pServerInfo;
+};
+
+
+
+
+#endif // SERVERINFOMSGHANDLERDETAILS_H
diff --git a/tracker/AdminServer/serverinfopanel.cpp b/tracker/AdminServer/serverinfopanel.cpp
new file mode 100644
index 0000000..c384d55
--- /dev/null
+++ b/tracker/AdminServer/serverinfopanel.cpp
@@ -0,0 +1,285 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ServerInfoPanel.h"
+#include "MapCycleEditDialog.h"
+
+#include <vgui/ISystem.h>
+
+#include <ctype.h>
+#include <stdio.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CServerInfoPanel::CServerInfoPanel(vgui::Panel *parent, const char *name) : CVarListPropertyPage(parent, name)
+{
+ LoadControlSettings("Admin/GamePanelInfo.res", "PLATFORM");
+ LoadVarList("Admin/MainServerConfig.vdf");
+ m_iLastUptimeDisplayed = 0;
+ m_flUpdateTime = 0.0f;
+ m_bMapListRetrieved = false;
+ RemoteServer().AddServerMessageHandler(this, "UpdatePlayers");
+ RemoteServer().AddServerMessageHandler(this, "UpdateMap");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CServerInfoPanel::~CServerInfoPanel()
+{
+ RemoteServer().RemoveServerDataResponseTarget(this);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the current hostname
+//-----------------------------------------------------------------------------
+const char *CServerInfoPanel::GetHostname()
+{
+ return GetVarString("hostname");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Refreshes page if necessary
+//-----------------------------------------------------------------------------
+void CServerInfoPanel::OnThink()
+{
+ if (m_flUpdateTime < vgui::system()->GetFrameTime())
+ {
+ OnResetData();
+ }
+
+ // check uptime count
+ int time = m_iLastUptimeReceived + (int)(vgui::system()->GetFrameTime() - m_flLastUptimeReceiveTime);
+ if (time != m_iLastUptimeDisplayed)
+ {
+ m_iLastUptimeDisplayed = time;
+ char timeText[64];
+ _snprintf(timeText, sizeof(timeText), "%0.1i:%0.2i:%0.2i:%0.2i", (time / 3600) / 24, (time / 3600), (time / 60) % 60, time % 60);
+ SetControlString("UpTimeText", timeText);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Data is be reloaded from document into controls.
+//-----------------------------------------------------------------------------
+void CServerInfoPanel::OnResetData()
+{
+ // only ask for maps list once
+ if (!m_bMapListRetrieved)
+ {
+ RemoteServer().RequestValue(this, "maplist");
+ m_bMapListRetrieved = true;
+ }
+
+ // refresh our vars
+ RefreshVarList();
+
+ // ask for the constant data
+ RemoteServer().RequestValue(this, "playercount");
+ RemoteServer().RequestValue(this, "maxplayers");
+ RemoteServer().RequestValue(this, "gamedescription");
+ RemoteServer().RequestValue(this, "uptime");
+ RemoteServer().RequestValue(this, "ipaddress");
+
+ // update once every minute
+ m_flUpdateTime = (float)system()->GetFrameTime() + (60 * 1.0f);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles responses from the server
+//-----------------------------------------------------------------------------
+void CServerInfoPanel::OnServerDataResponse(const char *value, const char *response)
+{
+ if (!stricmp(value, "playercount"))
+ {
+ m_iPlayerCount = atoi(response);
+ }
+ else if (!stricmp(value, "maxplayers"))
+ {
+ m_iMaxPlayers = atoi(response);
+
+ // update control
+ char buf[128];
+ buf[0] = 0;
+ if (m_iMaxPlayers > 0)
+ {
+ sprintf(buf, "%d / %d", m_iPlayerCount, m_iMaxPlayers);
+ }
+ SetControlString("PlayersText", buf);
+ }
+ else if (!stricmp(value, "gamedescription"))
+ {
+ SetControlString("GameText", response);
+ }
+ else if (!stricmp(value, "hostname"))
+ {
+ PostActionSignal(new KeyValues("UpdateTitle"));
+ }
+ else if (!stricmp(value, "UpdateMap") || !stricmp(value, "UpdatePlayers"))
+ {
+ // server has indicated a change, force an update
+ m_flUpdateTime = 0.0f;
+ }
+ else if (!stricmp(value, "maplist"))
+ {
+ SetCustomStringList("map", response);
+ // save off maplist for use in mapcycle editing
+ ParseIntoMapList(response, m_AvailableMaps);
+ // don't chain through, not in varlist
+ return;
+ }
+ else if (!stricmp(value, "uptime"))
+ {
+ // record uptime for extrapolation
+ m_iLastUptimeReceived = atoi(response);
+ m_flLastUptimeReceiveTime = (float)system()->GetFrameTime();
+ }
+ else if (!stricmp(value, "ipaddress"))
+ {
+ SetControlString("ServerIPText", response);
+ }
+ else if (!stricmp(value, "mapcycle"))
+ {
+ ParseIntoMapList(response, m_MapCycle);
+ UpdateMapCycleValue();
+ // don't chain through, we set the value ourself
+ return;
+ }
+
+ // always chain through, in case this variable is in the list as well
+ BaseClass::OnServerDataResponse(value, response);
+
+ // post update
+ if (!stricmp(value, "map"))
+ {
+ // map has changed, update map cycle view
+ UpdateMapCycleValue();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: special editing of map cycle list
+//-----------------------------------------------------------------------------
+void CServerInfoPanel::OnEditVariable(KeyValues *rule)
+{
+ if (!stricmp(rule->GetName(), "mapcycle"))
+ {
+ CMapCycleEditDialog *dlg = new CMapCycleEditDialog(this, "MapCycleEditDialog");
+ dlg->Activate(this, m_AvailableMaps, m_MapCycle);
+ }
+ else
+ {
+ BaseClass::OnEditVariable(rule);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the value shown in the mapcycle field
+//-----------------------------------------------------------------------------
+void CServerInfoPanel::UpdateMapCycleValue()
+{
+ // look at current map
+ CUtlSymbol currentMap = GetVarString("map");
+ if (!currentMap.IsValid())
+ return;
+
+ // find it in the map cycle list
+ int listPoint = -1;
+ for (int i = 0; i < m_MapCycle.Count(); i++)
+ {
+ if (!stricmp(m_MapCycle[i].String(), currentMap.String()))
+ {
+ listPoint = i;
+ }
+ }
+
+ // take out the next 2 maps and make them the value
+ char nextMaps[512];
+ nextMaps[0] = 0;
+ bool needComma = false;
+ for (int i = 0; i < 2; i++)
+ {
+ int point = listPoint + i + 1;
+ if (point >= m_MapCycle.Count())
+ {
+ point -= m_MapCycle.Count();
+ }
+
+ if (m_MapCycle.IsValidIndex(point))
+ {
+ if (needComma)
+ {
+ strcat(nextMaps, ", ");
+ }
+ strcat(nextMaps, m_MapCycle[point].String());
+ needComma = true;
+ }
+ }
+
+ // add some elipses to show there is more maps
+ if (needComma)
+ {
+ strcat(nextMaps, ", ");
+ }
+ strcat(nextMaps, "...");
+
+ // show in varlist
+ SetVarString("mapcycle", nextMaps);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Seperates out a newline-seperated map list into an array
+//-----------------------------------------------------------------------------
+void CServerInfoPanel::ParseIntoMapList(const char *maplist, CUtlVector<CUtlSymbol> &mapArray)
+{
+ mapArray.RemoveAll();
+
+ const char *parse = maplist;
+ while (*parse)
+ {
+ // newline-seperated map list
+ //!! this should be done with a more standard tokenizer
+ if (isspace(*parse))
+ {
+ parse++;
+ continue;
+ }
+
+ // pull out the map name
+ const char *end = strstr(parse, "\n");
+ const char *end2 = strstr(parse, "\r");
+ if (end && end2 && end2 < end)
+ {
+ end = end2;
+ }
+ if (!end)
+ break;
+
+ char customString[64];
+ int nameSize = end - parse;
+ if (nameSize >= sizeof(customString))
+ {
+ nameSize = sizeof(customString) - 1;
+ }
+
+ // copy in the name
+ strncpy(customString, parse, nameSize);
+ customString[nameSize] = 0;
+ parse = end;
+
+ // add to the list string that aren't comments
+ if (nameSize > 0 && !(customString[0] == '/' && customString[1] == '/'))
+ {
+ int i = mapArray.AddToTail();
+ mapArray[i] = customString;
+ }
+ }
+}
+
diff --git a/tracker/AdminServer/serverinfopanel.h b/tracker/AdminServer/serverinfopanel.h
new file mode 100644
index 0000000..2959031
--- /dev/null
+++ b/tracker/AdminServer/serverinfopanel.h
@@ -0,0 +1,63 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERINFOPANEL_H
+#define SERVERINFOPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "VarListPropertyPage.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/utlvector.h"
+#include "tier1/utlsymbol.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying information about a game server
+//-----------------------------------------------------------------------------
+class CServerInfoPanel : public CVarListPropertyPage
+{
+public:
+ CServerInfoPanel(vgui::Panel *parent, const char *name);
+ ~CServerInfoPanel();
+
+ // gets the current hostname
+ const char *GetHostname();
+
+ // Called when page is loaded. Data should be reloaded from document into controls.
+ virtual void OnResetData();
+
+protected:
+ // vgui overrides
+ virtual void OnThink();
+
+ // special editing of map cycle list
+ virtual void OnEditVariable(KeyValues *rule);
+
+ // handles responses from the server
+ virtual void OnServerDataResponse(const char *value, const char *response);
+
+private:
+ void UpdateMapCycleValue();
+
+ float m_flUpdateTime;
+ int m_iPlayerCount, m_iMaxPlayers;
+ float m_flLastUptimeReceiveTime;
+ long m_iLastUptimeReceived;
+ long m_iLastUptimeDisplayed;
+
+ bool m_bMapListRetrieved;
+
+ // used to store some strings for mapcycle
+ CUtlVector<CUtlSymbol> m_AvailableMaps;
+ CUtlVector<CUtlSymbol> m_MapCycle;
+ void ParseIntoMapList(const char *maplist, CUtlVector<CUtlSymbol> &mapArray);
+
+ typedef CVarListPropertyPage BaseClass;
+};
+
+#endif // SERVERINFOPANEL_H \ No newline at end of file
diff --git a/tracker/AdminServer/serverpage.cpp b/tracker/AdminServer/serverpage.cpp
new file mode 100644
index 0000000..4677715
--- /dev/null
+++ b/tracker/AdminServer/serverpage.cpp
@@ -0,0 +1,906 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+// base vgui interfaces
+#include <VGUI_Controls.h>
+#include <VGUI_IInput.h>
+#include <VGUI_ISurface.h>
+#include <VGUI_IScheme.h>
+#include <VGUI_IVGui.h>
+#include <VGUI_MouseCode.h>
+#include "filesystem.h"
+
+
+// vgui controls
+#include <VGUI_Button.h>
+#include <VGUI_CheckButton.h>
+#include <VGUI_ComboBox.h>
+#include <VGUI_FocusNavGroup.h>
+#include <VGUI_Frame.h>
+#include <VGUI_KeyValues.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_MessageBox.h>
+#include <VGUI_Panel.h>
+#include <VGUI_PropertySheet.h>
+#include <VGUI_ToggleButton.h>
+#include <VGUI_QueryBox.h>
+
+
+// serverbrowser headers
+#include "inetapi.h"
+//#include "msgbuffer.h"
+#include "proto_oob.h"
+#include "ServerContextMenu.h"
+#include "socket.h"
+#include "util.h"
+#include "vinternetdlg.h"
+#include "dialogcvarchange.h"
+//#include "ModList.h"
+#include "DialogGameInfo.h"
+#include "ConfigPanel.h"
+
+
+// game list
+#include "FavoriteGames.h"
+#include "GamePanelInfo.h"
+
+// tracker stuff
+//#include "Tracker.h"
+#include "TrackerProtocol.h"
+//#include "OnlineStatus.h"
+
+
+// interface to game engine / tracker
+#include "IRunGameEngine.h"
+
+using namespace vgui;
+
+static VInternetDlg *s_InternetDlg = NULL;
+CSysModule * g_hTrackerNetModule = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+VInternetDlg::VInternetDlg( unsigned int userid ) : Frame(NULL, "VInternetDlg")
+{
+ s_InternetDlg = this;
+
+ m_iUserID=userid;
+ m_bLoggedIn=false;
+
+ MakePopup();
+
+ m_pSavedData = NULL;
+
+ // create the controls
+ m_pContextMenu = new CServerContextMenu(this);
+// m_pContextMenu->SetVisible(false);
+
+ m_pFavoriteGames = new CFavoriteGames(this);
+
+ SetMinimumSize(570, 550);
+
+ m_pGameList = m_pFavoriteGames;
+
+ // property sheet
+ m_pTabPanel = new PropertySheet(this, "GameTabs");
+
+ m_pTabPanel->SetTabWidth(150);
+// m_pTabPanel->SetScrolling(true);
+ m_pTabPanel->AddPage(m_pFavoriteGames, "My Servers");
+ m_pTabPanel->AddActionSignalTarget(this);
+
+ m_pStatusLabel = new Label(this, "StatusLabel", "");
+
+ LoadControlSettings("Admin\\DialogAdminServer.res");
+
+ m_pStatusLabel->SetText("");
+
+
+ // Setup tracker objects
+ // tracker doc
+ //g_pTrackerDoc = new CTrackerDoc();
+
+ // create the networking
+ /*m_pServerSession = new CServerSession();
+
+ // load networking dll
+ char szDLL[_MAX_PATH];
+
+ // now load the net interface so we can use it
+ g_pFullFileSystem->GetLocalPath("Friends/TrackerNET.dll", szDLL);
+ g_pFullFileSystem->GetLocalCopy(szDLL);
+ g_hTrackerNetModule = Sys_LoadModule(szDLL);
+
+ CreateInterfaceFn netFactory = Sys_GetFactory(g_hTrackerNetModule);
+ m_pNet = (ITrackerNET *)netFactory(TRACKERNET_INTERFACE_VERSION, NULL);
+
+ m_pNet->Initialize(27030, 27100);
+ m_iServerAddr=m_pNet->GetNetAddress("tracker3.valvesoftware.com:1200");
+
+ // uncomment this to do the "tracker" magic
+ //SendInitialLogin();
+ */
+
+ // load filters
+ LoadFilters();
+ // load window settings
+ LoadDialogState(this, "AdminServer");
+
+ // let us be ticked every frame
+ ivgui()->AddTickSignal(this->GetVPanel());
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+VInternetDlg::~VInternetDlg()
+{
+ // set a flag indicating the threads should kill themselves
+// m_pNet->Shutdown(false);
+// m_pNet->deleteThis();
+// m_pNet = NULL;
+
+ Sys_UnloadModule(g_hTrackerNetModule);
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called once to set up
+//-----------------------------------------------------------------------------
+void VInternetDlg::Initialize()
+{
+ SetTitle("Admin", true);
+ SetVisible(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : serverID -
+// Output : serveritem_t
+//-----------------------------------------------------------------------------
+serveritem_t &VInternetDlg::GetServer(unsigned int serverID)
+{
+ return m_pGameList->GetServer(serverID);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VInternetDlg::Open( void )
+{
+ m_pTabPanel->RequestFocus();
+ // if serverbrowser file is not there we will try to transfer the favorites list.
+ FileHandle_t f = g_pFullFileSystem->Open("AdminServer.vdf", "rb");
+ if (f)
+ {
+ g_pFullFileSystem->Close( f );
+ }
+
+
+ surface()->SetMinimized(GetVPanel(), false);
+ SetVisible(true);
+ RequestFocus();
+ m_pTabPanel->RequestFocus();
+ MoveToFront();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: relayouts the dialogs controls
+//-----------------------------------------------------------------------------
+void VInternetDlg::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y, wide, tall;
+ GetClientArea(x, y, wide, tall);
+
+ // game list in middle
+ m_pTabPanel->SetBounds(8, y + 8, GetWide() - 16, tall - (28));
+ x += 4;
+
+ // status text along bottom
+ m_pStatusLabel->SetBounds(x + 2, (tall - y) + 40, wide - 6, 20);
+ m_pStatusLabel->SetContentAlignment(Label::a_northwest);
+
+ Repaint();
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VInternetDlg::OnClose()
+{
+ // bug here if you exit before logging in.
+ SaveDialogState(this, "AdminServer");
+ SaveFilters();
+ Frame::OnClose();
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads filter settings from disk
+//-----------------------------------------------------------------------------
+void VInternetDlg::LoadFilters()
+{
+ // free any old filters
+ if (m_pSavedData)
+ {
+ m_pSavedData->deleteThis();
+ }
+
+ m_pSavedData = new KeyValues ("Filters");
+ if (!m_pSavedData->LoadFromFile(g_pFullFileSystem, "Admin\\AdminServer.vdf", true, "PLATFORM"))
+ {
+ // file not successfully loaded, create the default key
+ m_pSavedData->FindKey("List", true);
+ m_pSavedData->FindKey("List/Default", true);
+ m_pSavedData->SetString("DefaultFilter", "Default");
+ }
+
+ // load favorite servers
+ KeyValues *favorites = m_pSavedData->FindKey("Favorites", true);
+ m_bSaveRcon= m_pSavedData->FindKey("SaveRcon", true)->GetInt();
+
+ m_pFavoriteGames->LoadFavoritesList(favorites,m_bSaveRcon);
+
+ m_bAutoRefresh= m_pSavedData->FindKey("AutoRefresh", true)->GetInt();
+ if(!m_bAutoRefresh)
+ {
+ m_iRefreshTime=0;
+ }
+ else
+ {
+ m_iRefreshTime= m_pSavedData->FindKey("RefreshTime", true)->GetInt();
+ }
+
+ m_bGraphs= m_pSavedData->FindKey("ShowGraphs", true)->GetInt();
+ if(!m_bGraphs)
+ {
+ m_iGraphsRefreshTime=0;
+ }
+ else
+ {
+ m_iGraphsRefreshTime= m_pSavedData->FindKey("GraphsRefreshTime", true)->GetInt();
+ }
+
+ m_bDoLogging= m_pSavedData->FindKey("GetLogs", true)->GetInt();
+
+
+ m_pTabPanel->SetActivePage(m_pFavoriteGames);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VInternetDlg::SaveFilters()
+{
+
+ // get the favorites list
+ KeyValues *favorites = m_pSavedData->FindKey("Favorites", true);
+ m_pFavoriteGames->SaveFavoritesList(favorites,m_bSaveRcon);
+ m_pSavedData->SaveToFile(g_pFullFileSystem, "Admin\\AdminServer.vdf", "PLATFORM");
+
+}
+
+void VInternetDlg::SetConfig(bool autorefresh,bool savercon,int refreshtime,bool graphs,int graphsrefreshtime,bool getlogs)
+{
+ m_bAutoRefresh=autorefresh;
+ m_bDoLogging = getlogs;
+ m_bSaveRcon=savercon;
+ if(m_bAutoRefresh)
+ {
+ m_iRefreshTime=refreshtime;
+ }
+ else
+ {
+ m_iRefreshTime=0;
+ }
+
+ m_bGraphs = graphs;
+ if(graphs)
+ {
+ m_iGraphsRefreshTime=graphsrefreshtime;
+ }
+ else
+ {
+ m_iGraphsRefreshTime=0;
+ }
+
+ m_pSavedData->SetInt("AutoRefresh",autorefresh);
+ m_pSavedData->SetInt("SaveRcon",savercon);
+ m_pSavedData->SetInt("RefreshTime",refreshtime);
+ m_pSavedData->SetInt("GraphsRefreshTime",graphsrefreshtime);
+ m_pSavedData->SetInt("ShowGraphs",graphs);
+ m_pSavedData->SetInt("GetLogs",getlogs);
+
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates status test at bottom of window
+// Input : *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void VInternetDlg::UpdateStatusText(const char *fmt, ...)
+{
+ if ( !m_pStatusLabel )
+ return;
+
+ char str[ 1024 ];
+ va_list argptr;
+ va_start( argptr, fmt );
+ vsprintf( str, fmt, argptr );
+ va_end( argptr );
+
+ m_pStatusLabel->SetText( str );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a pointer to a static instance of this dialog
+// Output : VInternetDlg
+//----------------------------------------------------------------------------
+VInternetDlg *VInternetDlg::GetInstance()
+{
+ return s_InternetDlg;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : CServerContextMenu
+//-----------------------------------------------------------------------------
+CServerContextMenu *VInternetDlg::GetContextMenu()
+{
+ return m_pContextMenu;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: begins the process of joining a server from a game list
+// the game info dialog it opens will also update the game list
+//-----------------------------------------------------------------------------
+CDialogGameInfo *VInternetDlg::JoinGame(IGameList *gameList, unsigned int serverIndex)
+{
+ // open the game info dialog, then mark it to attempt to connect right away
+ CDialogGameInfo *gameDialog = OpenGameInfoDialog(gameList, serverIndex);
+
+ // set the dialog name to be the server name
+ gameDialog->Connect();
+
+ return gameDialog;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: joins a game by a specified IP, not attached to any game list
+//-----------------------------------------------------------------------------
+CDialogGameInfo *VInternetDlg::JoinGame(int serverIP, int serverPort, const char *titleName)
+{
+ // open the game info dialog, then mark it to attempt to connect right away
+ CDialogGameInfo *gameDialog = OpenGameInfoDialog(serverIP, serverPort, titleName);
+
+ // set the dialog name to be the server name
+ gameDialog->Connect();
+
+ return gameDialog;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: opens a game info dialog from a game list
+//-----------------------------------------------------------------------------
+CDialogGameInfo *VInternetDlg::OpenGameInfoDialog(IGameList *gameList, unsigned int serverIndex)
+{
+ CDialogGameInfo *gameDialog = new CDialogGameInfo(gameList, serverIndex);
+ serveritem_t &server = gameList->GetServer(serverIndex);
+ gameDialog->Run(server.name);
+ return gameDialog;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: opens a game info dialog by a specified IP, not attached to any game list
+//-----------------------------------------------------------------------------
+CDialogGameInfo *VInternetDlg::OpenGameInfoDialog(int serverIP, int serverPort, const char *titleName)
+{
+ CDialogGameInfo *gameDialog = new CDialogGameInfo(NULL, 0, serverIP, serverPort);
+ gameDialog->Run(titleName);
+ return gameDialog;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Save position and window size of a dialog from the .vdf file.
+// Input : *dialog - panel we are setting position and size
+// *dialogName - name of dialog in the .vdf file
+//-----------------------------------------------------------------------------
+void VInternetDlg::SaveDialogState(Panel *dialog, const char *dialogName)
+{
+ // write the size and position to the document
+ int x, y, wide, tall;
+ dialog->GetBounds(x, y, wide, tall);
+
+ KeyValues *data;
+ data = m_pSavedData->FindKey(dialogName, true);
+
+ data->SetInt("x", x);
+ data->SetInt("y", y);
+ data->SetInt("w", wide);
+ data->SetInt("t", tall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Load position and window size of a dialog from the .vdf file.
+// Input : *dialog - panel we are setting position and size
+// *dialogName - name of dialog in the .vdf file
+//-----------------------------------------------------------------------------
+void VInternetDlg::LoadDialogState(Panel *dialog, const char *dialogName)
+{
+ // read the size and position from the document
+ KeyValues *data;
+ data = m_pSavedData->FindKey(dialogName, true);
+
+ // calculate defaults, center of the screen
+ int x, y, wide, tall, dwide, dtall;
+ int nx, ny, nwide, ntall;
+ vgui::surface()->GetScreenSize(wide, tall);
+ dialog->GetSize(dwide, dtall);
+ x = (int)((wide - dwide) * 0.5);
+ y = (int)((tall - dtall) * 0.5);
+
+ // set dialog
+ nx = data->GetInt("x", x);
+ ny = data->GetInt("y", y);
+ nwide = data->GetInt("w", dwide);
+ ntall = data->GetInt("t", dtall);
+
+ // make sure it's on the screen. If it isn't, move it over so it is.
+ if (nx + nwide > wide)
+ {
+ nx = wide - nwide;
+ }
+ if (ny + ntall > tall)
+ {
+ ny = tall - ntall;
+ }
+ if (nx < 0)
+ {
+ nx = 0;
+ }
+ if (ny < 0)
+ {
+ ny = 0;
+ }
+
+ dialog->SetBounds(nx, ny, nwide, ntall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *dest -
+// *src -
+// bufsize -
+//-----------------------------------------------------------------------------
+void v_strncpy(char *dest, const char *src, int bufsize)
+{
+ if (src == dest)
+ return;
+
+ strncpy(dest, src, bufsize - 1);
+ dest[bufsize - 1] = 0;
+}
+
+void VInternetDlg::ConfigPanel()
+{
+ CConfigPanel *config = new CConfigPanel(m_bAutoRefresh,m_bSaveRcon,m_iRefreshTime,m_bGraphs,m_iGraphsRefreshTime,m_bDoLogging);
+ config->Run();
+}
+
+void VInternetDlg::OnManageServer(int serverID)
+{
+ int i;
+ serveritem_t &server = m_pFavoriteGames->GetServer(serverID);
+ netadr_t addr;
+ memcpy(addr.ip,server.ip,4);
+ addr.port=(server.port & 0xff) << 8 | (server.port & 0xff00) >> 8;
+ addr.type=NA_IP;
+
+ const char *netString = net->AdrToString(&addr);
+ char tabName[20];
+
+ for(i=0;i<m_pTabPanel->GetNumPages();i++)
+ {
+
+ m_pTabPanel->GetTabTitle(i,tabName,20);
+ if(!stricmp(netString,tabName))
+ {
+ break;
+ }
+ }
+
+ if(i==m_pTabPanel->GetNumPages())
+ {
+
+ if(m_bSaveRcon)
+ { // rcons are being saved
+ if(strlen(server.rconPassword)>0)
+ { // this rcon password is already saved :)
+ ManageServer(serverID,server.rconPassword);
+ return;
+ }
+ }
+
+ // otherwise ask for an rcon password
+ CDialogCvarChange *box = new CDialogCvarChange();
+ char id[5];
+ _snprintf(id,5,"%i",serverID);
+ box->AddActionSignalTarget(this);
+ box->SetTitle("Enter Rcon Password",true);
+ box->SetLabelText("CvarNameLabel","");
+ box->SetLabelText("PasswordLabel","Password:");
+
+ box->MakePassword();
+ box->Activate(id, "","rconpassword","Enter Rcon Password for this Server");
+ }
+ else
+ {
+ m_pTabPanel->SetActivePage(m_pTabPanel->GetPage(i));
+ }
+}
+
+void VInternetDlg::OnPlayerDialog(vgui::KeyValues *data)
+{
+ const char *type=data->GetString("type");
+ const char *playerName=data->GetString("player");
+ if(!stricmp(type,"rconpassword"))
+ {
+ const char *value=data->GetString("value");
+ serveritem_t &server = m_pFavoriteGames->GetServer(atoi(playerName)); // we encode the serverid in the name field :)
+ strncpy(server.rconPassword,value,sizeof(server.rconPassword)); // save this password
+
+ ManageServer(atoi(playerName),value);
+ }
+}
+
+void VInternetDlg::ManageServer(int serverID,const char *pass)
+{
+ serveritem_t &server = m_pFavoriteGames->GetServer(serverID);
+ netadr_t addr;
+ memcpy(addr.ip,server.ip,4);
+ addr.port=(server.port & 0xff) << 8 | (server.port & 0xff00) >> 8;
+ addr.type=NA_IP;
+
+ m_pGamePanelInfo = new CGamePanelInfo(this,"Current Server",server.gameDir,m_iRefreshTime,m_iGraphsRefreshTime,m_bDoLogging);
+
+ m_pTabPanel->AddPage(m_pGamePanelInfo,net->AdrToString(&addr) );
+
+ m_pGamePanelInfo->ChangeGame(server,pass);
+ m_pTabPanel->SetActivePage(m_pGamePanelInfo);
+}
+
+void VInternetDlg::UpdateServer(serveritem_t &server)
+{
+ m_pFavoriteGames->UpdateServer(server);
+}
+
+void VInternetDlg::OnDeleteServer(int chosenPanel)
+{
+ Panel *delPanel =m_pTabPanel->GetPage(chosenPanel);
+ m_pTabPanel->DeletePage(delPanel);
+
+ InvalidateLayout();
+ Repaint();
+
+}
+
+vgui::PropertySheet *VInternetDlg::GetTabPanel()
+{
+ return m_pTabPanel;
+}
+
+
+void VInternetDlg::OnOpenContextMenu()
+{
+// CServerContextMenu *menu = VInternetDlg::GetInstance()->GetContextMenu();
+ // no selected rows, so don't display default stuff in menu
+ if( m_pTabPanel->GetActiveTab()->IsCursorOver() ||
+ m_pFavoriteGames->IsCursorOver() )
+ {
+ m_pContextMenu->ShowMenu(this, -1, false, false, false,false);
+ }
+}
+
+
+
+
+
+
+
+
+void VInternetDlg::OnTick()
+{
+
+//FIX ME!!!
+ return;
+
+/*
+
+ // get the latest raw messages
+ IBinaryBuffer *buf;
+ CNetAddress address;
+ while ((buf = m_pNet->GetIncomingRawData(address)) != NULL)
+ {
+ //ReceivedRawData(buf, address);
+ buf->Release();
+ }
+
+ // get all the latest messages
+ IReceiveMessage *recv;
+ while ((recv = m_pNet->GetIncomingData()) != NULL)
+ {
+
+ // make sure the message is valid
+ if (!CheckMessageValidity(recv))
+ return;
+
+ // record the reception
+ // m_iLastReceivedTime = m_iTime;
+
+ // find the message id in the dispatch table
+ int dataName = recv->GetMsgID();
+
+
+
+ switch(dataName)
+ {
+ case TSVC_CHALLENGE:
+ {
+ int ChallengeKey;
+ int status = COnlineStatus::ONLINE;
+ int heartbeatRate =10000;//GetHeartBeatRate();
+
+ recv->ReadInt("challenge", ChallengeKey);
+ recv->ReadUInt("sessionID", m_iSessionID);
+ // respond to the challenge
+ ISendMessage *reply = CreateServerMessage(TCLS_RESPONSE);
+ reply->SetSessionID( m_iSessionID );
+
+
+
+ reply->WriteInt("challenge", ChallengeKey);
+ reply->WriteUInt("sessionID", m_iSessionID);
+ reply->WriteInt("status", status);
+ reply->WriteInt("build", 1994);
+ reply->WriteInt("hrate", heartbeatRate); // heartbeat rate to expect
+
+ //m_iPreviousHeartBeatRateSentToServer = heartbeatRate;
+
+ // reset the login timeout
+ //m_iLoginTimeout = system()->getTimeMillis() + COnlineStatus::SERVERCONNECT_TIMEOUT;
+
+ m_pNet->SendMessage(reply, NET_RELIABLE);
+
+ }
+ break;
+
+ case TSVC_LOGINOK:
+ {
+ int newStatus;
+ recv->ReadInt("status", newStatus);
+ m_bLoggedIn=true;
+
+ SearchForFriend(0, "[email protected]", "", "", "");
+
+ }
+ break;
+ case TSVC_FRIENDSFOUND:
+ {
+ //char name[60];
+
+ int serverID,sessionID;
+ recv->ReadInt("uid",m_iRemoteUID);
+ recv->ReadInt("serverid",serverID);
+ recv->ReadInt("sessionID",sessionID);
+
+
+
+ // create the message to the server
+ ISendMessage *msg = CreateServerMessage(TCLS_ROUTETOFRIEND);
+
+ // write in the redirection info
+ msg->WriteInt("rID", TCL_MESSAGE);
+ msg->WriteUInt("rUserID", m_iRemoteUID);
+ msg->WriteUInt("rSessionID", sessionID);
+ msg->WriteUInt("rServerID", serverID);
+ msg->WriteBlob("rData", "Hello", 5);
+
+ m_pNet->SendMessage(msg, NET_RELIABLE);
+
+ // lets log off
+ msg = CreateServerMessage(TCLS_HEARTBEAT);
+ msg->WriteInt("status", COnlineStatus::OFFLINE);
+ m_pNet->SendMessage(msg, NET_RELIABLE);
+
+ // m_pNet->Shutdown(true);
+ // m_pNet->deleteThis();
+ // SendStatusToServer(COnlineStatus::OFFLINE);
+
+ }
+ break;
+
+ default:
+ {
+ while(recv->AdvanceField())
+ {
+ char data[512];
+ const char *nm=recv->GetFieldName();
+ recv->ReadString(nm, data, 512);
+
+ }
+ }
+
+ break;
+
+
+ // { TSVC_CHALLENGE, CServerSession::ReceivedMsg_Challenge },
+ // { TSVC_LOGINOK, CServerSession::ReceivedMsg_LoginOK },
+ // { TSVC_LOGINFAIL, CServerSession::ReceivedMsg_LoginFail },
+ // { TSVC_DISCONNECT, CServerSession::ReceivedMsg_Disconnect },
+ // { TSVC_FRIENDS, CServerSession::ReceivedMsg_Friends },
+ // { TSVC_FRIENDUPDATE, CServerSession::ReceivedMsg_FriendUpdate },
+ // { TSVC_GAMEINFO, CServerSession::ReceivedMsg_GameInfo },
+ // { TSVC_HEARTBEAT, CServerSession::ReceivedMsg_Heartbeat },
+ // { TSVC_PINGACK, CServerSession::ReceivedMsg_PingAck },
+
+
+ //default:
+ // break;
+
+ }
+ //ReceivedData(recv);
+ m_pNet->ReleaseMessage(recv);
+ }
+
+
+ // get the latest fails
+ while ((recv = m_pNet->GetFailedMessage()) != NULL)
+ {
+
+
+ m_pNet->ReleaseMessage(recv);
+ }
+
+ // now let it update itself
+ m_pNet->RunFrame();
+ */
+}
+
+void VInternetDlg::SearchForFriend(unsigned int uid, const char *email, const char *username, const char *firstname, const char *lastname)
+{
+ ISendMessage *msg = CreateServerMessage(TCLS_FRIENDSEARCH);
+ msg->WriteUInt("uid", uid);
+ msg->WriteString("Email", email);
+ msg->WriteString("UserName", username);
+ msg->WriteString("FirstName", firstname);
+ msg->WriteString("LastName", lastname);
+
+ m_pNet->SendMessage(msg, NET_RELIABLE);
+}
+
+ISendMessage *VInternetDlg::CreateServerMessage(int msgID)
+{
+ ISendMessage *msg = m_pNet->CreateMessage(msgID);
+ msg->SetNetAddress(GetServerAddress());
+ msg->SetSessionID(m_iSessionID);
+ msg->SetEncrypted(true);
+
+ return msg;
+}
+
+CNetAddress VInternetDlg::GetServerAddress()
+{
+ return m_iServerAddr;// m_pNet->GetNetAddress("tracker.valvesoftware.com:1200");
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sends the first pack in the login sequence
+//-----------------------------------------------------------------------------
+void VInternetDlg::SendInitialLogin()
+{
+// assert(m_iLoginState == LOGINSTATE_WAITINGTORECONNECT || m_iLoginState == LOGINSTATE_DISCONNECTED);
+
+ m_iSessionID = 0;
+
+ // stop searching for alternate servers
+// m_bServerSearch = false;
+
+// int desiredStatus = COnlineStatus::ONLINE;
+
+
+ // setup the login message
+/* ISendMessage *loginMsg = m_pNet->CreateMessage(TCLS_LOGIN);
+ loginMsg->SetNetAddress(GetServerAddress());
+ loginMsg->SetEncrypted(true);
+ loginMsg->SetSessionID(0);
+
+// const char *adr= GetServerAddress().ToStaticString();
+
+ loginMsg->WriteUInt("uid", 36283);
+ loginMsg->WriteString("email", "[email protected]");
+ loginMsg->WriteString("password", "mrorange");
+ loginMsg->WriteInt("status", desiredStatus);
+
+ m_pNet->SendMessage(loginMsg, NET_RELIABLE);
+*/
+ // set the current status to be a connecting message
+// m_iStatus = COnlineStatus::CONNECTING;
+
+// m_iLoginState = LOGINSTATE_AWAITINGCHALLENGE;
+ // record the time (for timeouts)
+// m_iLoginTimeout = system()->getTimeMillis() + COnlineStatus::SERVERCONNECT_TIMEOUT;
+
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if the current message is valid
+// replies with a message telling the sender if it's not
+//-----------------------------------------------------------------------------
+bool VInternetDlg::CheckMessageValidity(IReceiveMessage *dataBlock)
+{
+ int msgID = dataBlock->GetMsgID();
+ if (msgID == TSVC_FRIENDS || msgID == TSVC_GAMEINFO || msgID == TSVC_HEARTBEAT || msgID == TSVC_FRIENDUPDATE)
+ {
+ // see if the server really knows us
+ if (/*m_iStatus < COnlineStatus::ONLINE ||*/ m_iSessionID != dataBlock->SessionID())
+ {
+ // the server thinks we're still logged on to it
+ // tell the server we're actually logged off from it
+ ISendMessage *msg = m_pNet->CreateReply(TCLS_HEARTBEAT, dataBlock);
+ // tell it we're the sessionID it thinks we are
+ msg->SetSessionID(dataBlock->SessionID());
+ msg->WriteInt("status", 0);
+ m_pNet->SendMessage(msg, NET_RELIABLE);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Message map
+//-----------------------------------------------------------------------------
+MessageMapItem_t VInternetDlg::m_MessageMap[] =
+{
+// MAP_MESSAGE( VInternetDlg, "PageChanged", OnGameListChanged ),
+ MAP_MESSAGE_INT( VInternetDlg, "Manage", OnManageServer, "serverID" ),
+ MAP_MESSAGE_PARAMS( VInternetDlg, "CvarChangeValue", OnPlayerDialog ),
+ MAP_MESSAGE_INT( VInternetDlg, "DeleteServer", OnDeleteServer, "panelid" ),
+ MAP_MESSAGE( VInternetDlg, "OpenContextMenu", OnOpenContextMenu ),
+};
+IMPLEMENT_PANELMAP(VInternetDlg, vgui::Frame);
diff --git a/tracker/AdminServer/serverpage.h b/tracker/AdminServer/serverpage.h
new file mode 100644
index 0000000..d12f599
--- /dev/null
+++ b/tracker/AdminServer/serverpage.h
@@ -0,0 +1,197 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================
+#if !defined( VINTERNETDLG_H )
+#define VINTERNETDLG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <VGUI_Frame.h>
+#include <VGUI_ListPanel.h>
+#include <VGUI_PHandle.h>
+
+#include "utlvector.h"
+#include "netadr.h"
+#include "Server.h"
+//#include "serversession.h"
+//#include "trackerdoc.h"
+
+//#include "ITrackerUser.h"
+#include "../TrackerNET/TrackerNET_Interface.h"
+#include "../TrackerNET/NetAddress.h" // for CNetAddress
+#include "../TrackerNET/BinaryBuffer.h" // for IBinaryBuffer
+
+#include "IGameList.h"
+
+//#include "ClickableTabbedPanel.h"
+
+class CServerContextMenu;
+namespace vgui
+{
+class Label;
+class Font;
+class ListPanel;
+class Button;
+class ComboBox;
+class QueryBox;
+class ToggleButton;
+class TextEntry;
+class CheckButton;
+class PropertySheet;
+}
+
+extern class IRunGameEngine *g_pRunGameEngine;
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+class CFavoriteGames;
+class CGamePanelInfo;
+class CDialogGameInfo;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class VInternetDlg : public vgui::Frame
+{
+
+public:
+ // Construction/destruction
+ VInternetDlg( unsigned int userid );
+ virtual ~VInternetDlg( void );
+
+ virtual void Initialize( void );
+
+ // displays the dialog, moves it into focus, updates if it has to
+ virtual void Open( void );
+
+ // gets server info
+ serveritem_t &VInternetDlg::GetServer(unsigned int serverID);
+
+ // setup
+ virtual void PerformLayout();
+
+ // updates status text at bottom of window
+ virtual void UpdateStatusText(PRINTF_FORMAT_STRING const char *format, ...);
+
+ // context menu access
+ virtual CServerContextMenu *GetContextMenu();
+
+ // returns a pointer to a static instance of this dialog
+ // valid for use only in sort functions
+ static VInternetDlg *GetInstance();
+
+ // begins the process of joining a server from a game list
+ // the game info dialog it opens will also update the game list
+ virtual CDialogGameInfo *JoinGame(IGameList *gameList, unsigned int serverIndex);
+
+ // joins a game by a specified IP, not attached to any game list
+ virtual CDialogGameInfo *JoinGame(int serverIP, int serverPort, const char *titleName);
+
+ // opens a game info dialog from a game list
+ virtual CDialogGameInfo *OpenGameInfoDialog(IGameList *gameList, unsigned int serverIndex);
+
+ // opens a game info dialog by a specified IP, not attached to any game list
+ virtual CDialogGameInfo *OpenGameInfoDialog(int serverIP, int serverPort, const char *titleName);
+
+ virtual vgui::PropertySheet *GetTabPanel();
+
+ // called by the config panel to setup some global config values
+ virtual void SetConfig(bool autorefresh,bool savercon,int refreshtime,bool graphs,int graphrefreshtime,bool getlogs);
+
+ // passes the server info to the favorites panel to update the rconPassword
+ virtual void UpdateServer(serveritem_t &server);
+
+ // opens up the config dialog with the current config settings
+ virtual void ConfigPanel();
+
+ virtual void OnTick();
+
+ void SearchForFriend(unsigned int uid, const char *email, const char *username, const char *firstname, const char *lastname);
+ ISendMessage *VInternetDlg::CreateServerMessage(int msgID);
+ CNetAddress GetServerAddress();
+ void SendInitialLogin();
+ bool CheckMessageValidity(IReceiveMessage *dataBlock);
+
+
+
+private:
+
+ // menu handler for tabs
+ void OnOpenContextMenu();
+ // current game list change
+ //virtual void OnGameListChanged();
+
+
+ // password entry dialog for new servers
+ void OnPlayerDialog(vgui::KeyValues *data);
+ void OnDeleteServer(int chosenPanel);
+
+ // load/saves filter settings from disk
+ virtual void LoadFilters();
+ virtual void SaveFilters();
+
+ // Load/saves position and window size of a dialog from disk
+ virtual void LoadDialogState(vgui::Panel *dialog, const char *dialogName);
+ virtual void SaveDialogState(vgui::Panel *dialog, const char *dialogName);
+
+ // called when dialog is shut down
+ virtual void OnClose();
+
+ // catches the "manage server" menu option
+ void OnManageServer(int serverID);
+
+ // actually creates the new tab
+ void ManageServer(int serverID,const char *pass);
+
+
+
+ // pointer to current game list
+ IGameList *m_pGameList;
+
+ // Status text
+ vgui::Label *m_pStatusLabel;
+
+ // property sheet
+ vgui::PropertySheet *m_pTabPanel;
+ CFavoriteGames *m_pFavoriteGames;
+ CGamePanelInfo *m_pGamePanelInfo;
+
+ vgui::KeyValues *m_pSavedData;
+
+ bool m_bAutoRefresh;
+ bool m_bSaveRcon;
+ int m_iRefreshTime;
+ bool m_bGraphs;
+ int m_iGraphsRefreshTime;
+ bool m_bDoLogging; // whether to get server log messages
+
+ ITrackerNET *m_pNet;
+ unsigned int m_iSessionID; // the session ID from tracker
+ unsigned int m_iUserID;
+ int m_iRemoteUID;
+ bool m_bLoggedIn;
+ CNetAddress m_iServerAddr;
+
+ // context menu
+ CServerContextMenu *m_pContextMenu;
+
+ typedef vgui::Frame BaseClass;
+
+ DECLARE_PANELMAP();
+};
+
+#endif // VINTERNETDLG_H \ No newline at end of file
diff --git a/tracker/AdminServer/serverping.cpp b/tracker/AdminServer/serverping.cpp
new file mode 100644
index 0000000..2c4eb69
--- /dev/null
+++ b/tracker/AdminServer/serverping.cpp
@@ -0,0 +1,145 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ServerPing.h"
+#include "Iresponse.h"
+
+#include "ServerPingMsgHandler.h"
+#include "Socket.h"
+#include "proto_oob.h"
+
+extern void v_strncpy(char *dest, const char *src, int bufsize);
+
+CServerPing::CServerPing(IResponse *target,serveritem_t &server) {
+
+ memcpy(&m_Server, &server,sizeof(serveritem_t));
+ m_pResponseTarget=target;
+
+ m_bIsRefreshing=false;
+
+ int bytecode = S2A_INFO_DETAILED;
+ m_pQuery = new CSocket("internet server ping", -1);
+ m_pQuery->AddMessageHandler(new CServerPingMsgHandlerDetails(this, CMsgHandler::MSGHANDLER_ALL, &bytecode));
+ m_fSendTime=0;
+}
+
+CServerPing::~CServerPing() {
+ delete m_pQuery;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sends a status query packet to a single server
+//-----------------------------------------------------------------------------
+void CServerPing::Query()
+{
+ CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
+ assert( buffer );
+
+ if ( !buffer )
+ {
+ return;
+ }
+
+ m_bIsRefreshing=true;
+ m_bRefreshed=false;
+
+ netadr_t adr;
+
+ adr.ip[0] = m_Server.ip[0];
+ adr.ip[1] = m_Server.ip[1];
+ adr.ip[2] = m_Server.ip[2];
+ adr.ip[3] = m_Server.ip[3];
+ adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
+ adr.type = NA_IP;
+
+ // Create query message
+ buffer->Clear();
+ // Write control sequence
+ buffer->WriteLong(0xffffffff);
+
+ // Write query string
+ buffer->WriteString("ping");
+
+ // Sendmessage
+ m_pQuery->SendMessage( &adr );
+
+ m_fSendTime = CSocket::GetClock();
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerPing::RunFrame()
+{
+/* float curtime = CSocket::GetClock();
+ if(m_fSendTime!=0 && (curtime-m_fSendTime)> 5.0f) // 10 seconds timeout
+ {
+ m_fSendTime = 0;
+ m_pResponseTarget->ServerFailedToRespond();
+ }
+*/
+
+ if (m_pQuery)
+ {
+ m_pQuery->Frame();
+ }
+
+}
+
+void CServerPing::UpdateServer(float recvTime)
+{
+
+ //A2A_ACK
+ int ping = (int)((recvTime - m_fSendTime) * 1000);
+
+
+ if (ping > 10000 || ping < 0)
+ {
+ // make sure ping is valid
+ ping = 1200;
+ }
+
+ m_Server.ping = ping;
+
+
+ m_bIsRefreshing=false;
+ m_bRefreshed=true;
+ m_fSendTime=0;
+
+ // notify the UI of the new server info
+ m_pResponseTarget->ServerResponded();
+
+}
+
+void CServerPing::Refresh()
+{
+ Query();
+}
+
+bool CServerPing::IsRefreshing()
+{
+
+ return m_bIsRefreshing;
+}
+
+serveritem_t &CServerPing::GetServer()
+{
+ return m_Server;
+}
+
+bool CServerPing::Refreshed()
+{
+ bool val = m_bRefreshed;
+ m_bRefreshed=false;
+
+ return val;
+} \ No newline at end of file
diff --git a/tracker/AdminServer/serverping.h b/tracker/AdminServer/serverping.h
new file mode 100644
index 0000000..43d8e74
--- /dev/null
+++ b/tracker/AdminServer/serverping.h
@@ -0,0 +1,55 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: defines a RCon class used to send rcon commands to remote servers
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERPING_H
+#define SERVERPING_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "server.h"
+#include "netadr.h"
+
+class CSocket;
+class IResponse;
+
+
+class CServerPing
+{
+
+public:
+
+ CServerPing(IResponse *target,serveritem_t &server);
+ ~CServerPing();
+
+ // send a ping to the server
+ void Query();
+
+ void Refresh();
+
+ bool IsRefreshing();
+ serveritem_t &GetServer();
+ void RunFrame();
+ bool Refreshed();
+
+ void UpdateServer(float recvTime);
+
+private:
+
+ serveritem_t m_Server;
+ CSocket *m_pQuery; // Game server query socket
+
+ IResponse *m_pResponseTarget;
+
+ bool m_bIsRefreshing;
+ float m_fSendTime;
+ bool m_bRefreshed;
+
+};
+
+
+#endif // SERVERPING_H \ No newline at end of file
diff --git a/tracker/AdminServer/serverpingmsghandler.cpp b/tracker/AdminServer/serverpingmsghandler.cpp
new file mode 100644
index 0000000..17a7b60
--- /dev/null
+++ b/tracker/AdminServer/serverpingmsghandler.cpp
@@ -0,0 +1,31 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "ServerPingMsgHandler.h"
+
+#include "ServerPing.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CServerPingMsgHandlerDetails::CServerPingMsgHandlerDetails( CServerPing *baseobject, HANDLERTYPE type, void *typeinfo /*= NULL*/ )
+ : CMsgHandler( type, typeinfo )
+{
+ m_pServerPing = baseobject;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Process cracked message
+//-----------------------------------------------------------------------------
+bool CServerPingMsgHandlerDetails::Process( netadr_t *from, CMsgBuffer *msg )
+{
+
+ m_pServerPing->UpdateServer(msg->GetTime());
+ return true;
+}
+
+
diff --git a/tracker/AdminServer/serverpingmsghandler.h b/tracker/AdminServer/serverpingmsghandler.h
new file mode 100644
index 0000000..c3b5a4a
--- /dev/null
+++ b/tracker/AdminServer/serverpingmsghandler.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVERPINGMSGHANDLERDETAILS_H
+#define SERVERPINGMSGHANDLERDETAILS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "Socket.h"
+
+class CServerPing;
+
+//-----------------------------------------------------------------------------
+// Purpose: Socket handler for pinging internet servers
+//-----------------------------------------------------------------------------
+class CServerPingMsgHandlerDetails : public CMsgHandler
+{
+public:
+ CServerPingMsgHandlerDetails(CServerPing *baseobject, HANDLERTYPE type, void *typeinfo = NULL);
+
+ virtual bool Process(netadr_t *from, CMsgBuffer *msg);
+
+private:
+ // the parent class that we push info back to
+ CServerPing *m_pServerPing;
+};
+
+
+
+
+#endif // SERVERPINGMSGHANDLERDETAILS_H
diff --git a/tracker/common/CompletionEvent.cpp b/tracker/common/CompletionEvent.cpp
new file mode 100644
index 0000000..dd4bfae
--- /dev/null
+++ b/tracker/common/CompletionEvent.cpp
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "CompletionEvent.h"
+#include "winlite.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: creates an event
+//-----------------------------------------------------------------------------
+EventHandle_t Event_CreateEvent()
+{
+ return (EventHandle_t)::CreateEvent(NULL, false, false, NULL);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the current thread to wait for either the event to be signalled, or the timeout to occur
+//-----------------------------------------------------------------------------
+void Event_WaitForEvent(EventHandle_t event, unsigned long timeoutMilliseconds)
+{
+ ::WaitForSingleObject((HANDLE)event, timeoutMilliseconds);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: signals an event to Activate
+// Releases one thread waiting on the event.
+// If the event has no threads waiting on it, the next thread to wait on it will be let right through
+//-----------------------------------------------------------------------------
+void Event_SignalEvent(EventHandle_t event)
+{
+ ::SetEvent((HANDLE)event);
+}
+
+
diff --git a/tracker/common/CompletionEvent.h b/tracker/common/CompletionEvent.h
new file mode 100644
index 0000000..77075f9
--- /dev/null
+++ b/tracker/common/CompletionEvent.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Wraps windows WaitForSingleEvent() calls
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef COMPLETIONEVENT_H
+#define COMPLETIONEVENT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+// handle to an event
+typedef unsigned long EventHandle_t;
+
+// creates an event
+EventHandle_t Event_CreateEvent();
+
+// sets the current thread to wait for either the event to be signalled, or the timeout to occur
+void Event_WaitForEvent(EventHandle_t event, unsigned long timeoutMilliseconds);
+
+// set the timeout to this for it to never time out
+#define TIMEOUT_INFINITE 0xFFFFFFFF
+
+// signals an event to Activate
+// Releases one thread waiting on the event.
+// If the event has no threads waiting on it, the next thread to wait on it will be let right through
+void Event_SignalEvent(EventHandle_t event);
+
+
+#endif // COMPLETIONEVENT_H
diff --git a/tracker/common/DebugConsole_Interface.h b/tracker/common/DebugConsole_Interface.h
new file mode 100644
index 0000000..4462046
--- /dev/null
+++ b/tracker/common/DebugConsole_Interface.h
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DEBUGCONSOLE_INTERFACE_H
+#define DEBUGCONSOLE_INTERFACE_H
+#pragma once
+
+#include "interface.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Debugging console interface
+//-----------------------------------------------------------------------------
+class IDebugConsole : public IBaseInterface
+{
+public:
+ virtual void Initialize( const char *consoleName, int logLevel ) = 0;
+ virtual void Print( int severity, PRINTF_FORMAT_STRING const char *msgDescriptor, ... ) = 0;
+
+ // gets a line of command input
+ // returns true if anything returned, false otherwise
+ virtual bool GetInput(char *buffer, int bufferSize) = 0;
+};
+
+#define DEBUGCONSOLE_INTERFACE_VERSION "DebugConsole001"
+
+#endif // DEBUGCONSOLE_INTERFACE_H
diff --git a/tracker/common/DebugTimer.h b/tracker/common/DebugTimer.h
new file mode 100644
index 0000000..57fc1be
--- /dev/null
+++ b/tracker/common/DebugTimer.h
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef DEBUGTIMER_H
+#define DEBUGTIMER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+// resets the timer
+void Timer_Start();
+
+// returns the time since Timer_Start() was called, in seconds
+double Timer_End();
+
+
+
+#endif // DEBUGTIMER_H
diff --git a/tracker/common/IGameList.h b/tracker/common/IGameList.h
new file mode 100644
index 0000000..8b7a008
--- /dev/null
+++ b/tracker/common/IGameList.h
@@ -0,0 +1,69 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef IGAMELIST_H
+#define IGAMELIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+struct serveritem_t;
+#include "FindSteamServers.h"
+
+#define EMPTY_SERVER_NAME "0.0.0.0:0"
+
+//-----------------------------------------------------------------------------
+// Purpose: Interface to accessing a game list
+//-----------------------------------------------------------------------------
+class IGameList
+{
+public:
+
+ enum InterfaceItem_e
+ {
+ FILTERS,
+ GETNEWLIST,
+ ADDSERVER,
+ ADDCURRENTSERVER,
+ };
+
+ // returns true if the game list supports the specified ui elements
+ virtual bool SupportsItem(InterfaceItem_e item) = 0;
+
+ // starts the servers refreshing
+ virtual void StartRefresh() = 0;
+
+ // gets a new server list
+ virtual void GetNewServerList() = 0;
+
+ // stops current refresh/GetNewServerList()
+ virtual void StopRefresh() = 0;
+
+ // returns true if the list is currently refreshing servers
+ virtual bool IsRefreshing() = 0;
+
+ // gets information about specified server
+ virtual serveritem_t &GetServer(unsigned int serverID) = 0;
+
+ // adds a new server to list
+ virtual void AddNewServer(serveritem_t &server) = 0;
+
+ // marks that server list has been fully received
+ virtual void ListReceived(bool moreAvailable, const char *lastUniqueIP, ESteamServerType serverType) = 0;
+
+ // called when Connect button is pressed
+ virtual void OnBeginConnect() = 0;
+
+ // reapplies filters
+ virtual void ApplyFilters() = 0;
+
+ // invalid server index
+ virtual int GetInvalidServerListID() = 0;
+};
+
+
+#endif // IGAMELIST_H
diff --git a/tracker/common/IServerRefreshResponse.h b/tracker/common/IServerRefreshResponse.h
new file mode 100644
index 0000000..50ab088
--- /dev/null
+++ b/tracker/common/IServerRefreshResponse.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef ISERVERREFRESHRESPONSE_H
+#define ISERVERREFRESHRESPONSE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+struct serveritem_t;
+
+//-----------------------------------------------------------------------------
+// Purpose: Callback interface for server updates
+//-----------------------------------------------------------------------------
+class IServerRefreshResponse
+{
+public:
+ // called when the server has successfully responded
+ virtual void ServerResponded(serveritem_t &server) = 0;
+
+ // called when a server response has timed out
+ virtual void ServerFailedToRespond(serveritem_t &server) = 0;
+
+ // called when the current refresh list is complete
+ virtual void RefreshComplete() = 0;
+};
+
+
+
+#endif // ISERVERREFRESHRESPONSE_H
diff --git a/tracker/common/IceKey.H b/tracker/common/IceKey.H
new file mode 100644
index 0000000..d6590f4
--- /dev/null
+++ b/tracker/common/IceKey.H
@@ -0,0 +1,65 @@
+//========= Public Domain Code ================================================
+//
+// Purpose: Header file for the C++ ICE encryption class.
+// Taken from public domain code, as written by Matthew Kwan - July 1996
+// http://www.darkside.com.au/ice/
+//=============================================================================
+
+#ifndef _IceKey_H
+#define _IceKey_H
+
+/*
+The IceKey class is used for encrypting and decrypting 64-bit blocks of data
+with the ICE (Information Concealment Engine) encryption algorithm.
+
+The constructor creates a new IceKey object that can be used to encrypt and decrypt data.
+The level of encryption determines the size of the key, and hence its speed.
+Level 0 uses the Thin-ICE variant, which is an 8-round cipher taking an 8-byte key.
+This is the fastest option, and is generally considered to be at least as secure as DES,
+although it is not yet certain whether it is as secure as its key size.
+
+For levels n greater than zero, a 16n-round cipher is used, taking 8n-byte keys.
+Although not as fast as level 0, these are very very secure.
+
+Before an IceKey can be used to encrypt data, its key schedule must be set with the set() member function.
+The length of the key required is determined by the level, as described above.
+
+The member functions encrypt() and decrypt() encrypt and decrypt respectively data
+in blocks of eight chracters, using the specified key.
+
+Two functions keySize() and blockSize() are provided
+which return the key and block size respectively, measured in bytes.
+The key size is determined by the level, while the block size is always 8.
+
+The destructor zeroes out and frees up all memory associated with the key.
+*/
+
+class IceSubkey;
+
+class IceKey {
+ public:
+ IceKey (int n);
+ ~IceKey ();
+
+ void set (const unsigned char *key);
+
+ void encrypt (const unsigned char *plaintext,
+ unsigned char *ciphertext) const;
+
+ void decrypt (const unsigned char *ciphertext,
+ unsigned char *plaintext) const;
+
+ int keySize () const;
+
+ int blockSize () const;
+
+ private:
+ void scheduleBuild (unsigned short *k, int n,
+ const int *keyrot);
+
+ int _size;
+ int _rounds;
+ IceSubkey *_keysched;
+};
+
+#endif
diff --git a/tracker/common/IceKey.cpp b/tracker/common/IceKey.cpp
new file mode 100644
index 0000000..f6b0c77
--- /dev/null
+++ b/tracker/common/IceKey.cpp
@@ -0,0 +1,393 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//========= Public Domain Code ================================================
+//
+// Purpose: C++ implementation of the ICE encryption algorithm.
+// Taken from public domain code, as written by Matthew Kwan - July 1996
+// http://www.darkside.com.au/ice/
+//=============================================================================
+
+#include "mathlib/IceKey.H"
+
+#pragma warning(disable: 4244)
+
+
+ /* Structure of a single round subkey */
+class IceSubkey {
+ public:
+ unsigned long val[3];
+};
+
+
+ /* The S-boxes */
+static unsigned long ice_sbox[4][1024];
+static int ice_sboxes_initialised = 0;
+
+
+ /* Modulo values for the S-boxes */
+static const int ice_smod[4][4] = {
+ {333, 313, 505, 369},
+ {379, 375, 319, 391},
+ {361, 445, 451, 397},
+ {397, 425, 395, 505}};
+
+ /* XOR values for the S-boxes */
+static const int ice_sxor[4][4] = {
+ {0x83, 0x85, 0x9b, 0xcd},
+ {0xcc, 0xa7, 0xad, 0x41},
+ {0x4b, 0x2e, 0xd4, 0x33},
+ {0xea, 0xcb, 0x2e, 0x04}};
+
+ /* Permutation values for the P-box */
+static const unsigned long ice_pbox[32] = {
+ 0x00000001, 0x00000080, 0x00000400, 0x00002000,
+ 0x00080000, 0x00200000, 0x01000000, 0x40000000,
+ 0x00000008, 0x00000020, 0x00000100, 0x00004000,
+ 0x00010000, 0x00800000, 0x04000000, 0x20000000,
+ 0x00000004, 0x00000010, 0x00000200, 0x00008000,
+ 0x00020000, 0x00400000, 0x08000000, 0x10000000,
+ 0x00000002, 0x00000040, 0x00000800, 0x00001000,
+ 0x00040000, 0x00100000, 0x02000000, 0x80000000};
+
+ /* The key rotation schedule */
+static const int ice_keyrot[16] = {
+ 0, 1, 2, 3, 2, 1, 3, 0,
+ 1, 3, 2, 0, 3, 1, 0, 2};
+
+
+/*
+ * 8-bit Galois Field multiplication of a by b, modulo m.
+ * Just like arithmetic multiplication, except that additions and
+ * subtractions are replaced by XOR.
+ */
+
+static unsigned int
+gf_mult (
+ register unsigned int a,
+ register unsigned int b,
+ register unsigned int m
+) {
+ register unsigned int res = 0;
+
+ while (b) {
+ if (b & 1)
+ res ^= a;
+
+ a <<= 1;
+ b >>= 1;
+
+ if (a >= 256)
+ a ^= m;
+ }
+
+ return (res);
+}
+
+
+/*
+ * Galois Field exponentiation.
+ * Raise the base to the power of 7, modulo m.
+ */
+
+static unsigned long
+gf_exp7 (
+ register unsigned int b,
+ unsigned int m
+) {
+ register unsigned int x;
+
+ if (b == 0)
+ return (0);
+
+ x = gf_mult (b, b, m);
+ x = gf_mult (b, x, m);
+ x = gf_mult (x, x, m);
+ return (gf_mult (b, x, m));
+}
+
+
+/*
+ * Carry out the ICE 32-bit P-box permutation.
+ */
+
+static unsigned long
+ice_perm32 (
+ register unsigned long x
+) {
+ register unsigned long res = 0;
+ register const unsigned long *pbox = ice_pbox;
+
+ while (x) {
+ if (x & 1)
+ res |= *pbox;
+ pbox++;
+ x >>= 1;
+ }
+
+ return (res);
+}
+
+
+/*
+ * Initialise the ICE S-boxes.
+ * This only has to be done once.
+ */
+
+static void
+ice_sboxes_init (void)
+{
+ register int i;
+
+ for (i=0; i<1024; i++) {
+ int col = (i >> 1) & 0xff;
+ int row = (i & 0x1) | ((i & 0x200) >> 8);
+ unsigned long x;
+
+ x = gf_exp7 (col ^ ice_sxor[0][row], ice_smod[0][row]) << 24;
+ ice_sbox[0][i] = ice_perm32 (x);
+
+ x = gf_exp7 (col ^ ice_sxor[1][row], ice_smod[1][row]) << 16;
+ ice_sbox[1][i] = ice_perm32 (x);
+
+ x = gf_exp7 (col ^ ice_sxor[2][row], ice_smod[2][row]) << 8;
+ ice_sbox[2][i] = ice_perm32 (x);
+
+ x = gf_exp7 (col ^ ice_sxor[3][row], ice_smod[3][row]);
+ ice_sbox[3][i] = ice_perm32 (x);
+ }
+}
+
+
+/*
+ * Create a new ICE key.
+ */
+
+IceKey::IceKey (int n)
+{
+ if (!ice_sboxes_initialised) {
+ ice_sboxes_init ();
+ ice_sboxes_initialised = 1;
+ }
+
+ if (n < 1) {
+ _size = 1;
+ _rounds = 8;
+ } else {
+ _size = n;
+ _rounds = n * 16;
+ }
+
+ _keysched = new IceSubkey[_rounds];
+}
+
+
+/*
+ * Destroy an ICE key.
+ */
+
+IceKey::~IceKey ()
+{
+ int i, j;
+
+ for (i=0; i<_rounds; i++)
+ for (j=0; j<3; j++)
+ _keysched[i].val[j] = 0;
+
+ _rounds = _size = 0;
+
+ delete[] _keysched;
+}
+
+
+/*
+ * The single round ICE f function.
+ */
+
+static unsigned long
+ice_f (
+ register unsigned long p,
+ const IceSubkey *sk
+) {
+ unsigned long tl, tr; /* Expanded 40-bit values */
+ unsigned long al, ar; /* Salted expanded 40-bit values */
+
+ /* Left half expansion */
+ tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00);
+
+ /* Right half expansion */
+ tr = (p & 0x3ff) | ((p << 2) & 0xffc00);
+
+ /* Perform the salt permutation */
+ // al = (tr & sk->val[2]) | (tl & ~sk->val[2]);
+ // ar = (tl & sk->val[2]) | (tr & ~sk->val[2]);
+ al = sk->val[2] & (tl ^ tr);
+ ar = al ^ tr;
+ al ^= tl;
+
+ al ^= sk->val[0]; /* XOR with the subkey */
+ ar ^= sk->val[1];
+
+ /* S-box lookup and permutation */
+ return (ice_sbox[0][al >> 10] | ice_sbox[1][al & 0x3ff]
+ | ice_sbox[2][ar >> 10] | ice_sbox[3][ar & 0x3ff]);
+}
+
+
+/*
+ * Encrypt a block of 8 bytes of data with the given ICE key.
+ */
+
+void
+IceKey::encrypt (
+ const unsigned char *ptext,
+ unsigned char *ctext
+) const
+{
+ register int i;
+ register unsigned long l, r;
+
+ l = (((unsigned long) ptext[0]) << 24)
+ | (((unsigned long) ptext[1]) << 16)
+ | (((unsigned long) ptext[2]) << 8) | ptext[3];
+ r = (((unsigned long) ptext[4]) << 24)
+ | (((unsigned long) ptext[5]) << 16)
+ | (((unsigned long) ptext[6]) << 8) | ptext[7];
+
+ for (i = 0; i < _rounds; i += 2) {
+ l ^= ice_f (r, &_keysched[i]);
+ r ^= ice_f (l, &_keysched[i + 1]);
+ }
+
+ for (i = 0; i < 4; i++) {
+ ctext[3 - i] = r & 0xff;
+ ctext[7 - i] = l & 0xff;
+
+ r >>= 8;
+ l >>= 8;
+ }
+}
+
+
+/*
+ * Decrypt a block of 8 bytes of data with the given ICE key.
+ */
+
+void
+IceKey::decrypt (
+ const unsigned char *ctext,
+ unsigned char *ptext
+) const
+{
+ register int i;
+ register unsigned long l, r;
+
+ l = (((unsigned long) ctext[0]) << 24)
+ | (((unsigned long) ctext[1]) << 16)
+ | (((unsigned long) ctext[2]) << 8) | ctext[3];
+ r = (((unsigned long) ctext[4]) << 24)
+ | (((unsigned long) ctext[5]) << 16)
+ | (((unsigned long) ctext[6]) << 8) | ctext[7];
+
+ for (i = _rounds - 1; i > 0; i -= 2) {
+ l ^= ice_f (r, &_keysched[i]);
+ r ^= ice_f (l, &_keysched[i - 1]);
+ }
+
+ for (i = 0; i < 4; i++) {
+ ptext[3 - i] = r & 0xff;
+ ptext[7 - i] = l & 0xff;
+
+ r >>= 8;
+ l >>= 8;
+ }
+}
+
+
+/*
+ * Set 8 rounds [n, n+7] of the key schedule of an ICE key.
+ */
+
+void
+IceKey::scheduleBuild (
+ unsigned short *kb,
+ int n,
+ const int *keyrot
+) {
+ int i;
+
+ for (i=0; i<8; i++) {
+ register int j;
+ register int kr = keyrot[i];
+ IceSubkey *isk = &_keysched[n + i];
+
+ for (j=0; j<3; j++)
+ isk->val[j] = 0;
+
+ for (j=0; j<15; j++) {
+ register int k;
+ unsigned long *curr_sk = &isk->val[j % 3];
+
+ for (k=0; k<4; k++) {
+ unsigned short *curr_kb = &kb[(kr + k) & 3];
+ register int bit = *curr_kb & 1;
+
+ *curr_sk = (*curr_sk << 1) | bit;
+ *curr_kb = (*curr_kb >> 1) | ((bit ^ 1) << 15);
+ }
+ }
+ }
+}
+
+
+/*
+ * Set the key schedule of an ICE key.
+ */
+
+void
+IceKey::set (
+ const unsigned char *key
+) {
+ int i;
+
+ if (_rounds == 8) {
+ unsigned short kb[4];
+
+ for (i=0; i<4; i++)
+ kb[3 - i] = (key[i*2] << 8) | key[i*2 + 1];
+
+ scheduleBuild (kb, 0, ice_keyrot);
+ return;
+ }
+
+ for (i=0; i<_size; i++) {
+ int j;
+ unsigned short kb[4];
+
+ for (j=0; j<4; j++)
+ kb[3 - j] = (key[i*8 + j*2] << 8) | key[i*8 + j*2 + 1];
+
+ scheduleBuild (kb, i*8, ice_keyrot);
+ scheduleBuild (kb, _rounds - 8 - i*8, &ice_keyrot[8]);
+ }
+}
+
+
+/*
+ * Return the key size, in bytes.
+ */
+
+int
+IceKey::keySize () const
+{
+ return (_size * 8);
+}
+
+
+/*
+ * Return the block size, in bytes.
+ */
+
+int
+IceKey::blockSize () const
+{
+ return (8);
+}
diff --git a/tracker/common/MasterMsgHandler.h b/tracker/common/MasterMsgHandler.h
new file mode 100644
index 0000000..094a2e4
--- /dev/null
+++ b/tracker/common/MasterMsgHandler.h
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef MASTERMSGHANDLER_H
+#define MASTERMSGHANDLER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "Socket.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Socket handler for lan broadcast pings
+//-----------------------------------------------------------------------------
+class CMasterMsgHandler : public CMsgHandler
+{
+public:
+ CMasterMsgHandler( IGameList *baseobject, HANDLERTYPE type, void *typeinfo = NULL );
+
+ virtual bool Process( netadr_t *from, CMsgBuffer *msg );
+
+private:
+ IGameList *m_pGameList;
+};
+
+
+
+#endif // MASTERMSGHANDLER_H
diff --git a/tracker/common/Socket.cpp b/tracker/common/Socket.cpp
new file mode 100644
index 0000000..93109ba
--- /dev/null
+++ b/tracker/common/Socket.cpp
@@ -0,0 +1,1035 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+#if !defined( _X360 )
+#define FD_SETSIZE 1024
+#endif
+
+#include <assert.h>
+#include "winlite.h"
+#if !defined( _X360 )
+#include "winsock.h"
+#else
+#include "winsockx.h"
+#endif
+#include "msgbuffer.h"
+#include "socket.h"
+#include "inetapi.h"
+#include "tier0/vcrmode.h"
+
+#include <VGUI/IVGui.h>
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: All socket I/O occurs on a thread
+//-----------------------------------------------------------------------------
+class CSocketThread
+{
+public:
+ typedef struct threadsocket_s
+ {
+ struct threadsocket_s *next;
+ CSocket *socket;
+ } threadsocket_t;
+
+ // Construction
+ CSocketThread( void );
+ virtual ~CSocketThread( void );
+
+ // Sockets add/remove themselves via their constructor
+ virtual void AddSocketToThread( CSocket *socket );
+ virtual void RemoveSocketFromThread( CSocket *socket );
+
+ // Lock changes to socket list, etc.
+ virtual void Lock( void );
+ // Unlock socket list, etc.
+ virtual void Unlock( void );
+
+ // Retrieve handle to shutdown event
+ virtual HANDLE GetShutdownHandle( void );
+ // Get head of socket list
+ virtual threadsocket_t *GetSocketList( void );
+
+ // Sample clock for socket thread
+ virtual float GetClock( void );
+
+private:
+ // Initialize the clock
+ void InitTimer( void );
+
+private:
+ // Critical section used for synchronizing access to socket list
+ CRITICAL_SECTION cs;
+ // List of sockets we are listening on
+ threadsocket_t *m_pSocketList;
+ // Thread handle
+ HANDLE m_hThread;
+ // Thread id
+ DWORD m_nThreadId;
+ // Event to set when we want to tell the thread to shut itself down
+ HANDLE m_hShutdown;
+
+ // High performance clock frequency
+ double m_dClockFrequency;
+ // Current accumulated time
+ double m_dCurrentTime;
+ // How many bits to shift raw 64 bit sample count by
+ int m_nTimeSampleShift;
+ // Previous 32 bit sample count
+ unsigned int m_uiPreviousTime;
+};
+
+// Singleton handler
+static CSocketThread *GetSocketThread()
+{
+ static CSocketThread g_SocketThread;
+ return &g_SocketThread;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Main winsock processing thread
+// Input : threadobject -
+// Output : static DWORD WINAPI
+//-----------------------------------------------------------------------------
+static DWORD WINAPI SocketThreadFunc( LPVOID threadobject )
+{
+ // Get pointer to CSocketThread object
+ CSocketThread *socketthread = ( CSocketThread * )threadobject;
+ assert( socketthread );
+ if ( !socketthread )
+ {
+ return 0;
+ }
+
+ // Keep looking for data until shutdown event is triggered
+ while ( 1 )
+ {
+ // List of sockets
+ CSocketThread::threadsocket_t *sockets;
+ // file descriptor set for sockets
+ fd_set fdset;
+ // number of sockets with messages ready
+ int number;
+ // number of sockets added to fd_set
+ int count;
+
+ // Check for shutdown event
+ if ( WAIT_OBJECT_0 == VCRHook_WaitForSingleObject( socketthread->GetShutdownHandle(), 0 ) )
+ {
+ break;
+ }
+
+ // Clear the set
+ FD_ZERO(&fdset);
+
+ // No changes to list right now
+ socketthread->Lock();
+
+ // Add all active sockets to the fdset
+ count = 0;
+ for ( sockets = socketthread->GetSocketList(); sockets; sockets = sockets->next )
+ {
+ FD_SET( static_cast<u_int>( sockets->socket->GetSocketNumber() ), &fdset );
+ count = max( count, sockets->socket->GetSocketNumber() );
+ }
+
+ // Done
+ socketthread->Unlock();
+
+ if ( count )
+ {
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000; // 100 millisecond == 100000 usec
+
+ // Block for 100000 usec, or until a message is in the queue
+ number = select( count + 1, &fdset, NULL, NULL, &tv );
+#if !defined( NO_VCR )
+ VCRGenericValue( "", &number, sizeof( number ) );
+#endif
+ if ( number > 0 )
+ {
+ // Iterate through socket list and see who has data waiting //
+ // No changes to list right now
+ socketthread->Lock();
+
+ // Check FD_SET for incoming network messages
+ for ( sockets = socketthread->GetSocketList(); sockets; sockets = sockets->next )
+ {
+ bool bSet = FD_ISSET( sockets->socket->GetSocketNumber(), &fdset );
+#if !defined( NO_VCR )
+ VCRGenericValue( "", &bSet, sizeof( bSet ) );
+#endif
+ if ( bSet )
+ {
+ // keep reading as long as there is data on the socket
+ while (sockets->socket->ReceiveData())
+ {
+ }
+ }
+ }
+
+ // Done
+ socketthread->Unlock();
+ }
+ }
+
+ // no need to sleep here, much better let it sleep in the select
+ }
+
+ ExitThread( 0 );
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Construction
+//-----------------------------------------------------------------------------
+CSocketThread::CSocketThread( void )
+{
+ InitTimer();
+
+ m_pSocketList = NULL;
+
+ InitializeCriticalSection( &cs );
+
+ m_hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL );
+ assert( m_hShutdown );
+
+ m_hThread = 0;
+ m_nThreadId = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CSocketThread::~CSocketThread( void )
+{
+ Lock();
+ if ( m_hThread )
+ {
+ SetEvent( m_hShutdown );
+ Sleep( 2 );
+ TerminateThread( m_hThread, 0 );
+ }
+ Unlock();
+
+ // Kill the socket
+//!! need to validate this line
+// assert( !m_pSocketList );
+
+ if ( m_hThread )
+ {
+ CloseHandle( m_hThread );
+ }
+
+ CloseHandle( m_hShutdown );
+
+ DeleteCriticalSection( &cs );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize socket thread timer
+//-----------------------------------------------------------------------------
+void CSocketThread::InitTimer( void )
+{
+ BOOL success;
+ LARGE_INTEGER PerformanceFreq;
+ unsigned int lowpart, highpart;
+
+ // Start clock at zero
+ m_dCurrentTime = 0.0;
+
+ success = QueryPerformanceFrequency( &PerformanceFreq );
+ assert( success );
+
+ // get 32 out of the 64 time bits such that we have around
+ // 1 microsecond resolution
+ lowpart = (unsigned int)PerformanceFreq.LowPart;
+ highpart = (unsigned int)PerformanceFreq.HighPart;
+
+ m_nTimeSampleShift = 0;
+
+ while ( highpart || ( lowpart > 2000000.0 ) )
+ {
+ m_nTimeSampleShift++;
+ lowpart >>= 1;
+ lowpart |= (highpart & 1) << 31;
+ highpart >>= 1;
+ }
+
+ m_dClockFrequency = 1.0 / (double)lowpart;
+
+ // Get initial sample
+ unsigned int temp;
+ LARGE_INTEGER PerformanceCount;
+ QueryPerformanceCounter( &PerformanceCount );
+ if ( !m_nTimeSampleShift )
+ {
+ temp = (unsigned int)PerformanceCount.LowPart;
+ }
+ else
+ {
+ // Rotate counter to right by m_nTimeSampleShift places
+ temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) |
+ ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift));
+ }
+
+ // Set first time stamp
+ m_uiPreviousTime = temp;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Thread local timer function
+// Output : float
+//-----------------------------------------------------------------------------
+float CSocketThread::GetClock( void )
+{
+ LARGE_INTEGER PerformanceCount;
+ unsigned int temp, t2;
+ double time;
+
+ // Get sample counter
+ QueryPerformanceCounter( &PerformanceCount );
+
+ if ( !m_nTimeSampleShift )
+ {
+ temp = (unsigned int)PerformanceCount.LowPart;
+ }
+ else
+ {
+ // Rotate counter to right by m_nTimeSampleShift places
+ temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) |
+ ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift));
+ }
+
+ // check for turnover or backward time
+ if ( ( temp <= m_uiPreviousTime ) &&
+ ( ( m_uiPreviousTime - temp ) < 0x10000000) )
+ {
+ m_uiPreviousTime = temp; // so we can't get stuck
+ }
+ else
+ {
+ // gap in performance clocks
+ t2 = temp - m_uiPreviousTime;
+
+ // Convert to time using frequencey of clock
+ time = (double)t2 * m_dClockFrequency;
+
+ // Remember old time
+ m_uiPreviousTime = temp;
+
+ // Increment clock
+ m_dCurrentTime += time;
+ }
+#if !defined( NO_VCR )
+ VCRGenericValue( "", &m_dCurrentTime, sizeof( m_dCurrentTime ) );
+#endif
+ // Convert to float
+ return (float)m_dCurrentTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns handle of shutdown event
+// Output : HANDLE
+//-----------------------------------------------------------------------------
+HANDLE CSocketThread::GetShutdownHandle( void )
+{
+ return m_hShutdown;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns head of socket list
+// Output : CSocketThread::threadsocket_t
+//-----------------------------------------------------------------------------
+CSocketThread::threadsocket_t *CSocketThread::GetSocketList( void )
+{
+ return m_pSocketList;
+}
+
+int socketCount = 0;
+
+//-----------------------------------------------------------------------------
+// Purpose: Locks object and adds socket to thread
+//-----------------------------------------------------------------------------
+void CSocketThread::AddSocketToThread( CSocket *socket )
+{
+ // create the thread if it isn't there
+ if (!m_hThread)
+ {
+ m_hThread = VCRHook_CreateThread( NULL, 0, SocketThreadFunc, (void *)this, 0, &m_nThreadId );
+ assert( m_hThread );
+ }
+
+ socketCount++;
+
+ threadsocket_t *p = new threadsocket_t;
+ p->socket = socket;
+
+ Lock();
+ p->next = m_pSocketList;
+ m_pSocketList = p;
+ Unlock();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Locks list and removes specified socket from thread
+//-----------------------------------------------------------------------------
+void CSocketThread::RemoveSocketFromThread( CSocket *socket )
+{
+ if (!m_hThread)
+ return;
+
+ socketCount--;
+
+ Lock();
+ if ( m_pSocketList )
+ {
+ threadsocket_t *p, *n;
+ p = m_pSocketList;
+ if ( p->socket == socket )
+ {
+ m_pSocketList = m_pSocketList->next;
+ delete p;
+ }
+ else
+ {
+ while ( p->next )
+ {
+ n = p->next;
+ if ( n->socket == socket )
+ {
+ p->next = n->next;
+ delete n;
+ break;
+ }
+ p = n;
+ }
+ }
+ }
+ Unlock();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSocketThread::Lock( void )
+{
+ VCRHook_EnterCriticalSection( &cs );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSocketThread::Unlock( void )
+{
+ LeaveCriticalSection( &cs );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructs a message handler for incoming socket messages
+//-----------------------------------------------------------------------------
+CMsgHandler::CMsgHandler( HANDLERTYPE type, void *typeinfo /*=NULL*/ )
+{
+ m_Type = type;
+ m_pNext = NULL;
+
+ // Assume no socket
+ SetSocket( NULL );
+
+ // Assume no special checking
+ m_ByteCode = 0;
+ m_szString[ 0 ] = 0;
+
+ switch ( m_Type )
+ {
+ default:
+ case MSGHANDLER_ALL:
+ break;
+ case MSGHANDLER_BYTECODE:
+ m_ByteCode = *(unsigned char *)typeinfo;
+ break;
+ case MSGHANDLER_STRING:
+ strcpy( m_szString, (char *)typeinfo );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMsgHandler::~CMsgHandler( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Default message handler for received messages
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMsgHandler::Process( netadr_t *from, CMsgBuffer *msg )
+{
+ // Swallow message by default
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check for special handling
+// Input : *from -
+// *msg -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMsgHandler::ProcessMessage( netadr_t *from, CMsgBuffer *msg )
+{
+ bool bret = false;
+ unsigned char ch;
+ const char *str;
+
+ // Crack bytecode or string code
+ switch( m_Type )
+ {
+ case MSGHANDLER_BYTECODE:
+ msg->Push();
+ ch = (unsigned char)msg->ReadByte();
+ msg->Pop();
+ if ( ch == m_ByteCode )
+ {
+ bret = Process( from, msg );
+ }
+ break;
+ case MSGHANDLER_STRING:
+ msg->Push();
+ str = msg->ReadString();
+ msg->Pop();
+ if ( str && str[ 0 ] && !stricmp( m_szString, str ) )
+ {
+ bret = Process( from, msg );
+ }
+ break;
+ default:
+ case MSGHANDLER_ALL:
+ bret = Process( from, msg );
+ break;
+ }
+
+ return bret;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get next in chain of handlers
+//-----------------------------------------------------------------------------
+CMsgHandler *CMsgHandler::GetNext( void ) const
+{
+ return m_pNext;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set next in handler chain
+// Input : *next -
+//-----------------------------------------------------------------------------
+void CMsgHandler::SetNext( CMsgHandler *next )
+{
+ m_pNext = next;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get underlying socket object
+// Output : CSocket
+//-----------------------------------------------------------------------------
+CSocket *CMsgHandler::GetSocket( void ) const
+{
+ return m_pSocket;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set underlying socket object
+// Input : *socket -
+//-----------------------------------------------------------------------------
+void CMsgHandler::SetSocket( CSocket *socket )
+{
+ m_pSocket = socket;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a non-blocking, broadcast capable, UDP socket. If port is
+// specified, binds it to listen on that port, otherwise, chooses a random port.
+//-----------------------------------------------------------------------------
+CSocket::CSocket( const char *socketname, int port /*= -1*/ ) : m_SendBuffer(socketname)
+{
+ struct sockaddr_in address;
+ unsigned long _true = 1;
+ int i = 1;
+
+ m_pSocketName = socketname;
+
+ m_bValid = false;
+ m_bResolved = false;
+ m_pMessageHandlers = NULL;
+ m_nUserData = 0;
+ m_bBroadcastSend = false;
+ m_iTotalPackets = 0;
+ m_iCurrentPackets = 0;
+ m_iRetries = 0;
+
+ m_pBufferCS = new CRITICAL_SECTION;
+ InitializeCriticalSection((CRITICAL_SECTION *)m_pBufferCS);
+
+ // ensure the socketthread singleton has been created
+ GetSocketThread();
+
+ // Set up the socket
+ m_Socket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ if ( m_Socket == -1 )
+ {
+ //int err = WSAGetLastError();
+ // WSANOTINITIALISED
+ return;
+ }
+
+ // Set it to non-blocking
+ if ( ioctlsocket ( m_Socket, FIONBIO, &_true ) == -1 )
+ {
+ closesocket( m_Socket );
+ m_Socket = 0;
+ return;
+ }
+
+ // Allow broadcast packets
+ if ( setsockopt( m_Socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == -1 )
+ {
+ closesocket( m_Socket );
+ m_Socket = 0;
+ return;
+ }
+
+ // LATER: Support specifying interface name
+ //if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
+ address.sin_addr.s_addr = INADDR_ANY;
+ //else
+ // NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
+
+ if ( port == -1 )
+ {
+ address.sin_port = 0;
+ }
+ else
+ {
+ address.sin_port = htons( (short)port );
+ }
+
+ address.sin_family = AF_INET;
+
+ // only bind if we're required to be on a certain port
+ if ( address.sin_port > 0)
+ {
+ // Bind the socket to specified port
+ if ( bind( m_Socket, (struct sockaddr *)&address, sizeof(address) ) == -1 )
+ {
+ closesocket (m_Socket);
+ m_Socket = 0;
+ return;
+ }
+ }
+
+ // Mark as valid
+ m_bValid = true;
+
+ // Only add valid sockets to thread
+ GetSocketThread()->AddSocketToThread( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CSocket::~CSocket( void )
+{
+ DeleteCriticalSection((CRITICAL_SECTION *)m_pBufferCS);
+ delete (CRITICAL_SECTION *)m_pBufferCS;
+
+ // Try to remove socket from thread
+ GetSocketThread()->RemoveSocketFromThread( this );
+
+ // Ask message handlers to remove selves?
+ if ( m_bValid )
+ {
+ ::shutdown(m_Socket, 0x01);
+ ::shutdown(m_Socket, 0x02);
+ closesocket( m_Socket );
+ m_Socket = 0;
+ }
+
+ // Remove handlers
+ CMsgHandler *handler = m_pMessageHandlers;
+ while ( handler )
+ {
+ RemoveMessageHandler( handler );
+ delete handler;
+ handler = m_pMessageHandlers;
+ }
+ m_pMessageHandlers = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add hander to head of chain
+// Input : *handler -
+//-----------------------------------------------------------------------------
+void CSocket::AddMessageHandler( CMsgHandler *handler )
+{
+ handler->SetNext( m_pMessageHandlers );
+ m_pMessageHandlers = handler;
+
+ // Set the socket pointer
+ handler->SetSocket( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Removed indicated handler
+// Input : *handler -
+//-----------------------------------------------------------------------------
+void CSocket::RemoveMessageHandler( CMsgHandler *handler )
+{
+ if ( !handler )
+ {
+ return;
+ }
+
+ CMsgHandler *list = m_pMessageHandlers;
+ if ( list == handler )
+ {
+ m_pMessageHandlers = m_pMessageHandlers->GetNext();
+ return;
+ }
+
+ while ( list )
+ {
+ if ( list->GetNext() == handler )
+ {
+ list->SetNext( handler->GetNext() );
+ handler->SetNext( NULL );
+ return;
+ }
+ list = list->GetNext();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Send message to specified address
+// Input : *to -
+// Output : int - number of bytes sent
+//-----------------------------------------------------------------------------
+int CSocket::SendMessage( netadr_t *to, CMsgBuffer *msg /*= NULL*/ )
+{
+ m_bBroadcastSend = false;
+ m_ToAddress = *to;
+
+ if ( !m_bValid )
+ {
+ return 0;
+ }
+
+ if ( !msg )
+ {
+ msg = GetSendBuffer();
+ }
+
+ struct sockaddr addr;
+ net->NetAdrToSockAddr ( to, &addr );
+
+ int bytessent = sendto( m_Socket, (const char *)msg->GetData(), msg->GetCurSize(), 0, &addr, sizeof( addr ) );
+ if ( bytessent == msg->GetCurSize() )
+ {
+ return bytessent;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Send broadcast message on specified port
+// Input : port -
+// Output : int - number of bytes sent
+//-----------------------------------------------------------------------------
+int CSocket::Broadcast( int port, CMsgBuffer *msg /*= NULL*/ )
+{
+ m_bBroadcastSend = true;
+ memset( &m_ToAddress, 0, sizeof( m_ToAddress ) );
+
+ if ( !m_bValid )
+ {
+ return 0;
+ }
+
+ if ( !msg )
+ {
+ msg = GetSendBuffer();
+ }
+
+ struct sockaddr addr;
+ netadr_t to;
+
+ to.port = (unsigned short)htons( (unsigned short)port );
+ to.type = NA_BROADCAST;
+
+ net->NetAdrToSockAddr ( &to, &addr );
+
+ int bytessent = sendto( m_Socket, (const char *)msg->GetData(), msg->GetCurSize(), 0, &addr, sizeof( addr ) );
+ if ( bytessent == msg->GetCurSize() )
+ {
+ return bytessent;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Retrieve internal message buffer
+// Output : CMsgBuffer
+//-----------------------------------------------------------------------------
+CMsgBuffer *CSocket::GetSendBuffer( void )
+{
+ return &m_SendBuffer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called once per frame (outside of the socket thread) to allow socket to receive incoming messages
+// and route them as appropriate
+//-----------------------------------------------------------------------------
+void CSocket::Frame( void )
+{
+ // No data waiting
+ if (!m_MsgBuffers.Size())
+ return;
+
+ VCRHook_EnterCriticalSection( (CRITICAL_SECTION *)m_pBufferCS );
+
+ // pass up all the receive buffers
+ for (int i = 0; i < m_MsgBuffers.Size(); i++)
+ {
+ // See if there's a handler for this message
+ CMsgHandler *handler = m_pMessageHandlers;
+ netadr_t addr = m_MsgBuffers[i].GetNetAddress();
+ while ( handler )
+ {
+ // Swallow message?
+ if ( handler->ProcessMessage( &addr, &m_MsgBuffers[i] ) )
+ break;
+
+ handler = handler->GetNext();
+ }
+ }
+
+ // free the buffer list
+ m_MsgBuffers.RemoveAll();
+
+ LeaveCriticalSection((CRITICAL_SECTION *)m_pBufferCS);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Is socket set up correctly
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CSocket::IsValid( void ) const
+{
+ return m_bValid;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CSocket::GetClock( void )
+{
+ return GetSocketThread()->GetClock();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resolves the socket address
+// Output : const netadr_t
+//-----------------------------------------------------------------------------
+const netadr_t *CSocket::GetAddress( void )
+{
+ assert( m_bValid );
+
+ if ( !m_bResolved )
+ {
+ m_bResolved = true;
+ // Determine resulting socket address
+ net->GetSocketAddress( m_Socket, &m_Address );
+ }
+
+ return &m_Address;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Let the user store/retrieve a 32 bit value
+// Input : userData -
+//-----------------------------------------------------------------------------
+void CSocket::SetUserData( unsigned int userData )
+{
+ m_nUserData = userData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Let the user store/retrieve a 32 bit value
+// Output : unsigned int
+//-----------------------------------------------------------------------------
+unsigned int CSocket::GetUserData(void ) const
+{
+ return m_nUserData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the underlying socket id number for setting up the fd_set
+//-----------------------------------------------------------------------------
+int CSocket::GetSocketNumber( void ) const
+{
+ return m_Socket;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called once FD_ISSET is detected
+//-----------------------------------------------------------------------------
+bool CSocket::ReceiveData( void )
+{
+ // Check for data
+ struct sockaddr from;
+ int fromlen;
+ int bytes;
+ unsigned char buffer[ CMsgBuffer::NET_MAXMESSAGE ];
+
+ fromlen = sizeof( from );
+ bytes = VCRHook_recvfrom( m_Socket, (char *)buffer, CMsgBuffer::NET_MAXMESSAGE, 0, (struct sockaddr *)&from, &fromlen );
+
+ //int port = ntohs( ((struct sockaddr_in *)&from)->sin_port);
+
+ // Socket error
+ if ( bytes == -1 )
+ {
+ return false;
+ }
+
+ // Too much data, ignore it
+ if ( bytes >= CMsgBuffer::NET_MAXMESSAGE )
+ {
+ return false;
+ }
+
+ // Packets must have -1 tag
+ if ( bytes < 4 )
+ {
+ return false;
+ }
+
+ // Mark the time no matter what since FD_SET said there was data and we should have it now
+ float recvTime = GetClock();
+
+ if( *(int *)&buffer[0] == -2 ) // its a split packet :)
+ {
+ int curPacket=0,offset=0;
+ SPLITPACKET *pak =reinterpret_cast<SPLITPACKET *>(&buffer[0]);
+
+ if(m_iTotalPackets==0) // this is the first in the series
+ {
+ m_iTotalPackets = (pak->packetID & 0x0f);
+ m_iSeqNo = pak->sequenceNumber;
+ m_iRetries=0;
+
+ m_iCurrentPackets=1;// packet numbers start at zero, total is the total number (i.e =2 for packet 0,1)
+ curPacket= (pak->packetID & 0xf0)>>4;
+ }
+ else if (m_iSeqNo == pak->sequenceNumber)
+ {
+ m_iCurrentPackets++;
+ curPacket= (pak->packetID & 0xf0)>>4;
+ }
+ else
+ {
+ m_iRetries++;
+ if(m_iRetries>MAX_RETRIES) // make sure we give up eventually on fragments
+ {
+ m_iTotalPackets=0;
+ }
+ return false; // TODO: add support for multiple fragments at one time?
+ }
+
+
+ if(curPacket==0)
+ {
+ offset=4; // strip the "-1" at the front of the first packet
+ }
+
+ if(curPacket<MAX_PACKETS) // just in case...
+ {
+ m_CurPacket[curPacket].Clear(); // new packet, clear the buffer out
+ m_CurPacket[curPacket].WriteBuf(bytes-offset-sizeof(SPLITPACKET),&buffer[offset+sizeof(SPLITPACKET)]);
+ }
+
+ if(m_iCurrentPackets==m_iTotalPackets)
+ {
+
+ VCRHook_EnterCriticalSection((CRITICAL_SECTION *)m_pBufferCS);
+
+ // Get from address
+ netadr_t addr;
+ net->SockAddrToNetAdr( &from, &addr );
+
+ // append to the receive buffer
+ int idx = m_MsgBuffers.AddToTail();
+ CMsgBuffer &msgBuffer = m_MsgBuffers[idx];
+
+ msgBuffer.Clear();
+
+ // copy all our fragments together
+ for(int i=0;i<m_iTotalPackets;i++)
+ {
+ // buffer must be big enough for us to use, that is where the data originally came from :)
+ m_CurPacket[i].ReadBuf(m_CurPacket[i].GetCurSize(),buffer);
+ msgBuffer.WriteBuf(m_CurPacket[i].GetCurSize(),buffer);
+ }
+ msgBuffer.SetTime(recvTime);
+ msgBuffer.SetNetAddress(addr);
+
+ LeaveCriticalSection((CRITICAL_SECTION *)m_pBufferCS);
+
+ m_iTotalPackets = 0; // we have collected all the fragments for
+ //this packet, we can start on a new one now
+
+ }
+
+
+ }
+ else if ( *(int *)&buffer[0] == -1 ) // Must have 255,255,255,255 oob tag
+ {
+ /*
+ // Fake packet loss
+ if ( rand() % 1000 < 200 )
+ return;
+ */
+
+ VCRHook_EnterCriticalSection((CRITICAL_SECTION *)m_pBufferCS);
+
+ // Get from address
+ netadr_t addr;
+ net->SockAddrToNetAdr( &from, &addr );
+
+ // append to the receive buffer
+ int idx = m_MsgBuffers.AddToTail();
+ CMsgBuffer &msgBuffer = m_MsgBuffers[idx];
+
+ // Copy payload minus the -1 tag
+ msgBuffer.Clear();
+ msgBuffer.WriteBuf( bytes - 4, &buffer[ 4 ] );
+ msgBuffer.SetTime(recvTime);
+ msgBuffer.SetNetAddress(addr);
+
+ LeaveCriticalSection((CRITICAL_SECTION *)m_pBufferCS);
+ }
+
+ return true;
+}
diff --git a/tracker/common/Socket.h b/tracker/common/Socket.h
new file mode 100644
index 0000000..8ff4569
--- /dev/null
+++ b/tracker/common/Socket.h
@@ -0,0 +1,162 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+#if !defined( SOCKET_H )
+#define SOCKET_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "netadr.h"
+#include "MsgBuffer.h"
+#include "utlvector.h"
+
+#include <stdio.h>
+
+class CMsgBuffer;
+class CSocket;
+class IGameList;
+
+// Use this to pick apart the network stream, must be packed
+#pragma pack(1)
+typedef struct
+{
+ int netID;
+ int sequenceNumber;
+ char packetID;
+} SPLITPACKET;
+#pragma pack()
+
+#define MAX_PACKETS 16 // 4 bits for the packet count, so only
+#define MAX_RETRIES 2 // the number of fragments from other packets to drop before we declare the outstanding
+ // fragment lost :)
+
+//-----------------------------------------------------------------------------
+// Purpose: Instances a message handler for incoming messages.
+//-----------------------------------------------------------------------------
+class CMsgHandler
+{
+public:
+ enum
+ {
+ MAX_HANDLER_STRING = 64
+ };
+
+ typedef enum
+ {
+ MSGHANDLER_ALL = 0,
+ MSGHANDLER_BYTECODE,
+ MSGHANDLER_STRING
+ } HANDLERTYPE;
+
+ // Construction
+ CMsgHandler( HANDLERTYPE type, void *typeinfo = 0 );
+ virtual ~CMsgHandler( void );
+
+ // Message received, process it
+ virtual bool Process( netadr_t *from, CMsgBuffer *msg ) = 0;
+
+ // For linking togethr handler chains
+ virtual CMsgHandler *GetNext( void ) const;
+ virtual void SetNext( CMsgHandler *next );
+
+ // Access/set associated socket
+ virtual CSocket *GetSocket( void ) const;
+ virtual void SetSocket( CSocket *socket );
+
+private:
+ // Internal message received, crack type info and check it before calling process
+ bool ProcessMessage( netadr_t *from, CMsgBuffer *msg );
+
+ // Opaque pointer to underlying recipient class
+ IGameList *m_pBaseObject;
+
+ // Next handler in chain
+ HANDLERTYPE m_Type;
+ unsigned char m_ByteCode;
+ char m_szString[ MAX_HANDLER_STRING ];
+
+ // Next handler in chain
+ CMsgHandler *m_pNext;
+ // Associated socket
+ CSocket *m_pSocket;
+
+ friend CSocket;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a non-blocking, broadcast capable, UDP socket. If port is
+// specified, binds it to listen on that port, otherwise, chooses a random port.
+//-----------------------------------------------------------------------------
+class CSocket
+{
+public:
+ // Construction/destruction
+ CSocket( const char *socketname, int port = -1 );
+ virtual ~CSocket( void );
+
+ // Adds the message hander to the head of the sockets handler chain
+ virtual void AddMessageHandler( CMsgHandler *handler );
+ // Removes the specified message handler
+ virtual void RemoveMessageHandler( CMsgHandler *handler );
+
+ // Send the message to the recipient, if msg == NULL, use the internal message buffer
+ virtual int SendMessage( netadr_t *to, CMsgBuffer *msg = NULL );
+ // Broadcast the message on the specified port, if msg == NULL use the internal message buffer
+ virtual int Broadcast( int port, CMsgBuffer *msg = NULL );
+ // Get access to the internal message buffer
+ virtual CMsgBuffer *GetSendBuffer( void );
+ // Called once per frame to check for new data
+ virtual void Frame( void );
+ // Check whether the socket was created and set up properly
+ virtual bool IsValid( void ) const;
+ // Get the address this socket is bound to
+ virtual const netadr_t *GetAddress( void );
+
+ // Allow creating object to store a 32 bit value and retrieve it
+ virtual void SetUserData( unsigned int userData );
+ virtual unsigned int GetUserData(void ) const;
+
+ // Allow other objects to get the raw socket interger
+ virtual int GetSocketNumber( void ) const;
+ // Called when FD_ISSET noted that the socket has incoming data
+ virtual bool ReceiveData( void );
+ // Called to get current time
+ static float GetClock( void );
+
+private:
+ const char *m_pSocketName;
+ // Socket listen address
+ bool m_bValid;
+ // Socket IP address
+ netadr_t m_Address;
+ // Has the IP address been resolved
+ bool m_bResolved;
+ // Internal message buffers
+ CUtlVector<CMsgBuffer> m_MsgBuffers;
+ CMsgBuffer m_SendBuffer;
+ // critical section for accessing buffers
+ void *m_pBufferCS;
+ // One or more listeners for the incoming message
+ CMsgHandler *m_pMessageHandlers;
+ // Winsock socket number
+ int m_Socket;
+ // User 32 bit value
+ unsigned int m_nUserData;
+ // Socket to which non Broadcast SendMessage was directed. The socket will wait for a response
+ // from that exact address
+ netadr_t m_ToAddress;
+ // Set to true if the send was a Broadcast, and therefore from != to address is okay
+ bool m_bBroadcastSend;
+
+ int m_iTotalPackets; // total number of packets in a fragment
+ int m_iCurrentPackets; // current packet count
+ int m_iSeqNo; // the sequence number of the packet
+ int m_iRetries;
+ CMsgBuffer m_CurPacket[MAX_PACKETS]; // store for the packet
+};
+
+#endif // SOCKET_H \ No newline at end of file
diff --git a/tracker/common/TrackerMessageFlags.h b/tracker/common/TrackerMessageFlags.h
new file mode 100644
index 0000000..445679c
--- /dev/null
+++ b/tracker/common/TrackerMessageFlags.h
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef TRACKERMESSAGEFLAGS_H
+#define TRACKERMESSAGEFLAGS_H
+#pragma once
+
+//-----------------------------------------------------------------------------
+// Purpose: the set of flags that can modify a message
+//-----------------------------------------------------------------------------
+enum TrackerMessageFlags_e
+{
+ MESSAGEFLAG_SYSTEM = 1<<2, // message is from the tracker system
+ MESSAGEFLAG_MARKETING = 1<<3, // message is from the tracker system
+};
+
+
+#endif // TRACKERMESSAGEFLAGS_H
diff --git a/tracker/common/TrackerProtocol.h b/tracker/common/TrackerProtocol.h
new file mode 100644
index 0000000..3a63433
--- /dev/null
+++ b/tracker/common/TrackerProtocol.h
@@ -0,0 +1,161 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Holds all the protocol bits and defines used in tracker networking
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef TRACKERPROTOCOL_H
+#define TRACKERPROTOCOL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+// failed return versions of the messages are the TMSG_FAIL_OFFSET + 10000
+#define TMSG_FAIL_OFFSET 10000
+
+//-----------------------------------------------------------------------------
+// Purpose: List of all the tracker messages used
+// msgID's are 32bits big
+//-----------------------------------------------------------------------------
+enum TrackerMsgID_t
+{
+ // generic messages
+ TMSG_NONE = 0, // no message id
+ TMSG_ACK = 1, // packet acknowledgement
+
+ // server -> Client messages
+ TSVC_BASE = 1000,
+
+ TSVC_CHALLENGE,
+ TSVC_LOGINOK,
+ TSVC_LOGINFAIL,
+ TSVC_DISCONNECT,
+ TSVC_FRIENDS,
+ TSVC_FRIENDUPDATE,
+ TSVC_HEARTBEAT,
+ TSVC_PINGACK, // acknowledgement of TCLS_PING packet
+ TSVC_FRIENDINFO,
+ TSVC_USERVALID,
+ TSVC_FRIENDSFOUND,
+ TSVC_NOFRIENDS,
+ TSVC_MESSAGE, // message passed through from another client
+ TSVC_GAMEINFO, // information about a friends' game
+ TSVC_AUTHREQUEST, // a user requesting auth from the receiving user
+ TSVC_CONNECTIONKEEPALIVE, // information that an attemption connect is taking time, and the user should wait
+ TSVC_ROUTEMESSAGEFAILED, // chat message failed to be routed through the servers
+ TSVC_REDIRECTLOGIN, // tells the client to redirect their login attempt to a different server
+
+ // Client -> server messages
+ TCLS_BASE = 2000,
+
+ TCLS_LOGIN, // login message
+ TCLS_RESPONSE, // response to login challenge
+ TCLS_PING,
+ TCLS_FRIENDSEARCH,
+ TCLS_HEARTBEAT,
+ TCLS_AUTHUSER,
+ TCLS_REQAUTH,
+ TCLS_FRIENDINFO, // friend info request
+ TCLS_SETINFO,
+ TCLS_ROUTETOFRIEND, // generic reroute of a message to a friend
+
+ // Client -> Client messages
+ TCL_BASE = 3000,
+ TCL_MESSAGE, // chat text message
+ TCL_USERBLOCK, // soon to be obselete
+ TCL_ADDEDTOCHAT,
+ TCL_CHATADDUSER,
+ TCL_CHATUSERLEAVE,
+ TCL_TYPINGMESSAGE,
+ TCL_FRIENDNETMESSAGE,
+
+ // server -> server messages
+ TSV_BASE = 4000,
+
+ TSV_WHOISPRIMARY,
+ TSV_PRIMARYSRV,
+ TSV_REQUESTINFO,
+ TSV_TOPOLOGYINFO,
+ TSV_REQUESTTOPOLOGYINFO,
+ TSV_SERVERPING,
+ TSV_MONITORINFO,
+ TSV_LOCKUSERRANGE,
+ TSV_UNLOCKUSERRANGE,
+ TSV_REDIRECTTOUSER,
+ TSV_FORCEDISCONNECTUSER,
+ TSV_USERCHECKMESSAGES,
+ TSV_USERAUTHREQUEST,
+ TSV_USERSTATUSCHANGED,
+ TSV_USERRELOADFRIENDSLIST,
+ TSV_REGISTERSERVERINNETWORK,
+ TSV_SERVERSHUTTINGDOWN,
+ TSV_UPDATEACTIVEUSERRANGESTATUS,
+
+ // game server -> Client
+ TCLG_BASE = 5000,
+
+ // common msg failed ID's
+ TSVC_HEARTBEAT_FAIL = TSVC_HEARTBEAT + TMSG_FAIL_OFFSET,
+
+ TCLS_HEARTBEAT_FAIL = TCLS_HEARTBEAT + TMSG_FAIL_OFFSET,
+
+ TCL_MESSAGE_FAIL = TCL_MESSAGE + TMSG_FAIL_OFFSET,
+
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: List of reasons explaining to user why they have been disconnected
+// from the friends network
+//-----------------------------------------------------------------------------
+enum TrackerLogoffReason_t
+{
+ TRACKER_LOGOFF_NOREASON,
+
+ // server reasons for disconnecting user
+ TRACKER_LOGOFF_LOGGEDINELSEWHERE, // user has logged into friends at a different location
+ TRACKER_LOGOFF_SERVERWORK, // server needs to do work (like lock the user range)
+ TRACKER_LOGOFF_SERVERSHUTDOWN, // server has been shutdown
+ TRACKER_LOGOFF_TIMEDOUT, // user hasn't heartbeat'd to server recently enough
+ TRACKER_LOGOFF_REQUESTED, // user has requested to logoff
+ TRACKER_LOGOFF_FIREWALL, // users' firewall won't allow enough packets through
+ TRACKER_LOGOFF_NOTCONNECTED, // user sent server a packet that implied they think they're logged in but they're not
+ TRACKER_LOGOFF_INVALIDSTEAMTICKET, // users steam ticket is invalid
+
+ // client reasons for being disconnected
+ TRACKER_LOGOFF_JOINEDGAME, // user has logged off because they joined a game
+ TRACKER_LOGOFF_CONNECTIONTIMEOUT, // user connection has timed out
+ TRACKER_LOGOFF_SERVERMESSAGEFAIL, // a message to the server was not successfully transmitted
+
+ TRACKER_LOGOFF_TOOMANYATTEMPTS, // too many login attempts have been performed
+ TRACKER_LOGOFF_OFFLINE, // steam is in offline mode so don't try to connect
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: List of all the reasons a login attempt may fail
+//-----------------------------------------------------------------------------
+enum TrackerLoginFailReason_t
+{
+ TRACKER_LOGINFAIL_NOREASON = 0,
+ TRACKER_LOGINFAIL_NOSUCHUSER = -2,
+ TRACKER_LOGINFAIL_ALREADLOGGEDIN = -3,
+ TRACKER_LOGINFAIL_INVALIDSTEAMTICKET = -4,
+ TRACKER_LOGINFAIL_BUILDOUTOFDATE = -5,
+ TRACKER_LOGINFAIL_PLATFORMOUTOFDATE = -6,
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Holds basic status for a friend
+//-----------------------------------------------------------------------------
+struct FriendStatus_t
+{
+ unsigned int friendID;
+ int status;
+ unsigned int sessionID;
+ unsigned int ip;
+ unsigned int port;
+ unsigned int serverID;
+};
+
+#endif // TRACKERPROTOCOL_H
diff --git a/tracker/common/UtlMsgBuffer.cpp b/tracker/common/UtlMsgBuffer.cpp
new file mode 100644
index 0000000..b547d6a
--- /dev/null
+++ b/tracker/common/UtlMsgBuffer.cpp
@@ -0,0 +1,332 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "UtlMsgBuffer.h"
+
+#include <string.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: bitfields for use in variable descriptors
+//-----------------------------------------------------------------------------
+enum
+{
+ PACKBIT_CONTROLBIT = 0x01, // this must always be set
+ PACKBIT_INTNAME = 0x02, // if this is set then it's an int named variable, instead of a string
+ PACKBIT_BINARYDATA = 0x04, // signifies the data in this variable is binary, it's not a string
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CUtlMsgBuffer::CUtlMsgBuffer(unsigned short msgID, int initialSize) : m_Memory(0, initialSize)
+{
+ m_iMsgID = msgID;
+ m_iWritePos = 0;
+ m_iReadPos = 0;
+ m_iNextVarPos = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor, takes initial data
+//-----------------------------------------------------------------------------
+CUtlMsgBuffer::CUtlMsgBuffer(unsigned short msgID, void const *data, int dataSize) : m_Memory(0, dataSize)
+{
+ m_iMsgID = msgID;
+ m_iWritePos = (short)dataSize;
+ m_iReadPos = 0;
+ m_iNextVarPos = 0;
+
+ memcpy(Base(), data, dataSize);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CUtlMsgBuffer::~CUtlMsgBuffer()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Copy
+//-----------------------------------------------------------------------------
+CUtlMsgBuffer &CUtlMsgBuffer::Copy(const CUtlMsgBuffer &rhs)
+{
+ m_iWritePos = rhs.m_iWritePos;
+ m_iReadPos = rhs.m_iReadPos;
+ m_iNextVarPos = rhs.m_iNextVarPos;
+
+ m_Memory.EnsureCapacity(rhs.m_Memory.NumAllocated());
+ if ( rhs.m_Memory.NumAllocated() > 0 )
+ {
+ memcpy(Base(), rhs.Base(), rhs.m_Memory.NumAllocated());
+ }
+ return *this;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes string data to the message
+// Input : *name - name of the variable
+// *data - pointer to the string data to write
+//-----------------------------------------------------------------------------
+void CUtlMsgBuffer::WriteString(const char *name, const char *data)
+{
+ // write out the variable type
+ unsigned char vtype = PACKBIT_CONTROLBIT; // stringname var, string data
+ Write(&vtype, 1);
+
+ // write out the variable name
+ Write(name, strlen(name) + 1);
+
+ // write out the size of the data
+ unsigned short size = (unsigned short)(strlen(data) + 1);
+ Write(&size, 2);
+
+ // write out the data itself
+ Write(data, size);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes out a named block of data
+//-----------------------------------------------------------------------------
+void CUtlMsgBuffer::WriteBlob(const char *name, const void *data, int dataSize)
+{
+ // write out the variable type
+ unsigned char vtype = PACKBIT_CONTROLBIT | PACKBIT_BINARYDATA; // stringname var, binary data
+ Write(&vtype, 1);
+
+ // write out the variable name
+ Write(name, strlen(name) + 1);
+
+ // write out the size of the data
+ unsigned short size = (unsigned short)dataSize;
+ Write(&size, 2);
+
+ // write out the data itself
+ Write(data, dataSize);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes out another UtlMsgBuffer as an element of this one
+//-----------------------------------------------------------------------------
+void CUtlMsgBuffer::WriteBuffer(const char *name, const CUtlMsgBuffer *buffer)
+{
+ // write out the variable type
+ unsigned char vtype = PACKBIT_CONTROLBIT | PACKBIT_BINARYDATA; // stringname var, binary data
+ Write(&vtype, 1);
+
+ // write out the variable name
+ Write(name, strlen(name) + 1);
+
+ // write out the size of the data
+ unsigned short size = (unsigned short) buffer->DataSize();
+ Write(&size, 2);
+
+ // write out the data itself
+ Write(buffer->Base(), size);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads from the buffer, increments read position
+// returns false if past end of buffer
+//-----------------------------------------------------------------------------
+bool CUtlMsgBuffer::Read(void *buffer, int readAmount)
+{
+ if (m_iReadPos + readAmount >= m_iWritePos)
+ return false;
+
+ memcpy(buffer, &m_Memory[m_iReadPos], readAmount);
+ m_iReadPos += readAmount;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads characterse from the buffer until a null is hit
+//-----------------------------------------------------------------------------
+bool CUtlMsgBuffer::ReadUntilNull(void *buffer, int bufferSize)
+{
+ int nullPos = m_iReadPos;
+
+ // look through the buffer for the null terminator
+ while (nullPos < m_Memory.NumAllocated() && m_Memory[nullPos] != 0)
+ {
+ nullPos++;
+ }
+
+ if (nullPos >= m_Memory.NumAllocated())
+ {
+ // never found a null terminator
+ ((char *)buffer)[0] = 0;
+ return false;
+ }
+
+ // copy from the null terminator
+ int copySize = nullPos - m_iReadPos;
+ if (copySize > bufferSize)
+ {
+ copySize = bufferSize - 1;
+ }
+
+ // copy out the data and return
+ memcpy(buffer, &m_Memory[m_iReadPos], copySize);
+ ((char *)buffer)[copySize] = 0;
+ m_iReadPos += (copySize+1);
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes to the buffer, incrementing the write position
+// assumes enough space has already been allocated for the write
+//-----------------------------------------------------------------------------
+void CUtlMsgBuffer::Write(void const *data, int size)
+{
+ // make sure it will fit
+ m_Memory.EnsureCapacity(m_iWritePos + size);
+
+ // normal write
+ memcpy(&m_Memory[m_iWritePos], data, size);
+
+ // increment write position
+ m_iWritePos += size;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads in a named variable length data blob
+// returns number of bytes read, 0 on failure
+//-----------------------------------------------------------------------------
+int CUtlMsgBuffer::ReadBlob(const char *name, void *data, int dataBufferSize)
+{
+ int dataSize = 0;
+ char *readData = (char *)FindVar(name, dataSize);
+ if (!readData)
+ {
+ memset(data, 0, dataBufferSize);
+ return 0;
+ }
+
+ // ensure against buffer overflow
+ if (dataSize > dataBufferSize)
+ dataSize = dataBufferSize;
+
+ // copy out data
+ memcpy(data, readData, dataSize);
+ return dataSize;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads a blob of binary data into it's own buffer
+//-----------------------------------------------------------------------------
+bool CUtlMsgBuffer::ReadBuffer(const char *name, CUtlMsgBuffer &buffer)
+{
+ int dataSize = 0;
+ char *readData = (char *)FindVar(name, dataSize);
+ if (!readData)
+ {
+ return false;
+ }
+
+ buffer.m_Memory.EnsureCapacity(dataSize);
+ memcpy(&buffer.m_Memory[0], readData, dataSize);
+ buffer.m_iReadPos = 0;
+ buffer.m_iWritePos = (short)dataSize;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: reads out the next variable available in the buffer
+// fills out parameters with var details and data
+// returns false if no more vars available
+//-----------------------------------------------------------------------------
+bool CUtlMsgBuffer::ReadNextVar(char varname[32], bool &stringData, void *data, int &dataSize)
+{
+ // read the type
+ unsigned char vtype = 1;
+ if (!Read(&vtype, 1))
+ return false;
+
+ // check for null-termination type
+ if (vtype == 0)
+ return false;
+
+ stringData = !(vtype & PACKBIT_BINARYDATA);
+
+ // read the variable name
+ if (!ReadUntilNull(varname, 31))
+ return false;
+
+ // read the data size
+ unsigned short size = 0;
+ if (!Read(&size, 2))
+ return false;
+
+ // ensure against buffer overflows
+ if (dataSize > size)
+ dataSize = size;
+
+ // copy data
+ memcpy(data, &m_Memory[m_iReadPos], dataSize);
+
+ // store of the next position, since that is probably where the next read needs to occur
+ m_iReadPos += size;
+ m_iNextVarPos = m_iReadPos;
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the read/write position to be at the specified variable
+// returns pointer to buffer position on success, NULL if not found
+//-----------------------------------------------------------------------------
+void *CUtlMsgBuffer::FindVar(const char *name, int &dataSize)
+{
+ // reset to where we Think the next var will be read from
+ m_iReadPos = m_iNextVarPos;
+ int loopCount = 2;
+
+ // loop through looking for the specified variable
+ while (loopCount--)
+ {
+ unsigned char vtype = 1;
+ while (Read(&vtype, 1))
+ {
+ // check for null-termination type
+ if (vtype == 0)
+ break;
+
+ // read the variable name
+ char varname[32];
+ if (!ReadUntilNull(varname, 31))
+ break;
+
+ // read the data size
+ unsigned short size = 0;
+ if (!Read(&size, 2))
+ break;
+
+ // is this our variable?
+ if (!stricmp(varname, name))
+ {
+ dataSize = size;
+ void *data = &m_Memory[m_iReadPos];
+
+ // store of the next position, since that is probably where the next read needs to occur
+ m_iReadPos += size;
+ m_iNextVarPos = m_iReadPos;
+ return data;
+ }
+
+ // skip over the data block to the next variable
+ m_iReadPos += size;
+ if (m_iReadPos >= m_iWritePos)
+ break;
+ }
+
+ // we haven't found the data yet, Start again
+ m_iReadPos = 0;
+ }
+
+ return NULL;
+}
diff --git a/tracker/common/UtlMsgBuffer.h b/tracker/common/UtlMsgBuffer.h
new file mode 100644
index 0000000..1b4a818
--- /dev/null
+++ b/tracker/common/UtlMsgBuffer.h
@@ -0,0 +1,198 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Generic named data buffer, declaration and implementation
+//
+//=============================================================================
+
+#ifndef UTLMSGBUFFER_H
+#define UTLMSGBUFFER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "UtlMemory.h"
+
+#pragma warning(disable: 4244) // warning C4244: '=' : conversion from 'int' to 'short', possible loss of data
+
+//-----------------------------------------------------------------------------
+// Purpose: Generic named data buffer
+//-----------------------------------------------------------------------------
+class CUtlMsgBuffer
+{
+public:
+ CUtlMsgBuffer(unsigned short msgID, int initialSize);
+ CUtlMsgBuffer(unsigned short msgID, void const *data, int dataSize);
+ ~CUtlMsgBuffer();
+
+ unsigned short GetMsgID() const { return m_iMsgID; }
+ void SetMsgID(unsigned short msgID) { m_iMsgID = msgID; }
+
+ // read functions
+ bool ReadInt(const char *name, int &data);
+ bool ReadUInt(const char *name, unsigned int &data);
+ bool ReadString(const char *name, char *data, int dataBufferSize);
+ bool ReadBuffer(const char *name, CUtlMsgBuffer &buffer);
+ // returns number of bytes read, 0 on failure
+ int ReadBlob(const char *name, void *data, int dataBufferSize);
+
+ // reads out the next variable available in the buffer
+ // fills out parameters with var details and data
+ // returns false if no more vars available
+ bool ReadNextVar(char name[32], bool &stringData, void *data, int &dataSize);
+
+ // write functions
+ void WriteInt(const char *name, int data);
+ void WriteUInt(const char *name, unsigned int data);
+ void WriteString(const char *name, const char *data);
+ void WriteBlob(const char *name, const void *data, int dataSize);
+ void WriteBuffer(const char *name, const CUtlMsgBuffer *buffer);
+
+ // returns a pointer to the data buffer, and its size, of the specified variable
+ void *FindVar(const char *name, int &dataSizeOut);
+
+ // pads the buffer to the specified boundary (in bytes)
+ void PadBuffer(int boundary);
+
+ // makes sure the message has this much space allocated
+ void EnsureCapacity(int dataSize);
+
+ // returns the number of bytes used by the message
+ int DataSize() const;
+
+ // returns a pointer to the base data
+ void *Base();
+
+ // returns a const pointer to the base data
+ const void *Base() const;
+
+ // advances the write pointer - used when you write directly into the buffer
+ void SetWritePos(int size);
+
+ CUtlMsgBuffer& Copy(const CUtlMsgBuffer &rhs);
+
+ // copy constructor
+ CUtlMsgBuffer(const CUtlMsgBuffer &rhs)
+ {
+ m_iMsgID = rhs.m_iMsgID;
+ m_iWritePos = rhs.m_iWritePos;
+ m_iReadPos = rhs.m_iReadPos;
+ m_iNextVarPos = rhs.m_iNextVarPos;
+
+ m_Memory.EnsureCapacity(rhs.m_Memory.NumAllocated());
+ if ( rhs.m_Memory.NumAllocated() > 0 )
+ {
+ memcpy(Base(), rhs.Base(), rhs.m_Memory.NumAllocated());
+ }
+ }
+
+private:
+
+ bool Read(void *buffer, int readAmount);
+ bool ReadUntilNull(void *buffer, int bufferSize);
+ void Write(void const *data, int size);
+
+ CUtlMemory<char> m_Memory;
+
+ unsigned short m_iMsgID;
+ short m_iWritePos; // position in buffer we are currently writing to
+ short m_iReadPos; // current reading position
+ short m_iNextVarPos; // a guess at which variable is most likely to be read next
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the number of bytes used by the message
+//-----------------------------------------------------------------------------
+inline int CUtlMsgBuffer::DataSize() const
+{
+ // return the highest read/write mark
+ if (m_iWritePos > m_iReadPos)
+ return m_iWritePos;
+
+ return m_iReadPos;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a pointer to the base data
+//-----------------------------------------------------------------------------
+inline void *CUtlMsgBuffer::Base()
+{
+ return &m_Memory[0];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a pointer to the base data
+//-----------------------------------------------------------------------------
+inline const void *CUtlMsgBuffer::Base() const
+{
+ return &m_Memory[0];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: ensures capacity
+//-----------------------------------------------------------------------------
+inline void CUtlMsgBuffer::EnsureCapacity(int dataSize)
+{
+ m_Memory.EnsureCapacity(dataSize);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: pads the buffer to the specified boundary (in bytes)
+//-----------------------------------------------------------------------------
+inline void CUtlMsgBuffer::PadBuffer(int boundary)
+{
+ // pad the buffer to be the right size for encryption
+ int pad = (boundary - (DataSize() % boundary));
+ Write("\0\0\0\0\0\0\0\0\0\0\0\0", pad);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads in a named 4-byte int, returns true on sucess, false on failure
+//-----------------------------------------------------------------------------
+inline bool CUtlMsgBuffer::ReadInt(const char *name, int &data)
+{
+ return (ReadBlob(name, &data, 4) == 4);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads in a named 4-byte unsigned int, returns true on sucess, false on failure
+//-----------------------------------------------------------------------------
+inline bool CUtlMsgBuffer::ReadUInt(const char *name, unsigned int &data)
+{
+ return (ReadBlob(name, &data, 4) == 4);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads in a named variable length character string
+// returns true on sucess, false on failure
+//-----------------------------------------------------------------------------
+inline bool CUtlMsgBuffer::ReadString(const char *name, char *data, int dataBufferSize)
+{
+ return (ReadBlob(name, data, dataBufferSize) > 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes out an integer to the message
+//-----------------------------------------------------------------------------
+inline void CUtlMsgBuffer::WriteInt(const char *name, int data)
+{
+ WriteBlob(name, &data, 4);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes out an unsigned integer to the message
+//-----------------------------------------------------------------------------
+inline void CUtlMsgBuffer::WriteUInt(const char *name, unsigned int data)
+{
+ WriteBlob(name, &data, 4);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+inline void CUtlMsgBuffer::SetWritePos(int size)
+{
+ m_iWritePos = size;
+}
+
+
+#endif // UTLMSGBUFFER_H
diff --git a/tracker/common/inetapi.h b/tracker/common/inetapi.h
new file mode 100644
index 0000000..dfc4d35
--- /dev/null
+++ b/tracker/common/inetapi.h
@@ -0,0 +1,42 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+#if !defined( INETAPI_H )
+#define INETAPI_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "netadr.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Internal winsock helpers for launcher
+//-----------------------------------------------------------------------------
+class INetAPI
+{
+public:
+ // Convert a netadr_t to sockaddr
+ virtual void NetAdrToSockAddr( netadr_t *a, struct sockaddr *s ) = 0;
+ // Convert a sockaddr to netadr_t
+ virtual void SockAddrToNetAdr( struct sockaddr *s, netadr_t *a ) = 0;
+
+ // Convert a netadr_t to a string
+ virtual char *AdrToString( netadr_t *a ) = 0;
+ // Convert a string address to a netadr_t, doing DNS if needed
+ virtual bool StringToAdr( const char *s, netadr_t *a ) = 0;
+ // Look up IP address for socket
+ virtual void GetSocketAddress( int socket, netadr_t *a ) = 0;
+
+ virtual bool CompareAdr( netadr_t *a, netadr_t *b ) =0;
+
+ // return the IP of the local host
+ virtual void GetLocalIP(netadr_t *a)=0;
+
+};
+
+extern INetAPI *net;
+
+#endif // INETAPI_H \ No newline at end of file
diff --git a/tracker/common/msgbuffer.cpp b/tracker/common/msgbuffer.cpp
new file mode 100644
index 0000000..7bd576a
--- /dev/null
+++ b/tracker/common/msgbuffer.cpp
@@ -0,0 +1,421 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+#include <string.h>
+#include <assert.h>
+#include "msgbuffer.h"
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+#pragma warning(disable: 4244) // warning C4244: '=' : conversion from 'int' to 'unsigned char', possible loss of data
+
+//-----------------------------------------------------------------------------
+// Purpose: Allocate message buffer
+// Input : *buffername -
+// *ef -
+//-----------------------------------------------------------------------------
+CMsgBuffer::CMsgBuffer( const char *buffername, void (*ef)( const char *fmt, ... ) /*= NULL*/ )
+{
+ m_pszBufferName = buffername;
+ m_pfnErrorFunc = ef;
+ m_bAllowOverflow = false; // if false, Error
+ m_bOverFlowed = false; // set to true if the buffer size failed
+ m_nMaxSize = NET_MAXMESSAGE;
+ m_nPushedCount = 0;
+ m_bPushed = false;
+ m_nReadCount = 0;
+ m_bBadRead = false;
+
+ Clear();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMsgBuffer::~CMsgBuffer( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Temporarily remember the read position so we can reset it
+//-----------------------------------------------------------------------------
+void CMsgBuffer::Push( void )
+{
+ // ??? Allow multiple pushes without matching pops ???
+ assert( !m_bPushed );
+
+ m_nPushedCount = m_nReadCount;
+ m_bPushed = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMsgBuffer::Pop( void )
+{
+ assert( m_bPushed );
+
+ m_nReadCount = m_nPushedCount;
+ m_bPushed = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : allowed -
+//-----------------------------------------------------------------------------
+void CMsgBuffer::SetOverflow( bool allowed )
+{
+ m_bAllowOverflow = allowed;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CMsgBuffer::GetMaxSize( void )
+{
+ return m_nMaxSize;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : void *
+//-----------------------------------------------------------------------------
+void * CMsgBuffer::GetData( void )
+{
+ return m_rgData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CMsgBuffer::GetCurSize( void )
+{
+ return m_nCurSize;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CMsgBuffer::GetReadCount( void )
+{
+ return m_nReadCount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void CMsgBuffer::SetTime(float time)
+{
+ m_fRecvTime = time;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+float CMsgBuffer::GetTime()
+{
+ return m_fRecvTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+void CMsgBuffer::SetNetAddress(netadr_t &adr)
+{
+ m_NetAddr = adr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+netadr_t &CMsgBuffer::GetNetAddress()
+{
+ return m_NetAddr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMsgBuffer::WriteByte( int c )
+{
+ unsigned char *buf;
+ buf = (unsigned char *)GetSpace( 1 );
+ buf[0] = c;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : c -
+//-----------------------------------------------------------------------------
+void CMsgBuffer::WriteShort ( int c )
+{
+ unsigned char *buf;
+ buf = (unsigned char *)GetSpace( 2 );
+ buf[0] = c&0xff;
+ buf[1] = c>>8;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : c -
+//-----------------------------------------------------------------------------
+void CMsgBuffer::WriteLong (int c)
+{
+ unsigned char *buf;
+
+ buf = (unsigned char *)GetSpace( 4 );
+ buf[0] = c&0xff;
+ buf[1] = (c>>8)&0xff;
+ buf[2] = (c>>16)&0xff;
+ buf[3] = c>>24;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : f -
+//-----------------------------------------------------------------------------
+void CMsgBuffer::WriteFloat (float f)
+{
+ union
+ {
+ float f;
+ int l;
+ } dat;
+
+ dat.f = f;
+ Write( &dat.l, 4 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *s -
+//-----------------------------------------------------------------------------
+void CMsgBuffer::WriteString (const char *s)
+{
+ if ( !s )
+ {
+ Write ("", 1);
+ }
+ else
+ {
+ Write ( s, strlen( s ) + 1 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : iSize -
+// *buf -
+//-----------------------------------------------------------------------------
+void CMsgBuffer::WriteBuf( int iSize, void *buf )
+{
+ if ( !buf )
+ {
+ return;
+ }
+
+ Write( buf, iSize );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMsgBuffer::BeginReading (void)
+{
+ m_nReadCount = 0;
+ m_bBadRead = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int CMsgBuffer::ReadByte
+//-----------------------------------------------------------------------------
+int CMsgBuffer::ReadByte (void)
+{
+ int c;
+
+ if ( m_nReadCount + 1 > m_nCurSize )
+ {
+ m_bBadRead = true;
+ return -1;
+ }
+
+ c = ( unsigned char )m_rgData[ m_nReadCount ];
+ m_nReadCount++;
+ return c;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int CMsgBuffer::ReadShort
+//-----------------------------------------------------------------------------
+int CMsgBuffer::ReadShort (void)
+{
+ int c;
+
+ if ( m_nReadCount + 2 > m_nCurSize )
+ {
+ m_bBadRead = true;
+ return -1;
+ }
+
+ c = (short)(m_rgData[m_nReadCount] + (m_rgData[m_nReadCount+1]<<8));
+ m_nReadCount += 2;
+
+ return c;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int CMsgBuffer::ReadLong
+//-----------------------------------------------------------------------------
+int CMsgBuffer::ReadLong (void)
+{
+ int c;
+
+ if (m_nReadCount+4 > m_nCurSize)
+ {
+ m_bBadRead = true;
+ return -1;
+ }
+
+ c = m_rgData[m_nReadCount]
+ + (m_rgData[m_nReadCount+1]<<8)
+ + (m_rgData[m_nReadCount+2]<<16)
+ + (m_rgData[m_nReadCount+3]<<24);
+
+ m_nReadCount += 4;
+
+ return c;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float CMsgBuffer::ReadFloat
+//-----------------------------------------------------------------------------
+float CMsgBuffer::ReadFloat (void)
+{
+ union
+ {
+ unsigned char b[4];
+ float f;
+ } dat;
+
+ dat.b[0] = m_rgData[m_nReadCount];
+ dat.b[1] = m_rgData[m_nReadCount+1];
+ dat.b[2] = m_rgData[m_nReadCount+2];
+ dat.b[3] = m_rgData[m_nReadCount+3];
+ m_nReadCount += 4;
+ return dat.f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : iSize -
+// *pbuf -
+// Output : int
+//-----------------------------------------------------------------------------
+int CMsgBuffer::ReadBuf( int iSize, void *pbuf )
+{
+ if (m_nReadCount + iSize > m_nCurSize)
+ {
+ m_bBadRead = true;
+ return -1;
+ }
+
+ memcpy( pbuf, &m_rgData[m_nReadCount], iSize );
+ m_nReadCount += iSize;
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : char *
+//-----------------------------------------------------------------------------
+char *CMsgBuffer::ReadString (void)
+{
+ static char string[ NET_MAXMESSAGE ];
+ int l,c;
+
+ l = 0;
+ do
+ {
+ c = (char)ReadByte();
+ if ( c == -1 || c == 0 )
+ break;
+ string[l] = c;
+ l++;
+ } while ( l < sizeof(string)-1 );
+
+ string[ l ] = 0;
+
+ return string;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMsgBuffer::Clear( void )
+{
+ m_nCurSize = 0;
+ m_bOverFlowed = false;
+ m_nReadCount = 0;
+ m_bBadRead = false;
+ memset( m_rgData, 0, sizeof( m_rgData ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : length -
+//-----------------------------------------------------------------------------
+void *CMsgBuffer::GetSpace( int length )
+{
+ void *d;
+
+ if (m_nCurSize + length > m_nMaxSize)
+ {
+ if ( !m_bAllowOverflow )
+ {
+ if ( m_pfnErrorFunc )
+ {
+ ( *m_pfnErrorFunc )( "CMsgBuffer(%s), no room for %i bytes, %i / %i already in use\n",
+ m_pszBufferName, length, m_nCurSize, m_nMaxSize );
+ }
+ return NULL;
+ }
+
+ if (length > m_nMaxSize)
+ {
+ if ( m_pfnErrorFunc )
+ {
+ ( *m_pfnErrorFunc )( "CMsgBuffer(%s), no room for %i bytes, %i is max\n",
+ m_pszBufferName, length, m_nMaxSize );
+ }
+ return NULL;
+ }
+
+ m_bOverFlowed = true;
+ Clear();
+ }
+
+ d = m_rgData + m_nCurSize;
+ m_nCurSize += length;
+ return d;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *m_rgData -
+// length -
+//-----------------------------------------------------------------------------
+void CMsgBuffer::Write(const void *m_rgData, int length)
+{
+ memcpy( GetSpace(length), m_rgData, length );
+} \ No newline at end of file
diff --git a/tracker/common/msgbuffer.h b/tracker/common/msgbuffer.h
new file mode 100644
index 0000000..ac2bfd9
--- /dev/null
+++ b/tracker/common/msgbuffer.h
@@ -0,0 +1,108 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+#if !defined( MSGBUFFER_H )
+#define MSGBUFFER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "netadr.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Generic byte level message buffer with read/write support
+//-----------------------------------------------------------------------------
+class CMsgBuffer
+{
+public:
+ enum
+ {
+ NET_MAXMESSAGE = 8192
+ };
+
+ // Buffers must be named
+ CMsgBuffer( const char *buffername = "unnamed", void (*ef)( PRINTF_FORMAT_STRING const char *fmt, ... ) = 0 );
+ virtual ~CMsgBuffer( void );
+
+ // Reset the buffer for writing
+ void Clear( void );
+ // Get current # of bytes
+ int GetCurSize( void );
+ // Get max # of bytes
+ int GetMaxSize( void );
+ // Get pointer to raw data
+ void *GetData( void );
+ // Set/unset the allow overflow flag
+ void SetOverflow( bool allowed );
+ // Start reading from buffer
+ void BeginReading( void );
+ // Get current read byte
+ int GetReadCount( void );
+
+ // Push read count ( to peek at data )
+ void Push( void );
+ void Pop( void );
+
+ // Writing functions
+ void WriteByte(int c);
+ void WriteShort(int c);
+ void WriteLong(int c);
+ void WriteFloat(float f);
+ void WriteString(const char *s);
+ void WriteBuf( int iSize, void *buf );
+
+ // Reading functions
+ int ReadByte( void );
+ int ReadShort( void );
+ int ReadLong( void );
+ float ReadFloat( void );
+ char *ReadString( void );
+ int ReadBuf( int iSize, void *pbuf );
+
+ // setting and storing time received
+ void SetTime(float time);
+ float GetTime();
+
+ // net address received from
+ void SetNetAddress(netadr_t &adr);
+ netadr_t &GetNetAddress();
+
+private:
+ // Ensures sufficient space to append an object of length
+ void *GetSpace( int length );
+ // Copy buffer in at current writing point
+ void Write( const void *data, int length );
+
+private:
+ // Name of buffer in case of debugging/errors
+ const char *m_pszBufferName;
+ // Optional error callback
+ void ( *m_pfnErrorFunc )( PRINTF_FORMAT_STRING const char *fmt, ... );
+
+ // Current read pointer
+ int m_nReadCount;
+ // Push/pop read state
+ int m_nPushedCount;
+ bool m_bPushed;
+ // Did we hit the end of the read buffer?
+ bool m_bBadRead;
+ // Max size of buffer
+ int m_nMaxSize;
+ // Current bytes written
+ int m_nCurSize;
+ // if false, call m_pfnErrorFunc
+ bool m_bAllowOverflow;
+ // set to true when buffer hits end
+ bool m_bOverFlowed;
+ // Internal storage
+ unsigned char m_rgData[ NET_MAXMESSAGE ];
+ // time received
+ float m_fRecvTime;
+ // address received from
+ netadr_t m_NetAddr;
+};
+
+#endif // !MSGBUFFER_H \ No newline at end of file
diff --git a/tracker/common/netapi.cpp b/tracker/common/netapi.cpp
new file mode 100644
index 0000000..914f5f3
--- /dev/null
+++ b/tracker/common/netapi.cpp
@@ -0,0 +1,277 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+#include <stdio.h>
+#include <stdlib.h>
+#if defined( WIN32 )
+#if !defined( _X360 )
+#include "winsock.h"
+#else
+#include "winsockx.h"
+#endif
+#elif defined( POSIX )
+#include <sys/socket.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#else
+#error
+#endif
+#include "inetapi.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+#pragma warning(disable: 4706) // warning C4706: assignment within conditional expression
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements INetAPI
+//-----------------------------------------------------------------------------
+class CNetAPI : public INetAPI
+{
+public:
+ virtual void NetAdrToSockAddr( netadr_t *a, struct sockaddr *s );
+ virtual void SockAddrToNetAdr( struct sockaddr *s, netadr_t *a );
+
+ virtual char *AdrToString( netadr_t *a );
+ virtual bool StringToAdr( const char *s, netadr_t *a );
+
+ virtual void GetSocketAddress( int socket, netadr_t *a );
+
+ virtual bool CompareAdr( netadr_t *a, netadr_t *b );
+
+ virtual void GetLocalIP(netadr_t *a);
+};
+
+// Expose interface
+static CNetAPI g_NetAPI;
+INetAPI *net = ( INetAPI * )&g_NetAPI;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *a -
+// *s -
+//-----------------------------------------------------------------------------
+void CNetAPI::NetAdrToSockAddr (netadr_t *a, struct sockaddr *s)
+{
+ memset (s, 0, sizeof(*s));
+
+ if (a->type == NA_BROADCAST)
+ {
+ ((struct sockaddr_in *)s)->sin_family = AF_INET;
+ ((struct sockaddr_in *)s)->sin_port = a->port;
+ ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
+ }
+ else if (a->type == NA_IP)
+ {
+ ((struct sockaddr_in *)s)->sin_family = AF_INET;
+ ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
+ ((struct sockaddr_in *)s)->sin_port = a->port;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *s -
+// *a -
+//-----------------------------------------------------------------------------
+void CNetAPI::SockAddrToNetAdr( struct sockaddr *s, netadr_t *a )
+{
+ if (s->sa_family == AF_INET)
+ {
+ a->type = NA_IP;
+ *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
+ a->port = ((struct sockaddr_in *)s)->sin_port;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *a -
+// Output : char
+//-----------------------------------------------------------------------------
+char *CNetAPI::AdrToString( netadr_t *a )
+{
+ static char s[64];
+
+ memset(s, 0, 64);
+
+ if ( a )
+ {
+ if ( a->type == NA_LOOPBACK )
+ {
+ sprintf (s, "loopback");
+ }
+ else if ( a->type == NA_IP )
+ {
+ sprintf(s, "%i.%i.%i.%i:%i", a->ip[0], a->ip[1], a->ip[2], a->ip[3], ntohs( a->port ) );
+ }
+ }
+ return s;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *s -
+// *sadr -
+// Output : static bool
+//-----------------------------------------------------------------------------
+static bool StringToSockaddr( const char *s, struct sockaddr *sadr )
+{
+ struct hostent *h;
+ char *colon;
+ char copy[128];
+ struct sockaddr_in *p;
+
+ memset (sadr, 0, sizeof(*sadr));
+
+ p = ( struct sockaddr_in * )sadr;
+ p->sin_family = AF_INET;
+ p->sin_port = 0;
+
+ strcpy (copy, s);
+
+ // strip off a trailing :port if present
+ for ( colon = copy ; *colon ; colon++ )
+ {
+ if (*colon == ':')
+ {
+ // terminate
+ *colon = 0;
+ // Start at next character
+ p->sin_port = htons( ( short )atoi( colon + 1 ) );
+ }
+ }
+
+ // Numeric IP, no DNS
+ if ( copy[0] >= '0' && copy[0] <= '9' && strstr( copy, "." ) )
+ {
+ *(int *)&p->sin_addr = inet_addr( copy );
+ }
+ else
+ {
+ // DNS it
+ if ( !( h = gethostbyname( copy ) ) )
+ {
+ return false;
+ }
+ // Use first result
+ *(int *)&p->sin_addr = *(int *)h->h_addr_list[0];
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *s -
+// *a -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CNetAPI::StringToAdr( const char *s, netadr_t *a )
+{
+ struct sockaddr sadr;
+
+ if ( !strcmp ( s, "localhost" ) )
+ {
+ memset ( a, 0, sizeof( *a ) );
+ a->type = NA_LOOPBACK;
+ return true;
+ }
+
+ if ( !StringToSockaddr (s, &sadr) )
+ {
+ return false;
+ }
+
+ SockAddrToNetAdr( &sadr, a );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Lookup the IP address for the specified IP socket
+// Input : socket -
+// *a -
+//-----------------------------------------------------------------------------
+void CNetAPI::GetSocketAddress( int socket, netadr_t *a )
+{
+ char buff[512];
+ struct sockaddr_in address;
+ int namelen;
+// int net_error = 0;
+
+ memset( a, 0, sizeof( *a ) );
+ gethostname(buff, 512);
+ // Ensure that it doesn't overrun the buffer
+ buff[512-1] = 0;
+
+ StringToAdr(buff, a );
+
+ namelen = sizeof(address);
+ if ( getsockname( socket, (struct sockaddr *)&address, (int *)&namelen) == 0 )
+ {
+ a->port = address.sin_port;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Full IP address compare
+// Input : *a -
+// *b -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CNetAPI::CompareAdr( netadr_t *a, netadr_t *b )
+{
+ if ( a->type != b->type )
+ {
+ return false;
+ }
+
+ if ( a->type == NA_LOOPBACK )
+ {
+ return true;
+ }
+
+ if ( a->type == NA_IP &&
+ a->ip[0] == b->ip[0] &&
+ a->ip[1] == b->ip[1] &&
+ a->ip[2] == b->ip[2] &&
+ a->ip[3] == b->ip[3] &&
+ a->port == b->port )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Full IP address compare
+// Input : *a -
+// *b -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+
+void CNetAPI::GetLocalIP(netadr_t *a)
+{
+ char s[64];
+
+ if(!::gethostname(s,64))
+ {
+ struct hostent *localip = ::gethostbyname(s);
+ if(localip)
+ {
+ a->type=NA_IP;
+ a->port=0;
+ memcpy(a->ip,localip->h_addr_list[0],4);
+ }
+ }
+}
diff --git a/tracker/common/server.h b/tracker/common/server.h
new file mode 100644
index 0000000..9e510fe
--- /dev/null
+++ b/tracker/common/server.h
@@ -0,0 +1,51 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef SERVER_H
+#define SERVER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Data describing a single server
+//-----------------------------------------------------------------------------
+struct serveritem_t
+{
+ serveritem_t()
+ {
+ pings[0] = 0;
+ pings[1] = 0;
+ pings[2] = 0;
+ }
+
+ unsigned char ip[4];
+ int port;
+ int received;
+ float time;
+ int ping; // current ping time, derived from pings[]
+ int pings[3]; // last 3 ping times
+ bool hadSuccessfulResponse; // server has responded successfully in the past
+ bool doNotRefresh; // server is marked as not responding and should no longer be refreshed
+ char gameDir[32]; // current game directory
+ char map[32]; // current map
+ char gameDescription[64]; // game description
+ char name[64]; // server name
+ int players;
+ int maxPlayers;
+ int botPlayers;
+ bool proxy;
+ bool password;
+ unsigned int serverID;
+ int listEntryID;
+ char rconPassword[64]; // the rcon password for this server
+ bool loadedFromFile; // true if this entry was loaded from file rather than comming from the master
+};
+
+
+#endif // SERVER_H
diff --git a/tracker/common/util.cpp b/tracker/common/util.cpp
new file mode 100644
index 0000000..d28b1c7
--- /dev/null
+++ b/tracker/common/util.cpp
@@ -0,0 +1,70 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "util.h"
+#include <string.h>
+
+#define NUM_BUFFERS 4
+#define MAX_INFO_TOKEN_LENGTH 512
+const char *CUtil::InfoGetValue( const char *s, const char *key )
+{
+ char pkey[MAX_INFO_TOKEN_LENGTH];
+ // Use multiple buffers so compares
+ // work without stomping on each other
+ static char value[NUM_BUFFERS][MAX_INFO_TOKEN_LENGTH];
+ static int valueindex;
+ char *o;
+
+ valueindex = (valueindex + 1) % NUM_BUFFERS;
+
+ if (*s == '\\')
+ s++;
+ while (1)
+ {
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return "";
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value[valueindex];
+
+ while (*s != '\\' && *s)
+ {
+ if (!*s)
+ return "";
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!strcmp (key, pkey) )
+ return value[valueindex];
+
+ if (!*s)
+ return "";
+ s++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This function is supposed to localise the strings, but for now just return internal value
+// Input : *stringName -
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *CUtil::GetString(const char *stringName)
+{
+ return stringName;
+}
+
+static CUtil g_Util;
+CUtil *util = &g_Util;
+
+
diff --git a/tracker/common/util.h b/tracker/common/util.h
new file mode 100644
index 0000000..5c827b9
--- /dev/null
+++ b/tracker/common/util.h
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef UTIL_H
+#define UTIL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Utility function for the server browser
+//-----------------------------------------------------------------------------
+class CUtil
+{
+public:
+ const char *InfoGetValue(const char *s, const char *key);
+ const char *GetString(const char *stringName);
+
+};
+
+extern CUtil *util;
+
+
+
+#endif // UTIL_H