//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //============================================================================= #include "RemoteServer.h" #include #include #include "tier1/utlbuffer.h" #include "IGameServerData.h" extern IGameServerData *g_pGameServerData; //----------------------------------------------------------------------------- // Purpose: singleton accessor //----------------------------------------------------------------------------- CRemoteServer &RemoteServer() { static CRemoteServer s_RemoteServer; return s_RemoteServer; } //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CRemoteServer::CRemoteServer() { m_iCurrentRequestID = 0; m_ListenerID = INVALID_LISTENER_ID; m_bInitialized = false; } //----------------------------------------------------------------------------- // Purpose: Destructor //----------------------------------------------------------------------------- CRemoteServer::~CRemoteServer() { } //----------------------------------------------------------------------------- // Purpose: Destructor //----------------------------------------------------------------------------- void CRemoteServer::Initialize() { m_bInitialized = true; Assert( g_pGameServerData ); m_ListenerID = g_pGameServerData->GetNextListenerID( false ); // don't require auth on this connection g_pGameServerData->RegisterAdminUIID( m_ListenerID ); } //----------------------------------------------------------------------------- // Purpose: connects to a remote game server //----------------------------------------------------------------------------- void CRemoteServer::ConnectRemoteGameServer(unsigned int ip, unsigned short port, const char *password) { assert(!("CRemoteServer::ConnectRemoteGameServer() not yet implemented")); } //----------------------------------------------------------------------------- // Purpose: request a cvar/data from the server //----------------------------------------------------------------------------- void CRemoteServer::RequestValue(IServerDataResponse *requester, const char *variable) { Assert( m_bInitialized ); // add to the response handling table int i = m_ResponseHandlers.AddToTail(); m_ResponseHandlers[i].requestID = m_iCurrentRequestID; m_ResponseHandlers[i].handler = requester; // build the command char buf[512]; CUtlBuffer cmd(buf, sizeof(buf)); cmd.PutInt(m_iCurrentRequestID++); cmd.PutInt(SERVERDATA_REQUESTVALUE); cmd.PutString(variable); cmd.PutString(""); // send to server g_pGameServerData->WriteDataRequest(m_ListenerID, cmd.Base(), cmd.TellPut()); } //----------------------------------------------------------------------------- // Purpose: sets a value //----------------------------------------------------------------------------- void CRemoteServer::SetValue(const char *variable, const char *value) { Assert( m_bInitialized ); // build the command char buf[512]; CUtlBuffer cmd(buf, sizeof(buf)); cmd.PutInt(m_iCurrentRequestID++); cmd.PutInt(SERVERDATA_SETVALUE); cmd.PutString(variable); cmd.PutString(value); // send to server g_pGameServerData->WriteDataRequest(m_ListenerID, cmd.Base(), cmd.TellPut()); } //----------------------------------------------------------------------------- // Purpose: sends a custom command //----------------------------------------------------------------------------- void CRemoteServer::SendCommand(const char *commandString) { Assert( m_bInitialized ); // build the command char buf[512]; CUtlBuffer cmd(buf, sizeof(buf)); cmd.PutInt(m_iCurrentRequestID++); cmd.PutInt(SERVERDATA_EXECCOMMAND); cmd.PutString(commandString); cmd.PutString(""); g_pGameServerData->WriteDataRequest(m_ListenerID, cmd.Base(), cmd.TellPut()); } //----------------------------------------------------------------------------- // Purpose: changes the current password on the server // responds with "PasswordChange" "true" or "PasswordChange" "false" //----------------------------------------------------------------------------- void CRemoteServer::ChangeAccessPassword(IServerDataResponse *requester, const char *newPassword) { } //----------------------------------------------------------------------------- // Purpose: process any return values, firing any IServerDataResponse items // Output : returns true if any items were fired //----------------------------------------------------------------------------- bool CRemoteServer::ProcessServerResponse() { Assert(g_pGameServerData != NULL); Assert( m_bInitialized ); char charbuf[4096]; bool bProcessedAnyPackets = false; while (1) { // get packet from networking int bytesRead = g_pGameServerData->ReadDataResponse(m_ListenerID, charbuf, sizeof(charbuf)); if (bytesRead < 1) break; bProcessedAnyPackets = true; // parse response CUtlBuffer buf(charbuf, bytesRead, CUtlBuffer::READ_ONLY); int requestID = buf.GetInt(); int responseType = buf.GetInt(); char variable[64]; buf.GetString(variable); switch (responseType) { case SERVERDATA_RESPONSE_VALUE: { int valueSize = buf.GetInt(); Assert(valueSize > 0); CUtlBuffer value(0, valueSize); if (valueSize > 0) { value.Put(buf.PeekGet(), valueSize); } else { // null terminate value.PutChar(0); } // find callback (usually will be the first one in the list) for (int i = m_ResponseHandlers.Head(); m_ResponseHandlers.IsValidIndex(i); i = m_ResponseHandlers.Next(i)) { if (m_ResponseHandlers[i].requestID == requestID) { // found, call m_ResponseHandlers[i].handler->OnServerDataResponse(variable, (const char *)value.Base()); // remove from list m_ResponseHandlers.Remove(i); // there is only ever one handler for a message break; } } } break; case SERVERDATA_UPDATE: { // find all the people watching for this message for (int i = m_MessageHandlers.Head(); m_MessageHandlers.IsValidIndex(i); i = m_MessageHandlers.Next(i)) { if (!stricmp(m_MessageHandlers[i].messageName, variable)) { // found, call m_MessageHandlers[i].handler->OnServerDataResponse(variable, ""); // keep looking, there can be more than one handler for a message } } } break; default: Assert(responseType == SERVERDATA_RESPONSE_VALUE || responseType == SERVERDATA_UPDATE); break; } } return bProcessedAnyPackets; } //----------------------------------------------------------------------------- // Purpose: adds a constant watches for a particular message //----------------------------------------------------------------------------- void CRemoteServer::AddServerMessageHandler(IServerDataResponse *handler, const char *watch) { // add to the server message handling table int i = m_MessageHandlers.AddToTail(); strncpy(m_MessageHandlers[i].messageName, watch, sizeof(m_MessageHandlers[i].messageName) - 1); m_MessageHandlers[i].messageName[sizeof(m_MessageHandlers[i].messageName) - 1] = 0; m_MessageHandlers[i].handler = handler; } //----------------------------------------------------------------------------- // Purpose: removes a requester from the list to guarantee the pointer won't be used //----------------------------------------------------------------------------- void CRemoteServer::RemoveServerDataResponseTarget(IServerDataResponse *invalidRequester) { // iterate the responses for (int i = 0; i < m_ResponseHandlers.MaxElementIndex(); i++) { if (m_ResponseHandlers.IsValidIndex(i)) { if (m_ResponseHandlers[i].handler == invalidRequester) { // found invalid handler, remove from list m_ResponseHandlers.Remove(i); } } } // iterate the message handlers for (int i = 0; i < m_MessageHandlers.MaxElementIndex(); i++) { if (m_MessageHandlers.IsValidIndex(i)) { if (m_MessageHandlers[i].handler == invalidRequester) { // found invalid handler, remove from list m_MessageHandlers.Remove(i); } } } }