Code: Select all
/////////////////////////////////////////////////////////////////////////////
// Engine.cpp
//
//
// Запрос и обработка ответа сервера.
//
//
#include "stdafx.h"
#include "App.h"
#include "QueryServer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
TCHAR Buffer[4096] = TEXT("");
FString m_sValue = Buffer;
FString m_sIn = Buffer;
FString m_sOut = Buffer;
/////////////////////////////////////////////////////////////////////////////
//
// Запрос и обработка ответа сервера.
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// DefaultData
//
// Обнулить данные, адрес, порт сервера, установить по умолчанию.
//
void CMainFrame::DefaultData()
{
m_sHostAddress = m_sDefaultHostAddress;
m_nHostPort = m_nDefaultHostPort;
m_sPlayerName.Empty();
m_nPlayerFrags = 0;
m_nPlayerPing = 0;
m_sPlayerTeam.Empty();
m_sPlayerMesh.Empty();
m_sPlayerSkin.Empty();
m_sPlayerFace.Empty();
m_nPlayerID = 0;
m_sPlayerStats.Empty();
m_sPlayer.Empty();
}
int CMainFrame::Int(FString Text)
{
return _wtoi( *Text );
}
FString CMainFrame::LocalizeTeam(FString TeamNum)
{
if( TeamNum == TEXT("255") )
return TEXT("");
return TeamNum;
}
FString CMainFrame::GetItemName(FString FullName)
{
int pos;
pos = FullName.InStr( TEXT(".") );
while( pos != -1 )
{
FullName = FullName.Right( FullName.Len() - pos - 1 );
pos = FullName.InStr( TEXT(".") );
}
return FullName;
}
FString CMainFrame::LocalizeBoolValue(FString Value)
{
if( Value != TEXT("True") )
return m_sTrueString;
if( Value != TEXT("False") )
return m_sFalseString;
return Value;
}
FString CMainFrame::LocalizeSkin(FString SkinName)
{
static FString MeshName;
MeshName = SkinName.Left( SkinName.InStr(TEXT(".")) );
return MeshName;
}
BOOL CMainFrame::GetNextValue(FString In, FString Out, FString Result)
{
m_sValue.Empty();
Result = TEXT("");
BOOL bFoundStart = FALSE;
int i;
for( i = 0; i < In.Len(); ++i )
{
if( bFoundStart )
{
if( In.Mid( i, 1 ) == "\\" )
{
m_sOut = In.Right( In.Len() - i );
return TRUE;
}
else
{
Result += In.Mid( i, 1 );
m_sValue = Result;
}
}
else
{
if( In.Mid( i, 1 ) == "\\" )
{
bFoundStart = TRUE;
}
}
}
return FALSE;
}
FString CMainFrame::ParseReply(FString Text, FString Key)
{
FString key = FString::Printf( TEXT( "\\%s\\" ), *Key );
FString Temp;
int i = Text.InStr( key );
//Temp = Text.Mid( i + key.Len() + 2 );
Temp = Text.Mid( i + key.Len() );
return Temp.Left( Temp.InStr( TEXT( "\\") ) );
}
/////////////////////////////////////////////////////////////////////////////
// AddRule
//
// Добавить к ListView.
//
void CMainFrame::AddRule( FString PlayerName, int nPlayerFrags,
int nPlayerPing, FString PlayerTeam,
FString PlayerMesh, FString PlayerSkin,
FString PlayerFace, int nPlayerID
)
{
CString s;
BuildItems( INDEX_NAME, *PlayerName );
m_sPlayer += *PlayerName;
m_sPlayer += _T("\n");
s.Format( _T("%d"), nPlayerFrags );
BuildItems( INDEX_FRAGS, s );
//m_sPlayer += _T(" Frags: ");
//m_sPlayer += s;
s.Format( TEXT("%d"), nPlayerPing );
BuildItems( INDEX_PING, s );
//m_sPlayer += _T(" Ping: ");
//m_sPlayer += s;
//m_sPlayer += _T("\n");
BuildItems( INDEX_TEAM, *PlayerTeam );
BuildItems( INDEX_MESH, *PlayerMesh );
BuildItems( INDEX_SKIN, *PlayerSkin );
BuildItems( INDEX_FACE, *PlayerFace );
s.Format( TEXT( "%d" ), nPlayerID );
BuildItems( INDEX_ID, s );
}
/////////////////////////////////////////////////////////////////////////////
// GetInfo
//
// Разбор.
//
/*
void CMainFrame::GetInfo(FString Text)
{
CString sMsg;
FString Temp;
// Получить имя сервера.
Temp = ParseReply(Text, TEXT("hostname") );
if( Temp != TEXT("") )
m_sHostName = Temp;
// Имя сервера:
//sMsg += TEXT( "Имя сервера:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить порт сервера.
Temp = ParseReply(Text, TEXT("hostport") );
if( Temp != TEXT("") )
m_nGamePort = Int(Temp);
// debug - Порт сервера:
//sMsg += TEXT( "Порт сервера:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить название карты.
Temp = ParseReply(Text, TEXT("mapname") );
if( Temp != TEXT("") )
m_sMapName = Temp;
// debug - Имя карты:
//sMsg += TEXT( "Название карты:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить заголовок карты.
Temp = ParseReply(Text, TEXT("maptitle") );
if( Temp != TEXT("") )
{
m_sMapTitle = Temp;
m_sMapDisplayName = m_sMapTitle;
//if( m_sMapTitle == GEmpty || m_sMapTitle == GUntitled )
if( m_sMapTitle == TEXT("") || m_sMapTitle == TEXT("Untitled") )
m_sMapDisplayName = m_sMapName;
}
// debug - Зоголовок карты:
//sMsg += TEXT( "Зоголовок карты:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
Temp = ParseReply(Text, TEXT("gametype") );
if( Temp != TEXT("") )
m_sGameType = Temp;
// debug - Тип игры
//sMsg += TEXT( "Тип игры:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить число игроков.
Temp = ParseReply(Text, TEXT("numplayers") );
if( Temp != TEXT("") )
m_nNumPlayers = Int(Temp);
// debug - Число игроков:
//sMsg += TEXT( "Число игроков:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить число допустимых игроков.
Temp = ParseReply(Text, TEXT("maxplayers") );
if( Temp != TEXT("") )
m_nMaxPlayers = Int(Temp);
// debug - Максимум игроков:
//sMsg += TEXT( "Максимум игроков:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить режим игры.
Temp = ParseReply(Text, TEXT("gamemode") );
if( Temp != TEXT("") )
m_sGameMode = Temp;
// debug - Режим игры:
//sMsg += TEXT( "Режим игры:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить версию игры.
Temp = ParseReply(Text, TEXT("gamever") );
if( Temp != TEXT("") )
m_nGameVer = Int(Temp);
// debug - Версия игры:
//sMsg += TEXT( "Версия игры:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
// Получить минимально поддерживаемую версию игры.
Temp = ParseReply(Text, TEXT("minnetver") );
if( Temp != TEXT("") )
m_nMinNetVer = Int(Temp);
// debug - Минимально поддерживаемаю версия игры:
//sMsg += TEXT( "Минимально поддерживаемаю версия:\n" );
//sMsg += *Temp;
//sMsg += TEXT( "\n" );
//MessageBox( sMsg, TEXT("Information"),MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND|MB_TOPMOST);
}
*/
/////////////////////////////////////////////////////////////////////////////
// GetStatus
//
// Основной разбор.
//
void CMainFrame::GetStatus(FString Text)
{
int Result = CheckEngine();
if( Result ) return;
// Очистить список ListView.
ClearResponse();
int nID;
BOOL bOK;
m_sOut.Empty();
m_sValue.Empty();
m_sIn = *Text;
do {
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
if( m_sValue.Left( 7 )==TEXT("player_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 7));
++nID;
m_nPlayerID = nID;
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_sPlayerName = m_sValue;
}
else if( m_sValue.Left( 6 ) == TEXT("frags_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 6));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_nPlayerFrags = Int(m_sValue);
}
else if( m_sValue.Left( 5 ) == TEXT("ping_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 5));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_nPlayerPing = Int(m_sValue.Right(m_sValue.Len() - 1));
}
else if( m_sValue.Left( 5 ) == TEXT("team_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 5));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_sPlayerTeam = LocalizeTeam(m_sValue);
if( m_sPlayerTeam == TEXT("") )
m_sPlayerTeam = TEXT("255");
}
else if( m_sValue.Left( 5 ) == TEXT("skin_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 5));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_sPlayerSkin = LocalizeSkin(m_sValue);
}
else if( m_sValue.Left( 5 ) == TEXT("face_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 5));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_sPlayerFace = GetItemName(m_sValue);
}
else if( m_sValue.Left( 5 ) == TEXT("mesh_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 5));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_sPlayerMesh = m_sValue;
//
// Out...
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AddRule(
m_sPlayerName,
m_nPlayerFrags,
m_nPlayerPing,
m_sPlayerTeam,
m_sPlayerMesh,
m_sPlayerSkin,
m_sPlayerFace,
m_nPlayerID
);
// Check exit?
Result = CheckEngine();
if( Result ) return;
}
/*
else if( m_sValue.Left( 9 ) == TEXT("ngsecret_") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 9));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_sPlayerStats = m_sValue;
}
*/
//
// Имя сервера.
//
else if( m_sValue.Left( 8 ) == TEXT("hostname") )
{
nID = Int(m_sValue.Right(m_sValue.Len() - 8));
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
m_sIn = m_sOut;
m_sServername = *m_sValue;
}
else if( m_sValue == TEXT("final") )
{
//
// __ F i n a l __
//
m_nStatusDone = TRUE;
return;
}
else if( m_sValue == TEXT("gamever") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//Temp = *m_sIn;
//Temp = *m_sOut;
//Temp = *m_sValue;
//AddRule(GameVersionText, m_sValue);
}
else if( m_sValue == TEXT("minnetver") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(MinNetVersionText, m_sValue);
}
else if( m_sValue == TEXT("gametype") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(GameTypeText, m_sValue);
}
else if( m_sValue == TEXT("timelimit") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(TimeLimitText, m_sValue);
}
else if( m_sValue == TEXT("fraglimit") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(FragLimitText, m_sValue);
}
else if( m_sValue == TEXT("MultiplayerBots") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(MultiplayerBotsText, LocalizeBoolValue(m_sValue));
}
else if( m_sValue == TEXT("AdminName") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(AdminNameText, m_sValue);
}
else if( m_sValue == TEXT("AdminEMail") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(AdminEmailText, m_sValue);
}
else if( m_sValue == TEXT("WantWorldLog") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(WorldLogText, LocalizeBoolValue(m_sValue));
}
else if( m_sValue == TEXT("WorldLog") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
/*
if( Server.GameVer >= 406 )
{
if( m_sValue ~= TEXT("True") )
AddRule(WorldLogWorkingText, WorldLogWorkingTrue);
else
AddRule(WorldLogWorkingText, WorldLogWorkingFalse);
}
else
AddRule(WorldLogText, LocalizeBoolValue(m_sValue));
*/
}
else if( m_sValue == TEXT("mutators") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(MutatorsText, m_sValue);
}
else if( m_sValue == TEXT("goalteamscore") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(GoalTeamScoreText, m_sValue);
}
else if( m_sValue == TEXT("minplayers") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
/*
if( m_sValue == TEXT( "0" ) )
//AddRule(MultiplayerBotsText, FalseString);
else
//AddRule(MinPlayersText, m_sValue@PlayersText);
//AddRule(MinPlayersText, m_sValue);
*/
}
else if( m_sValue == TEXT("changelevels") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(ChangeLevelsText, LocalizeBoolValue(m_sValue));
}
else if( m_sValue == TEXT("botskill") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(BotSkillText, m_sValue);
}
else if( m_sValue == TEXT("maxteams") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(MaxTeamsText, m_sValue);
}
else if( m_sValue == TEXT("balanceteams") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(BalanceTeamsText, LocalizeBoolValue(m_sValue));
}
else if( m_sValue == TEXT("playersbalanceteams") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(PlayersBalanceTeamsText, LocalizeBoolValue(m_sValue));
}
else if( m_sValue == TEXT("friendlyfire") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(FriendlyFireText, m_sValue);
}
else if( m_sValue == TEXT("gamestyle") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(GameModeText, m_sValue);
}
else if( m_sValue == TEXT("tournament") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(TournamentText, LocalizeBoolValue(m_sValue));
}
else if( m_sValue == TEXT("listenserver") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
/*
if(bool(m_sValue))
AddRule(ServerModeText, NonDedicatedText);
else
AddRule(ServerModeText, DedicatedText);
*/
}
else if( m_sValue == TEXT("password") )
{
bOK = GetNextValue(m_sIn,m_sOut,m_sValue);
//AddRule(PasswordText, LocalizeBoolValue(m_sValue));
}
} while( bOK );
}
/////////////////////////////////////////////////////////////////////////////
// DoQuery
//
// Подготовка запроса.
//
int CMainFrame::DoQuery()
{
debugf( m_sStartQuery );
m_nPlayerID = 0;
// Проверка на 'Выход' ?
int Result = CheckEngine();
if( Result )
{
// Да, выход.
return Result;
}
const TCHAR* Magicstring;
Magicstring = TEXT( "\\status\\" );
//Magicstring = TEXT( "\\info\\" );
//Magicstring = TEXT( "\\players\\" );
//
// -- Текущий -- Madrixis --
//
// Server: Multiplay :: Public DM #13 (Deck16 - All Weapons)
//m_sHostAddress = TEXT("85.236.100.115");
//m_nHostPort = 8178;
//nPort = 8078;
//nPort = 8278;
//nPort = 7878;
//nPort = 7978;
//nPort = 8177;
// 1
// Server: zp| [=======] [PURE] [INSTAGIB] [UK] [======
//Hostaddress = TEXT("185.16.85.10");
//nPort = 7778;
// 2
// Server: ROCKET - OLYMPIC - PHOENIX
//m_sHostaddress = TEXT("108.61.254.168");
//nPort = 7778;
// Нет ли в текущем каталоге файла "servers.txt" ?
// Если есть, попытаться получить данные оттуда.
CheckFileServer();
// Инициализация класса "QueryServer".
QueryServer* query;
query = new QueryServer();
Result = query->Start(m_sHostAddress, m_nHostPort, Magicstring);
if( Result < 0 )
{
Sleep(100);
//MessageBox(TEXT("-->FAILED: QueryServer = 0x0FFFFFFFF"),
// TEXT("UDP Ping Server"),MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_TOPMOST);
// Удалить Queryserver.
delete query;
return -2;
}
// Проверка на 'Выход' ?
Result = CheckEngine();
if( Result )
{
// Да, выход.
delete query;
return Result;
}
// Копировать данные.
FString Buffer = query->GetResponse();
if( Buffer.Len()==0 )
{
// Данных нет.
debugf( TEXT("No data from server: %s port: %i"), m_sHostAddress, m_nHostPort);
delete query;
return -3;
}
// Обработка данных.
GetStatus( Buffer );
delete query;
debugf( m_sEndQuery );
return m_nPlayerID;
}
/////////////////////////////////////////////////////////////////////////////
// GetServerAddressPort
BOOL CMainFrame::GetServerAddressPort(const TCHAR* Stream)
{
BOOL bResult = 0x0FFFFFFFF;
TCHAR Temp[256], *URL=Temp;
TCHAR Line[256];
while( ParseLine( &Stream, Line, ARRAY_COUNT(Line),1) )
{
const TCHAR* Data = Line;
if( Data[0]==';' || Data[0]=='/' )
continue;
FString Str( Line );
TCHAR* Start = const_cast<TCHAR*>(*Str);
TCHAR* End = Start + Str.Len();
//while( Start<End && (Start[0]=='\r' || Start[0]=='\n' || Start[0]==' ') )
while( Start<End && (Start[0]=='\r' || Start[0]=='\n' || Start[0]=='\t' || Start[0]==' ') )
++Start;
//while( End>Start && (End [-1]=='\r' || End [-1]=='\n' || End [-1]==' ') )
while( End>Start && (End [-1]=='\r' || End [-1]=='\n' || End [-1]=='\t' || End [-1]==' ') )
--End;
*End = 0;
appStrncpy( Temp, Start, ARRAY_COUNT(Temp) );
// Skip leading blanks.
//while( *URL == ' ' )
// URL++;
if( appStrlen(URL)>2 && URL[1]==':' )
{
return bResult;
}
else
{
// Parse optional host name and port.
const TCHAR* Dot = appStrchr(URL,'.');
if( ( Dot ) && ( Dot - URL > 0 ) )
{
TCHAR* s = URL;
TCHAR* t = appStrchr(s,':');
if( t )
{
// Порт сервера.
*t++ = 0;
m_nHostPort = appAtoi( t );
}
// Адрес сервера.
m_sHostAddress = CString( s );
return 0;
}
}
}
return bResult;
}
/*
//
// Get port 1.
//
FString GetPort( FString Input )
{
int pos;
pos = Input.InStr( TEXT(":") );
while( pos != -1 )
{
Input = Input.Right( Input.Len() - pos - 1 );
pos = Input.InStr( TEXT(":") );
}
return Input;
}
// Return the server's port number.
int GetServerPort(FString Input)
{
int i;
// Figure out the server's port.
//Input = Level.GetAddressURL();
i = Input.InStr( TEXT(":") );
//assert(i>=0);
return int( Input.Mid( i+1 ) );
}
*/
/////////////////////////////////////////////////////////////////////////////
// CheckFileServer
//
// Перед каждым запросом, программа будет смотреть, если в текущем
// каталоге текстовой файл "servers.txt", при его наличии: адрес и порт сервера
// считывается оттуда. Файл размером больше 8 килобайт игнорируется.
// Формат записи, пример:
// 85.236.100.115:8178
// Берётся только одна строка, символ точки с запятой является комментарием.
// Если адрес корректный вы будете видеть отображение сервера.
//
void CMainFrame::CheckFileServer()
{
const TCHAR* Filename;
//Filename = TEXT("c:\\servers.txt");
Filename = TEXT("servers.txt");
FString Data;
if( appLoadFileToString(Data,Filename)==0 )
{
//debugf( TEXT("Could not open file %s"), Filename );
//FString Msg = FString::Printf(TEXT("Could not open file %s"), Filename);
//MessageBox( *Msg, TEXT("Error"), MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST);
return;
}
// Проверить размер файла.
// Если пустой или больше 8 килобайт, не обрабатывать.
int nSize = Data.Len();
if( nSize==0 )
{
// Файл пуст, установить по умолчанию.
debugf( TEXT("Empty file %s"), Filename );
DefaultData();
return;
}
if( nSize > 8000 )
{
// Файл больше 8 kb, установить по умолчанию.
debugf( TEXT("File %s large 8 kb"), Filename );
DefaultData();
return;
}
// Чтение данных из файла "servers.txt".
if( GetServerAddressPort( *Data ) != 0)
{
// Данных нет.
debugf( TEXT("Missing data %s"), Filename );
DefaultData();
return;
}
debugf( TEXT("New host query %s:%d"), m_sHostAddress, m_nHostPort );
//FString Msg;
//Msg = FString::Printf( TEXT( "%s" ), GetServerAddressPort( *Data ) );
//MessageBox( *Msg, TEXT("Error"), MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST);
}
/////////////////////////////////////////////////////////////////////////////
// <<eof>> Engine.cpp
/////////////////////////////////////////////////////////////////////////////