You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
401 lines
12 KiB
401 lines
12 KiB
//========= 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); |
|
} |
|
}
|
|
|