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/AdminServer/GraphPanel.cpp | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'tracker/AdminServer/GraphPanel.cpp')
| -rw-r--r-- | tracker/AdminServer/GraphPanel.cpp | 731 |
1 files changed, 731 insertions, 0 deletions
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; +} |