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.
402 lines
12 KiB
402 lines
12 KiB
5 years ago
|
//========= 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);
|
||
|
}
|
||
|
}
|