diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tracker | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'tracker')
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 |