Team Fortress 2 Source Code as on 22/4/2020
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.

285 lines
7.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "ServerInfoPanel.h"
  8. #include "MapCycleEditDialog.h"
  9. #include <vgui/ISystem.h>
  10. #include <ctype.h>
  11. #include <stdio.h>
  12. using namespace vgui;
  13. //-----------------------------------------------------------------------------
  14. // Purpose: Constructor
  15. //-----------------------------------------------------------------------------
  16. CServerInfoPanel::CServerInfoPanel(vgui::Panel *parent, const char *name) : CVarListPropertyPage(parent, name)
  17. {
  18. LoadControlSettings("Admin/GamePanelInfo.res", "PLATFORM");
  19. LoadVarList("Admin/MainServerConfig.vdf");
  20. m_iLastUptimeDisplayed = 0;
  21. m_flUpdateTime = 0.0f;
  22. m_bMapListRetrieved = false;
  23. RemoteServer().AddServerMessageHandler(this, "UpdatePlayers");
  24. RemoteServer().AddServerMessageHandler(this, "UpdateMap");
  25. }
  26. //-----------------------------------------------------------------------------
  27. // Purpose: Destructor
  28. //-----------------------------------------------------------------------------
  29. CServerInfoPanel::~CServerInfoPanel()
  30. {
  31. RemoteServer().RemoveServerDataResponseTarget(this);
  32. }
  33. //-----------------------------------------------------------------------------
  34. // Purpose: gets the current hostname
  35. //-----------------------------------------------------------------------------
  36. const char *CServerInfoPanel::GetHostname()
  37. {
  38. return GetVarString("hostname");
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Refreshes page if necessary
  42. //-----------------------------------------------------------------------------
  43. void CServerInfoPanel::OnThink()
  44. {
  45. if (m_flUpdateTime < vgui::system()->GetFrameTime())
  46. {
  47. OnResetData();
  48. }
  49. // check uptime count
  50. int time = m_iLastUptimeReceived + (int)(vgui::system()->GetFrameTime() - m_flLastUptimeReceiveTime);
  51. if (time != m_iLastUptimeDisplayed)
  52. {
  53. m_iLastUptimeDisplayed = time;
  54. char timeText[64];
  55. _snprintf(timeText, sizeof(timeText), "%0.1i:%0.2i:%0.2i:%0.2i", (time / 3600) / 24, (time / 3600), (time / 60) % 60, time % 60);
  56. SetControlString("UpTimeText", timeText);
  57. }
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose: Data is be reloaded from document into controls.
  61. //-----------------------------------------------------------------------------
  62. void CServerInfoPanel::OnResetData()
  63. {
  64. // only ask for maps list once
  65. if (!m_bMapListRetrieved)
  66. {
  67. RemoteServer().RequestValue(this, "maplist");
  68. m_bMapListRetrieved = true;
  69. }
  70. // refresh our vars
  71. RefreshVarList();
  72. // ask for the constant data
  73. RemoteServer().RequestValue(this, "playercount");
  74. RemoteServer().RequestValue(this, "maxplayers");
  75. RemoteServer().RequestValue(this, "gamedescription");
  76. RemoteServer().RequestValue(this, "uptime");
  77. RemoteServer().RequestValue(this, "ipaddress");
  78. // update once every minute
  79. m_flUpdateTime = (float)system()->GetFrameTime() + (60 * 1.0f);
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: handles responses from the server
  83. //-----------------------------------------------------------------------------
  84. void CServerInfoPanel::OnServerDataResponse(const char *value, const char *response)
  85. {
  86. if (!stricmp(value, "playercount"))
  87. {
  88. m_iPlayerCount = atoi(response);
  89. }
  90. else if (!stricmp(value, "maxplayers"))
  91. {
  92. m_iMaxPlayers = atoi(response);
  93. // update control
  94. char buf[128];
  95. buf[0] = 0;
  96. if (m_iMaxPlayers > 0)
  97. {
  98. sprintf(buf, "%d / %d", m_iPlayerCount, m_iMaxPlayers);
  99. }
  100. SetControlString("PlayersText", buf);
  101. }
  102. else if (!stricmp(value, "gamedescription"))
  103. {
  104. SetControlString("GameText", response);
  105. }
  106. else if (!stricmp(value, "hostname"))
  107. {
  108. PostActionSignal(new KeyValues("UpdateTitle"));
  109. }
  110. else if (!stricmp(value, "UpdateMap") || !stricmp(value, "UpdatePlayers"))
  111. {
  112. // server has indicated a change, force an update
  113. m_flUpdateTime = 0.0f;
  114. }
  115. else if (!stricmp(value, "maplist"))
  116. {
  117. SetCustomStringList("map", response);
  118. // save off maplist for use in mapcycle editing
  119. ParseIntoMapList(response, m_AvailableMaps);
  120. // don't chain through, not in varlist
  121. return;
  122. }
  123. else if (!stricmp(value, "uptime"))
  124. {
  125. // record uptime for extrapolation
  126. m_iLastUptimeReceived = atoi(response);
  127. m_flLastUptimeReceiveTime = (float)system()->GetFrameTime();
  128. }
  129. else if (!stricmp(value, "ipaddress"))
  130. {
  131. SetControlString("ServerIPText", response);
  132. }
  133. else if (!stricmp(value, "mapcycle"))
  134. {
  135. ParseIntoMapList(response, m_MapCycle);
  136. UpdateMapCycleValue();
  137. // don't chain through, we set the value ourself
  138. return;
  139. }
  140. // always chain through, in case this variable is in the list as well
  141. BaseClass::OnServerDataResponse(value, response);
  142. // post update
  143. if (!stricmp(value, "map"))
  144. {
  145. // map has changed, update map cycle view
  146. UpdateMapCycleValue();
  147. }
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose: special editing of map cycle list
  151. //-----------------------------------------------------------------------------
  152. void CServerInfoPanel::OnEditVariable(KeyValues *rule)
  153. {
  154. if (!stricmp(rule->GetName(), "mapcycle"))
  155. {
  156. CMapCycleEditDialog *dlg = new CMapCycleEditDialog(this, "MapCycleEditDialog");
  157. dlg->Activate(this, m_AvailableMaps, m_MapCycle);
  158. }
  159. else
  160. {
  161. BaseClass::OnEditVariable(rule);
  162. }
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Updates the value shown in the mapcycle field
  166. //-----------------------------------------------------------------------------
  167. void CServerInfoPanel::UpdateMapCycleValue()
  168. {
  169. // look at current map
  170. CUtlSymbol currentMap = GetVarString("map");
  171. if (!currentMap.IsValid())
  172. return;
  173. // find it in the map cycle list
  174. int listPoint = -1;
  175. for (int i = 0; i < m_MapCycle.Count(); i++)
  176. {
  177. if (!stricmp(m_MapCycle[i].String(), currentMap.String()))
  178. {
  179. listPoint = i;
  180. }
  181. }
  182. // take out the next 2 maps and make them the value
  183. char nextMaps[512];
  184. nextMaps[0] = 0;
  185. bool needComma = false;
  186. for (int i = 0; i < 2; i++)
  187. {
  188. int point = listPoint + i + 1;
  189. if (point >= m_MapCycle.Count())
  190. {
  191. point -= m_MapCycle.Count();
  192. }
  193. if (m_MapCycle.IsValidIndex(point))
  194. {
  195. if (needComma)
  196. {
  197. strcat(nextMaps, ", ");
  198. }
  199. strcat(nextMaps, m_MapCycle[point].String());
  200. needComma = true;
  201. }
  202. }
  203. // add some elipses to show there is more maps
  204. if (needComma)
  205. {
  206. strcat(nextMaps, ", ");
  207. }
  208. strcat(nextMaps, "...");
  209. // show in varlist
  210. SetVarString("mapcycle", nextMaps);
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose: Seperates out a newline-seperated map list into an array
  214. //-----------------------------------------------------------------------------
  215. void CServerInfoPanel::ParseIntoMapList(const char *maplist, CUtlVector<CUtlSymbol> &mapArray)
  216. {
  217. mapArray.RemoveAll();
  218. const char *parse = maplist;
  219. while (*parse)
  220. {
  221. // newline-seperated map list
  222. //!! this should be done with a more standard tokenizer
  223. if (isspace(*parse))
  224. {
  225. parse++;
  226. continue;
  227. }
  228. // pull out the map name
  229. const char *end = strstr(parse, "\n");
  230. const char *end2 = strstr(parse, "\r");
  231. if (end && end2 && end2 < end)
  232. {
  233. end = end2;
  234. }
  235. if (!end)
  236. break;
  237. char customString[64];
  238. int nameSize = end - parse;
  239. if (nameSize >= sizeof(customString))
  240. {
  241. nameSize = sizeof(customString) - 1;
  242. }
  243. // copy in the name
  244. strncpy(customString, parse, nameSize);
  245. customString[nameSize] = 0;
  246. parse = end;
  247. // add to the list string that aren't comments
  248. if (nameSize > 0 && !(customString[0] == '/' && customString[1] == '/'))
  249. {
  250. int i = mapArray.AddToTail();
  251. mapArray[i] = customString;
  252. }
  253. }
  254. }