Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.

286 lines
7.7 KiB

5 years ago
//========= 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;
}
}
}