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.

226 lines
4.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: defines a RCon class used to send rcon commands to remote servers
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "playerlist.h"
  8. #include "Iresponse.h"
  9. #include "PlayerMsgHandler.h"
  10. #include "Socket.h"
  11. #include "proto_oob.h"
  12. #include "DialogGameInfo.h"
  13. #include "inetapi.h"
  14. #include "TokenLine.h"
  15. #include "dialogkickplayer.h"
  16. extern void v_strncpy(char *dest, const char *src, int bufsize);
  17. typedef enum
  18. {
  19. NONE = 0,
  20. INFO_REQUESTED,
  21. INFO_RECEIVED
  22. } RCONSTATUS;
  23. CPlayerList::CPlayerList(IResponse *target,serveritem_t &server, const char *rconPassword) {
  24. memcpy(&m_Server, &server,sizeof(serveritem_t));
  25. m_pResponseTarget=target;
  26. m_bIsRefreshing=false;
  27. m_bNewPlayerList=false;
  28. m_bRconFailed=false;
  29. v_strncpy(m_szRconPassword,rconPassword,100);
  30. m_pRcon = new CRcon(this , server,rconPassword);
  31. m_PlayerList=NULL;
  32. m_pPlayerInfoMsg=NULL;
  33. m_pQuery = new CSocket("internet player query", -1);
  34. }
  35. CPlayerList::~CPlayerList() {
  36. delete m_pQuery;
  37. delete m_pRcon;
  38. }
  39. //-----------------------------------------------------------------------------
  40. // Purpose: sends a status query packet to a single server
  41. //-----------------------------------------------------------------------------
  42. void CPlayerList::SendQuery()
  43. {
  44. CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
  45. assert( buffer );
  46. if ( !buffer )
  47. {
  48. return;
  49. }
  50. int bytecode = S2A_PLAYER;
  51. if ( m_pPlayerInfoMsg != NULL )
  52. {
  53. delete m_pPlayerInfoMsg;
  54. }
  55. m_pPlayerInfoMsg=new CPlayerMsgHandlerDetails(this, &m_PlayerList,CMsgHandler::MSGHANDLER_ALL, &bytecode);
  56. m_pQuery->AddMessageHandler(m_pPlayerInfoMsg);
  57. m_bIsRefreshing=true;
  58. netadr_t adr;
  59. adr.ip[0] = m_Server.ip[0];
  60. adr.ip[1] = m_Server.ip[1];
  61. adr.ip[2] = m_Server.ip[2];
  62. adr.ip[3] = m_Server.ip[3];
  63. adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
  64. adr.type = NA_IP;
  65. // Set state
  66. m_Server.received = (int)INFO_REQUESTED;
  67. // Create query message
  68. buffer->Clear();
  69. // Write control sequence
  70. buffer->WriteLong(0xffffffff);
  71. // Write query string
  72. buffer->WriteString("players");
  73. // Sendmessage
  74. m_pQuery->SendMessage( &adr );
  75. }
  76. //-----------------------------------------------------------------------------
  77. // Purpose:
  78. //-----------------------------------------------------------------------------
  79. void CPlayerList::RunFrame()
  80. {
  81. if (m_pQuery && m_bIsRefreshing)
  82. {
  83. m_pQuery->Frame();
  84. }
  85. if(m_pRcon)
  86. {
  87. m_pRcon->RunFrame();
  88. }
  89. }
  90. void CPlayerList::ServerResponded()
  91. {
  92. const char *rconResp = m_pRcon->RconResponse();
  93. const char *cur = strstr(rconResp,"name userid uniqueid frag time ping loss adr\n")
  94. + strlen("name userid uniqueid frag time ping loss adr\n");
  95. // status format:
  96. // # name userid uniqueid frag time ping loss adr
  97. // # 1 "Player" 1 4294967295 0 30:56 22 0 192.168.3.64:27005
  98. for(int i=0;i<m_PlayerList.Count();i++)
  99. {
  100. if(cur!=NULL)
  101. {
  102. TokenLine playerLine;
  103. playerLine.SetLine(cur);
  104. if(playerLine.CountToken() >= 9 )
  105. {
  106. // playerLine.GetToken(1); // count
  107. // playerLine.GetToken(2); // player name
  108. // char *player= playerLine.GetToken(2);
  109. m_PlayerList[i].userid=atoi(playerLine.GetToken(3)); // userid
  110. v_strncpy(m_PlayerList[i].authid,playerLine.GetToken(4),20); // authid
  111. //playerLine.GetToken(5); // frag
  112. // playerLine.GetToken(6); // time
  113. m_PlayerList[i].ping=atoi(playerLine.GetToken(7)); //ping
  114. m_PlayerList[i].loss=atoi(playerLine.GetToken(8)); // loss
  115. // playerLine.GetToken(9); // adr
  116. }
  117. cur=strchr(cur,'\n')+1;
  118. }
  119. }
  120. m_bNewPlayerList=true;
  121. m_bIsRefreshing=false;
  122. // notify the UI of the new server info
  123. m_pResponseTarget->ServerResponded();
  124. }
  125. void CPlayerList::ServerFailedToRespond()
  126. {
  127. m_bNewPlayerList=true;
  128. m_bIsRefreshing=false;
  129. if(m_bRconFailed==false)
  130. {
  131. m_bRconFailed=true;
  132. // CDialogKickPlayer *box = new CDialogKickPlayer();
  133. //box->addActionSignalTarget(this);
  134. // box->Activate("","Bad Rcon Password","badrcon");
  135. }
  136. // rcon failed BUT we still have some valid data :)
  137. m_pResponseTarget->ServerResponded();
  138. }
  139. void CPlayerList::UpdateServer()
  140. {
  141. m_pQuery->RemoveMessageHandler(m_pPlayerInfoMsg);
  142. // you CANNOT delete this handler because we are inside of it at the moment... (yes, this was an ugly bug)
  143. // delete m_pPlayerInfoMsg;
  144. // now use "rcon status" to pull extra info about the players
  145. m_pRcon->SendRcon("status");
  146. }
  147. void CPlayerList::Refresh()
  148. {
  149. SendQuery();
  150. }
  151. bool CPlayerList::IsRefreshing()
  152. {
  153. return m_bIsRefreshing;
  154. }
  155. serveritem_t &CPlayerList::GetServer()
  156. {
  157. return m_Server;
  158. }
  159. bool CPlayerList::NewPlayerList()
  160. {
  161. return m_bNewPlayerList;
  162. }
  163. CUtlVector<Players_t> *CPlayerList::GetPlayerList()
  164. {
  165. m_bNewPlayerList=false;
  166. return &m_PlayerList;
  167. }
  168. void CPlayerList::SetPassword(const char *newPass)
  169. {
  170. m_pRcon->SetPassword(newPass);
  171. m_bRconFailed=false;
  172. }