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.
227 lines
4.9 KiB
227 lines
4.9 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: defines a RCon class used to send rcon commands to remote servers |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
|
|
#include "playerlist.h" |
|
#include "Iresponse.h" |
|
|
|
#include "PlayerMsgHandler.h" |
|
#include "Socket.h" |
|
#include "proto_oob.h" |
|
#include "DialogGameInfo.h" |
|
#include "inetapi.h" |
|
#include "TokenLine.h" |
|
#include "dialogkickplayer.h" |
|
|
|
extern void v_strncpy(char *dest, const char *src, int bufsize); |
|
|
|
typedef enum |
|
{ |
|
NONE = 0, |
|
INFO_REQUESTED, |
|
INFO_RECEIVED |
|
} RCONSTATUS; |
|
|
|
CPlayerList::CPlayerList(IResponse *target,serveritem_t &server, const char *rconPassword) { |
|
|
|
memcpy(&m_Server, &server,sizeof(serveritem_t)); |
|
m_pResponseTarget=target; |
|
|
|
m_bIsRefreshing=false; |
|
m_bNewPlayerList=false; |
|
m_bRconFailed=false; |
|
|
|
v_strncpy(m_szRconPassword,rconPassword,100); |
|
|
|
m_pRcon = new CRcon(this , server,rconPassword); |
|
m_PlayerList=NULL; |
|
m_pPlayerInfoMsg=NULL; |
|
|
|
m_pQuery = new CSocket("internet player query", -1); |
|
|
|
} |
|
|
|
CPlayerList::~CPlayerList() { |
|
delete m_pQuery; |
|
delete m_pRcon; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sends a status query packet to a single server |
|
//----------------------------------------------------------------------------- |
|
void CPlayerList::SendQuery() |
|
{ |
|
CMsgBuffer *buffer = m_pQuery->GetSendBuffer(); |
|
assert( buffer ); |
|
|
|
if ( !buffer ) |
|
{ |
|
return; |
|
} |
|
|
|
int bytecode = S2A_PLAYER; |
|
if ( m_pPlayerInfoMsg != NULL ) |
|
{ |
|
delete m_pPlayerInfoMsg; |
|
} |
|
m_pPlayerInfoMsg=new CPlayerMsgHandlerDetails(this, &m_PlayerList,CMsgHandler::MSGHANDLER_ALL, &bytecode); |
|
m_pQuery->AddMessageHandler(m_pPlayerInfoMsg); |
|
|
|
m_bIsRefreshing=true; |
|
|
|
netadr_t adr; |
|
|
|
adr.ip[0] = m_Server.ip[0]; |
|
adr.ip[1] = m_Server.ip[1]; |
|
adr.ip[2] = m_Server.ip[2]; |
|
adr.ip[3] = m_Server.ip[3]; |
|
adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8; |
|
adr.type = NA_IP; |
|
|
|
// Set state |
|
m_Server.received = (int)INFO_REQUESTED; |
|
|
|
// Create query message |
|
buffer->Clear(); |
|
// Write control sequence |
|
buffer->WriteLong(0xffffffff); |
|
|
|
// Write query string |
|
buffer->WriteString("players"); |
|
|
|
// Sendmessage |
|
m_pQuery->SendMessage( &adr ); |
|
|
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPlayerList::RunFrame() |
|
{ |
|
if (m_pQuery && m_bIsRefreshing) |
|
{ |
|
m_pQuery->Frame(); |
|
} |
|
if(m_pRcon) |
|
{ |
|
m_pRcon->RunFrame(); |
|
} |
|
|
|
} |
|
|
|
|
|
void CPlayerList::ServerResponded() |
|
{ |
|
const char *rconResp = m_pRcon->RconResponse(); |
|
const char *cur = strstr(rconResp,"name userid uniqueid frag time ping loss adr\n") |
|
+ strlen("name userid uniqueid frag time ping loss adr\n"); |
|
|
|
// status format: |
|
// # name userid uniqueid frag time ping loss adr |
|
// # 1 "Player" 1 4294967295 0 30:56 22 0 192.168.3.64:27005 |
|
|
|
|
|
for(int i=0;i<m_PlayerList.Count();i++) |
|
{ |
|
if(cur!=NULL) |
|
{ |
|
TokenLine playerLine; |
|
playerLine.SetLine(cur); |
|
|
|
if(playerLine.CountToken() >= 9 ) |
|
{ |
|
// playerLine.GetToken(1); // count |
|
// playerLine.GetToken(2); // player name |
|
// char *player= playerLine.GetToken(2); |
|
|
|
m_PlayerList[i].userid=atoi(playerLine.GetToken(3)); // userid |
|
v_strncpy(m_PlayerList[i].authid,playerLine.GetToken(4),20); // authid |
|
//playerLine.GetToken(5); // frag |
|
// playerLine.GetToken(6); // time |
|
m_PlayerList[i].ping=atoi(playerLine.GetToken(7)); //ping |
|
m_PlayerList[i].loss=atoi(playerLine.GetToken(8)); // loss |
|
// playerLine.GetToken(9); // adr |
|
} |
|
cur=strchr(cur,'\n')+1; |
|
|
|
} |
|
} |
|
|
|
m_bNewPlayerList=true; |
|
m_bIsRefreshing=false; |
|
|
|
// notify the UI of the new server info |
|
m_pResponseTarget->ServerResponded(); |
|
|
|
} |
|
|
|
void CPlayerList::ServerFailedToRespond() |
|
{ |
|
m_bNewPlayerList=true; |
|
m_bIsRefreshing=false; |
|
|
|
if(m_bRconFailed==false) |
|
{ |
|
m_bRconFailed=true; |
|
// CDialogKickPlayer *box = new CDialogKickPlayer(); |
|
//box->addActionSignalTarget(this); |
|
// box->Activate("","Bad Rcon Password","badrcon"); |
|
} |
|
|
|
// rcon failed BUT we still have some valid data :) |
|
m_pResponseTarget->ServerResponded(); |
|
} |
|
|
|
|
|
void CPlayerList::UpdateServer() |
|
{ |
|
|
|
m_pQuery->RemoveMessageHandler(m_pPlayerInfoMsg); |
|
// you CANNOT delete this handler because we are inside of it at the moment... (yes, this was an ugly bug) |
|
// delete m_pPlayerInfoMsg; |
|
|
|
// now use "rcon status" to pull extra info about the players |
|
m_pRcon->SendRcon("status"); |
|
|
|
} |
|
|
|
void CPlayerList::Refresh() |
|
{ |
|
SendQuery(); |
|
} |
|
|
|
bool CPlayerList::IsRefreshing() |
|
{ |
|
|
|
return m_bIsRefreshing; |
|
} |
|
|
|
serveritem_t &CPlayerList::GetServer() |
|
{ |
|
return m_Server; |
|
} |
|
|
|
|
|
bool CPlayerList::NewPlayerList() |
|
{ |
|
return m_bNewPlayerList; |
|
} |
|
|
|
CUtlVector<Players_t> *CPlayerList::GetPlayerList() |
|
{ |
|
m_bNewPlayerList=false; |
|
return &m_PlayerList; |
|
} |
|
|
|
void CPlayerList::SetPassword(const char *newPass) |
|
{ |
|
m_pRcon->SetPassword(newPass); |
|
m_bRconFailed=false; |
|
} |