Re: socket - server a get server b info
PHP Code:
#include <amxmodx>
#include <sockets>
#include <geoip>
#include <regex>
// A2S_INFO definitions for source according to http://developer.valvesoftware.com/wiki/Server_Queries#Source_servers_2
#define A2S_INFO_SOURCE_REPLY_FORMAT "411ssss21111111s"
#define A2S_INFO_SOURCE_IDX_HEADER 0 // Should be FF FF FF FF
#define A2S_INFO_SOURCE_IDX_TYPE 1 // Should be equal to 'I' (0x49)
#define A2S_INFO_SOURCE_IDX_VERSION 2 // Network version. 0x07 is the current Steam version.
#define A2S_INFO_SOURCE_IDX_SERVERNAME 3 // The Source server's name
#define A2S_INFO_SOURCE_IDX_MAP 4 // The current map being played, eg: "de_dust"
#define A2S_INFO_SOURCE_IDX_GAMEDIR 5 // The name of the folder containing the game files, eg: "cstrike"
#define A2S_INFO_SOURCE_IDX_GAMEDESC 6 // A friendly string name for the game type, eg: "Counter Strike: Source"
#define A2S_INFO_SOURCE_IDX_APPID 7 // Steam Application ID
#define A2S_INFO_SOURCE_IDX_NUMPLAYERS 8 // The number of players currently on the server
#define A2S_INFO_SOURCE_IDX_MAXPLAYERS 9 // Maximum allowed players for the server
#define A2S_INFO_SOURCE_IDX_NUMBOTS 10 // Number of bot players currently on the server
#define A2S_INFO_SOURCE_IDX_DEDICATED 11 // 'l' for listen, 'd' for dedicated, 'p' for SourceTV
#define A2S_INFO_SOURCE_IDX_OS 12 // Host operating system. 'l' for Linux, 'w' for Windows
#define A2S_INFO_SOURCE_IDX_PASSWORD 13 // If set to 0x01, a password is required to join this server
#define A2S_INFO_SOURCE_IDX_SECURE 14 // if set to 0x01, this server is VAC secured
#define A2S_INFO_SOURCE_IDX_GAMEVERSION 15 // The version of the game, eg: "1.0.0.22"
// A2S_INFO definitions for goldsource according to http://developer.valvesoftware.com/wiki/Server_Queries#Goldsource_servers_2
#define A2S_INFO_GOLD_REPLY_FORMAT "41sssss111111[ss14411]11"
#define A2S_INFO_GOLD_IDX_HEADER 0 // Should be FF FF FF FF
#define A2S_INFO_GOLD_IDX_TYPE 1 // Should be equal to 'm' (0x6D) - for older servers it's 'C' (0x43)
#define A2S_INFO_GOLD_IDX_IP 2 // Game Server IP address and port
#define A2S_INFO_GOLD_IDX_SERVERNAME 3 // The server's name
#define A2S_INFO_GOLD_IDX_MAP 4 // The current map being played, eg: "de_dust"
#define A2S_INFO_GOLD_IDX_GAMEDIR 5 // The name of the folder containing the game files, eg: "cstrike"
#define A2S_INFO_GOLD_IDX_GAMEDESC 6 // A friendly string name for the game type, eg: "Counter-Strike"
#define A2S_INFO_GOLD_IDX_NUMPLAYERS 7 // The number of players currently on the server
#define A2S_INFO_GOLD_IDX_MAXPLAYERS 8 // Maximum allowed players for the server
#define A2S_INFO_GOLD_IDX_VERSION 9 // Network version. 0x07 is the current Steam version.
#define A2S_INFO_GOLD_IDX_DEDICATED 10 // 'l' for listen, 'd' for dedicated, 'p' for HLTV
#define A2S_INFO_GOLD_IDX_OS 11 // Host operating system. 'l' for Linux, 'w' for Windows
#define A2S_INFO_GOLD_IDX_PASSWORD 12 // If set to 0x01, a password is required to join this server
#define A2S_INFO_GOLD_IDX_ISMOD 13 // If set to 0x01, this byte is followed by ModInfo
#define A2S_INFO_GOLD_IDX_SECURE 14 // if set to 0x01, this server is VAC secured
#define A2S_INFO_GOLD_IDX_NUMBOTS 15 // Number of bot players currently on the server
#define A2S_INFO_GOLD_IDX_MOD_URLINFO 14 // URL containing information about this mod
#define A2S_INFO_GOLD_IDX_MOD_URLDL 15 // URL to download this mod
#define A2S_INFO_GOLD_IDX_MOD_NUL 16 // 0x00
#define A2S_INFO_GOLD_IDX_MOD_MODVERSION 17 // Version of the installed mod
#define A2S_INFO_GOLD_IDX_MOD_MODSIZE 18 // The download size of this mod
#define A2S_INFO_GOLD_IDX_MOD_SVONLY 19 // If 1 this is a server side only mod
#define A2S_INFO_GOLD_IDX_MOD_CIDLL 20 // If 1 this mod has a custom client dll
#define A2S_INFO_GOLD_IDX_MOD_SECURE 21 // if set to 0x01, this server is VAC secured
#define A2S_INFO_GOLD_IDX_MOD_NUMBOTS 22 // Number of bot players currently on the server
#define PATTERN "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
#define DELAY 6.0
#define TASK 386
enum _:STR_RETURN {
HOSTNAME = 0,
MAP
};
enum _:INT_RETURN {
BOTS = 0,
PLAYERS,
MAX_PLAYERS
};
new bool:g_bServerAlive;
new Float:g_flCooldown;
new bool:g_bIsWindows;
new g_strReturn[ STR_RETURN ][ 64 ];
new g_intReturn[ INT_RETURN ];
new g_szIP[ 32 ];
new g_iSocket;
public plugin_init( ) {
register_plugin( "Locate Server", "1.0", "xPaw" );
register_clcmd( "say", "hookSay" );
}
public hookSay( id ) {
new szSaid[ 40 ], szCmd[ 8 ], szIP[ 32 ];
read_args( szSaid, 39 );
remove_quotes( szSaid );
if( szSaid[ 0 ] != '/' )
return PLUGIN_CONTINUE;
parse( szSaid, szCmd, 7, szIP, 31 );
if( equali( szCmd, "/locate", 7 ) || equali( szCmd, "/ip", 3 ) ) {
new szError[ 64 ], iReturn, Regex:iResult = regex_match( szIP, PATTERN, iReturn, szError, 63 );
switch( iResult ) {
case REGEX_MATCH_FAIL, REGEX_PATTERN_FAIL: return PLUGIN_HANDLED;
case REGEX_NO_MATCH: {
GreenPrint( id, "^4[LOCATE]^1 Wrong IP Address:^3 %s", szIP );
return PLUGIN_HANDLED;
}
default: {
new szPort[ 6 ];
strtok( szIP, szIP, 31, szPort, 5, ':' );
if( !szPort[ 0 ] ) {
GreenPrint( id, "^4[LOCATE]^1 Put a port!" );
return PLUGIN_HANDLED;
}
new Float:flGametime = get_gametime( );
if( g_flCooldown < flGametime ) {
g_flCooldown = flGametime + DELAY;
GreenPrint( id, "^4[LOCATE]^1 Locating:^3 %s:%s", szIP, szPort );
if( ConnectServer( id, szIP, str_to_num( szPort ) ) ) {
SendRequest( );
set_task( 0.5, "ShowResults" );
}
regex_free( iResult );
} else {
new iSeconds = floatround( g_flCooldown - flGametime )
GreenPrint( id, "^4[LOCATE]^1 Please wait^4 %i^1 second%s!", iSeconds == 1 ? "" : "s" );
}
return PLUGIN_HANDLED;
}
}
}
return PLUGIN_CONTINUE;
}
public ShowResults( ) {
remove_task( TASK );
new szCountry[ 46 ];
geoip_country( g_szIP, szCountry, 45 );
GreenPrint( 0, "^4[LOCATE] IP:^1 %s^4 | Country:^1 %s", g_szIP, szCountry );
if( g_bServerAlive ) {
new szBots[ 16 ];
if( g_intReturn[ BOTS ] > 0 )
formatex( szBots, 15, "^1 (^3%i^1 bots)", g_intReturn[ BOTS ] );
GreenPrint( 0, "^4[LOCATE]^1 %s^4 | OS:^1 %s^4 | Map:^1 %s^4 | Players:^3 %i^1 /^3 %i%s", g_strReturn[ HOSTNAME ], g_bIsWindows ? "Windows" : "Linux",
g_strReturn[ MAP ], g_intReturn[ PLAYERS ], g_intReturn[ MAX_PLAYERS ], szBots );
} else
GreenPrint( 0, "^4[LOCATE]^1 This is not Half-Life Server!" );
DisconnectServer( );
}
public SendRequest( ) {
new szOldRequest[ 12 ], szNewRequest[ 26 ], i;
format( szOldRequest, 11, "%c%c%c%c%s", 255, 255, 255, 255, "details" );
format( szNewRequest, 25, "%c%c%c%c%c%s%c", 255, 255, 255, 255, 84, "Source Engine Query", 0 );
// Clear infos
g_bServerAlive = false;
g_bIsWindows = false;
g_strReturn[ HOSTNAME ][ 0 ] = '^0';
g_strReturn[ MAP ][ 0 ] = '^0';
g_intReturn[ BOTS ] = 0;
g_intReturn[ PLAYERS ] = 0;
g_intReturn[ MAX_PLAYERS ] = 0;
// Send sockets
for( i = -1; i < 4; i++ )
socket_send2( g_iSocket, szOldRequest, 11 );
for( i = -1; i < 4; i++ )
socket_send2( g_iSocket, szNewRequest, 25 );
set_task( 0.1, "ReceiveInfo", TASK, _, _, "b" );
return PLUGIN_CONTINUE;
}
public ReceiveInfo( ) {
if( socket_change( g_iSocket, 1 ) ) {
new szBuffer[ 1400 ], iReceivedLen;
iReceivedLen = socket_recv( g_iSocket, szBuffer, 1400 );
if( iReceivedLen > 5 ) { // shortest reply is a ping response with length of 6
g_bServerAlive = true;
if( equal( szBuffer, { -1, -1, -1, -1 }, 4 ) ) {
new aIndexes[ 100 ], szOs[ 3 ];
switch( szBuffer[ 4 ] ) {
case 'm': {
index_create( szBuffer, iReceivedLen, A2S_INFO_GOLD_REPLY_FORMAT, aIndexes )
copyc( g_strReturn[ HOSTNAME ], 63, szBuffer[ aIndexes[ A2S_INFO_GOLD_IDX_SERVERNAME ] ], 0 );
copyc( g_strReturn[ MAP ], 63, szBuffer[ aIndexes[ A2S_INFO_GOLD_IDX_MAP ] ], 0 );
copyc( szOs, 2, szBuffer[ aIndexes[ A2S_INFO_GOLD_IDX_OS ] ], 0 );
g_intReturn[ BOTS ] = szBuffer[ aIndexes[ A2S_INFO_GOLD_IDX_NUMBOTS ] ];
g_intReturn[ PLAYERS ] = szBuffer[ aIndexes[ A2S_INFO_GOLD_IDX_NUMPLAYERS ] ];
g_intReturn[ MAX_PLAYERS ] = szBuffer[ aIndexes[ A2S_INFO_GOLD_IDX_MAXPLAYERS ] ];
}
case 'I': {
index_create( szBuffer, iReceivedLen, A2S_INFO_SOURCE_REPLY_FORMAT, aIndexes )
copyc( g_strReturn[ HOSTNAME ], 63, szBuffer[ aIndexes[ A2S_INFO_SOURCE_IDX_SERVERNAME ] ], 0 );
copyc( g_strReturn[ MAP ], 63, szBuffer[ aIndexes[ A2S_INFO_SOURCE_IDX_MAP ] ], 0 );
copyc( szOs, 2, szBuffer[ aIndexes[ A2S_INFO_SOURCE_IDX_OS ] ], 0 );
g_intReturn[ BOTS ] = szBuffer[ aIndexes[ A2S_INFO_SOURCE_IDX_NUMBOTS ] ];
g_intReturn[ PLAYERS ] = szBuffer[ aIndexes[ A2S_INFO_SOURCE_IDX_NUMPLAYERS ] ];
g_intReturn[ MAX_PLAYERS ] = szBuffer[ aIndexes[ A2S_INFO_SOURCE_IDX_MAXPLAYERS ] ];
}
}
if( szOs[ 0 ] == 'w' )
g_bIsWindows = true;
}
}
}
}
public bool:ConnectServer( id, szAddress[ ], iPort ) {
if( g_iSocket > 0 )
return false;
new iError;
g_iSocket = socket_open( szAddress, iPort, SOCKET_UDP, iError );
if( g_iSocket <= 0 || iError ) {
new szError[ 40 ];
switch( iError ) {
case 0: szError = "No Error";
case 1: szError = "Error while creating socket";
case 2: szError = "Couldn't resolve hostname";
case 3: szError = "Couldn't connect to given hostname:port";
}
GreenPrint( id, "^4[LOCATE]^1 %s (^3 %s:%i ^1)", szError, szAddress, iPort );
return false;
}
copy( g_szIP, 31, szAddress );
return true;
}
public DisconnectServer( ) {
socket_close( g_iSocket );
g_iSocket = 0;
}
public index_create( sData[ 1400 ], nDataLen, sFormatString[ 100 ], aIndexes[ 100 ] ) {
new nFormatPos, nIndexPos, nDataIndex, nFormatPosMax = strlen( sFormatString );
while ((nIndexPos < nFormatPosMax) && (nDataIndex <= nDataLen)) {
switch (sFormatString[nFormatPos]) {
case '1': {
aIndexes[nIndexPos] = nDataIndex
nDataIndex++
nIndexPos++
}
case '2': {
aIndexes[nIndexPos] = nDataIndex
nDataIndex += 2
nIndexPos++
}
case '4': {
aIndexes[nIndexPos] = nDataIndex
nDataIndex += 4
nIndexPos++
}
case 's': {
aIndexes[nIndexPos] = nDataIndex
do { nDataIndex++; } while ((sData[nDataIndex] != 0) && (nDataIndex < nDataLen))
nDataIndex++
nIndexPos++
}
case '[': {
if (sData[nDataIndex] != 1)
do { nFormatPos++; } while ((sFormatString[nFormatPos] != ']') && (nFormatPos < nFormatPosMax))
nDataIndex++
nIndexPos++
}
case ']': nDataIndex++
default: nDataIndex++
}
nFormatPos++
}
return nIndexPos;
}
stock GreenPrint( id, const message[], any:... ) {
new szMessage[ 192 ];
vformat( szMessage, 191, message, 3 );
static iSayText;
if( !iSayText )
iSayText = get_user_msgid( "SayText" );
message_begin( id ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, iSayText, _, id );
write_byte( 1 );
write_string( szMessage );
message_end( );
return 1;
}
Have fun
|