00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00029 #include "gameserver.h"
00030
00034 GameServer::GameServer(BotKernel*b)
00035 {
00036 this->author = "eponyme";
00037 this->description = "Provides tools to query game servers";
00038 this->version = VERSION;
00039 this->name = "gameserver";
00040 this->bindFunction("q3",IN_COMMAND_HANDLER,"q3",0,10);
00041 this->bindFunction("warsow",IN_COMMAND_HANDLER,"warsow",0,10);
00042 this->bindFunction("wsw",IN_COMMAND_HANDLER,"warsow",0,10);
00043 this->bindFunction("hl",IN_COMMAND_HANDLER,"hl",0,10);
00044 this->bindFunction("cs",IN_COMMAND_HANDLER,"hl",0,10);
00045 }
00046
00053 long GameServer::strToLong(string str)
00054 {
00055 char buffer[4];
00056 long result;
00057 for(unsigned int i = 0 ; i < 4 ; i ++ )
00058 {
00059 buffer[i] = str[i] ;
00060 }
00061 result= strtoll(buffer,NULL,10);
00062 return result;
00063 }
00064
00073 string GameServer::getHLstring(unsigned int * index,char*datas) {
00074 string buffer = "";
00075 while(datas[*index] != '\x00')
00076 {
00077 buffer += datas[(*index)];
00078 (*index)++;
00079 }
00080 (*index)++;
00081 return buffer;
00082 }
00083
00092 char GameServer::getHLbyte(unsigned int*index,char*datas) {
00093 (*index)++;
00094 return datas[(*index)-1];
00095 }
00096
00104 string GameServer::getHLlong(unsigned int*index,char*datas) {
00105 string buffer = "";
00106 for(unsigned int i = 0 ; i < 4 ; i ++ ) {
00107 buffer[i] = datas[(*index)+i];
00108 }
00109 (*index)+=4;
00110 return buffer;
00111 }
00112
00120 bool GameServer::getHL1Players(vector<string>*players,char*datas) {
00121 players->clear();
00122 unsigned int index = 4 ;
00123 if ( getHLbyte(&index,datas) != '\x44' )
00124 return false;
00125 int nbPlayers = (int)getHLbyte(&index,datas) ;
00126 for(int i = 0 ; i < nbPlayers ; i ++ ) {
00127 index++;
00128 players->push_back("\""+getHLstring(&index,datas)+"\"");
00129 index += 8;
00130 }
00131 return true;
00132 }
00133
00141 bool GameServer::getHL1Challenge(string*challenge,char*datas) {
00142 unsigned int index=4;
00143 if ( getHLbyte(&index,datas) != '\x41' )
00144 return false;
00145 *challenge = getHLlong(&index,datas) ;
00146 return true;
00147 }
00148
00156 bool GameServer::getHL1Infos(map<string,string>* settings,char*datas) {
00157 unsigned int index = 5;
00158 if(datas[4] == '\x6d') {
00159 (*settings)["ip"] = getHLstring(&index,datas);
00160 (*settings)["hostname"] = getHLstring(&index,datas);
00161 (*settings)["map"] = getHLstring(&index,datas);
00162 (*settings)["gamedir"] = getHLstring(&index,datas);
00163 (*settings)["gamedesc"] = getHLstring(&index,datas);
00164 (*settings)["players"] = getHLbyte(&index,datas);
00165 (*settings)["maxplayers"] = getHLbyte(&index,datas);
00166 (*settings)["version"] = getHLbyte(&index,datas);
00167 (*settings)["dedicated"] = getHLbyte(&index,datas);
00168 (*settings)["os"] = getHLbyte(&index,datas);
00169 (*settings)["pass"] = getHLbyte(&index,datas);
00170 (*settings)["ismod"] = getHLbyte(&index,datas);
00171 (*settings)["urlinfo"] = getHLstring(&index,datas);
00172 (*settings)["urldl"] = getHLstring(&index,datas);
00173 (*settings)["unused"] = getHLstring(&index,datas);
00174 (*settings)["modversion"] = getHLlong(&index,datas);
00175 (*settings)["modsize"] = getHLlong(&index,datas);
00176 (*settings)["svonly"] = getHLbyte(&index,datas);
00177 (*settings)["cidll"] = getHLbyte(&index,datas);
00178 (*settings)["secure"] = getHLbyte(&index,datas);
00179 (*settings)["numbots"] = getHLbyte(&index,datas);
00180 return true;
00181 }
00182 else {
00183 return false;
00184 }
00185 }
00186
00192 string GameServer::getQ3GameType(string number)
00193 {
00194 if ( number == "0" )
00195 return "FFA";
00196 else if ( number == "1" )
00197 return "1v1";
00198 else if ( number == "2" )
00199 return "CB TDM";
00200 else if ( number == "3" )
00201 return "TDM";
00202 else if ( number == "4" )
00203 return "CTF" ;
00204 else if ( number == "5" )
00205 return "CA" ;
00206 else if ( number == "6" )
00207 return "FF TDM" ;
00208 else
00209 return "unknown";
00210 }
00211
00220 bool GameServer::parseWSWinfos(map<string,string>* settings,vector<string>* players,char* datas)
00221 {
00222 unsigned int index,rindex;
00223 vector<string> split = Tools::stringToVector(datas,"\x0a",1);
00224 if(split.size()>= 1 )
00225 {
00226 vector<string>sets = Tools::stringToVector(split[0],"\\",0);
00227 for ( unsigned int i = 1 ; i < sets.size() ; i +=2 ) {
00228 (*settings)[sets[i]] = sets[i+1] ;
00229 }
00230 for (unsigned int i = 1 ; i < (split.size() -1); i ++ ) {
00231 index = split[i].find("\"") ;
00232 rindex = split[i].rfind("\"");
00233 (*players).push_back(Tools::parseQ3Colors(split[i].substr(index,rindex-index+1)));
00234 }
00235 return true;
00236 }
00237 return false;
00238 }
00239
00248 bool GameServer::parseQ3infos(map<string,string>* settings,vector<string>* players,char* datas)
00249 {
00250 vector<string> split = Tools::stringToVector(datas,"\x0a",1);
00251 if(split.size()>= 1 )
00252 {
00253 vector<string>sets = Tools::stringToVector(split[0],"\\",0);
00254 for ( unsigned int i = 1 ; i < sets.size() ; i +=2 ) {
00255 (*settings)[sets[i]] = sets[i+1] ;
00256 }
00257 for (unsigned int i = 1 ; i < split.size() ; i ++ ) {
00258 (*players).push_back(Tools::parseQ3Colors(split[i].substr(split[i].find("\""))));
00259 }
00260 return true;
00261 }
00262 return false;
00263 }
00264
00274 bool GameServer::sendQuery(string ip,string port,int* sock,string query)
00275 {
00276 sockaddr_in sockname;
00277 sockname.sin_family=AF_INET;
00278 sockname.sin_addr.s_addr=inet_addr(ip.c_str());
00279 sockname.sin_port=htons(Tools::strToInt(port.c_str()));
00280 (*sock) = socket(AF_INET,SOCK_DGRAM,0);
00281 if ( (*sock) <0 ) {
00282 return false;
00283 }
00284 else {
00285 if (sendto((*sock),query.c_str(),strlen(query.c_str()),0,(struct sockaddr*)&sockname,sizeof(sockname))<0) {
00286 return false;
00287 }
00288 else {
00289 return true;
00290 }
00291 }
00292 }
00293
00301 string GameServer::getResult(int sock,char*buffer)
00302 {
00303 int nbChars;
00304 fd_set readfds;
00305 struct timeval tv;
00306 tv.tv_sec = 3;
00307 tv.tv_usec = 0;
00308 FD_ZERO(&readfds);
00309 FD_SET(sock, &readfds);
00310 if (select(sock+1, &readfds, NULL, NULL, &tv) >=0 ) {
00311 if (FD_ISSET(sock, &readfds)) {
00312 nbChars=recv(sock,buffer,MAX_CHARS,0);
00313 if ((nbChars > -1) && (nbChars <= MAX_CHARS) ) {
00314 buffer[nbChars] = '\0';
00315 return "0";
00316 }
00317 else {
00318 return "Read error" ;
00319 }
00320 }
00321 else {
00322 return "No response" ;
00323 }
00324 }
00325 else {
00326 return "Socket down" ;
00327 }
00328 }
00329
00330 extern "C"
00331 {
00332 Plugin *contruct_gameserver(BotKernel*b)
00333 {
00334 return new GameServer(b);
00335 }
00336 void destroy_gameserver(Plugin*p)
00337 {
00338 delete p;
00339 }
00340 bool q3 (Message*m,Plugin*p,BotKernel*b)
00341 {
00342 GameServer * gs = (GameServer*) p;
00343 char buffer[MAX_CHARS];
00344 map<string,string> settings;
00345 vector<string> players,split;
00346 string result,query,message;
00347 int sock;
00348 if ( m->isPublic() && (m->nbParts() == 5) ) {
00349 split = Tools::stringToVector(m->getPart(4),":",0);
00350 if ( split.size() == 2 ) {
00351 query = "\xff\xff\xff\xffgetstatus";
00352 if (gs->sendQuery(split[0],split[1],&sock,query)) {
00353 result = gs->getResult(sock,buffer);
00354 if ( result == "0" ) {
00355 if (gs->parseQ3infos(&settings,&players,buffer) ) {
00356 message = ""+Tools::parseQ3Colors(settings["sv_hostname"]) + " => Q3 " + gs->getQ3GameType(settings["g_gametype"]) + " (" + settings["gameversion"] +") on " +settings["mapname"] +" Players:"+Tools::intToStr(players.size())+ "/"+settings["sv_maxclients"] + " ("+Tools::vectorToString(players,",",0)+") blue:" + settings["Score_Blue"]+" red:"+settings["Score_Red"]+ " Time Left:"+settings["Score_Time"]+ " pb:"+settings["sv_punkbuster"]+ " pv:"+settings["g_needpass"]+"";
00357 }
00358 else {
00359 message = "* Parse error *" ;
00360 }
00361 }
00362 else {
00363 message = result ;
00364 }
00365 }
00366 else {
00367 message = "* Error, unable to send querry *";
00368 }
00369 b->send( IRCProtocol::sendMsg(m->getSource(),message) ) ;
00370 close(sock);
00371 }
00372 }
00373 return true;
00374 }
00375 bool warsow (Message*m,Plugin*p,BotKernel*b)
00376 {
00377 GameServer * gs = (GameServer*) p;
00378 char buffer[MAX_CHARS];
00379 map<string,string> settings;
00380 vector<string> players,split;
00381 string result,query,message;
00382 int sock;
00383 if ( m->isPublic() && (m->nbParts() == 5) ) {
00384 split = Tools::stringToVector(m->getPart(4),":",0);
00385 if ( split.size() == 2 ) {
00386 query = "\xff\xff\xff\xffgetinfo";
00387 if (gs->sendQuery(split[0],split[1],&sock,query)) {
00388 result = gs->getResult(sock,buffer);
00389 if ( result == "0" ) {
00390 if (gs->parseWSWinfos(&settings,&players,buffer) ) {
00391 message = ""+Tools::parseQ3Colors(settings["sv_hostname"]) + " => WSW " + settings["g_gametype"] + " (" + settings["version"] +") on " +settings["mapname"] +" Players:"+Tools::intToStr(players.size())+ "/"+settings["sv_maxclients"] + " ("+Tools::vectorToString(players,",",0)+") " + settings["g_match_score"]+ " Time Left:"+settings["g_match_time"]+ " pure:"+settings["sv_pure"]+ " pv:"+settings["g_needpass"]+"";
00392 }
00393 else {
00394 message = "* Parse error *" ;
00395 }
00396 }
00397 else {
00398 message = result ;
00399 }
00400 }
00401 else {
00402 message = "* Error, unable to send querry *";
00403 }
00404 b->send( IRCProtocol::sendMsg(m->getSource(),message) ) ;
00405 close(sock);
00406 }
00407 }
00408 return true;
00409 }
00410 bool hl (Message*m,Plugin*p,BotKernel*b)
00411 {
00412 GameServer * gs = (GameServer*) p;
00413 char buffer[MAX_CHARS];
00414 map<string,string> settings;
00415 vector<string> players,split;
00416 string result,query,message,challenge;
00417 int sock;
00418 if ( m->isPublic() && (m->nbParts() == 5) ) {
00419 split = Tools::stringToVector(m->getPart(4),":",0);
00420 if ( split.size() == 2 ) {
00421 query = "\xFF\xFF\xFF\xFF\x54\x53\x6F\x75\x72\x63\x65\x20\x45\x6E\x67\x69\x6E\x65\x20\x51\x75\x65\x72\x79\x00";
00422 if (gs->sendQuery(split[0],split[1],&sock,query)) {
00423 result = gs->getResult(sock,buffer);
00424 if ( result == "0" ) {
00425 if (!gs->getHL1Infos(&settings,buffer) ) {
00426 message = "Error, only HL1 servers are supported" ;
00427 }
00428 else {
00429 query = "\xFF\xFF\xFF\xFF\x57";
00430 if (gs->sendQuery(split[0],split[1],&sock,query)) {
00431 result = gs->getResult(sock,buffer);
00432 if ( result == "0" ) {
00433 if ( !gs->getHL1Challenge(&challenge,buffer) ) {
00434 message = "* Parse error *" ;
00435 }
00436 else {
00437 query = "\xFF\xFF\xFF\xFF\x55";
00438 for (unsigned int i = 0 ; i < 4 ; i ++ ) {
00439 query += challenge[i] ;
00440 }
00441 if (gs->sendQuery(split[0],split[1],&sock,query)) {
00442 result = gs->getResult(sock,buffer);
00443 if ( result == "0" ) {
00444 if (gs->getHL1Players(&players,buffer)) {
00445 message = ""+settings["hostname"]+ " => HL1 " + settings["gamedesc"] + " on " +settings["map"] +" Players:"+Tools::intToStr((int)settings["players"][0])+ "/"+Tools::intToStr((int)settings["maxplayers"][0])+ " ("+Tools::vectorToString(players,",",0)+") pure:"+Tools::intToStr((int)settings["secure"][0])+ " pv:"+Tools::intToStr((int)settings["pass"][0])+"";
00446 }
00447 else {
00448 message = "* Parse error *";
00449 }
00450 }
00451 else {
00452 message = result ;
00453 }
00454 }
00455 else {
00456 message = "* Unable to send query *";
00457 }
00458 }
00459 }
00460 else {
00461 message = result ;
00462 }
00463 }
00464 else {
00465 message = "* Error, unable to send querry *";
00466 }
00467 }
00468 }
00469 else {
00470 message = result ;
00471 }
00472 }
00473 else {
00474 message = "* Error, unable to send querry *";
00475 }
00476 b->send( IRCProtocol::sendMsg(m->getSource(),message) ) ;
00477 close(sock);
00478 }
00479 }
00480 return true;
00481 }
00482 }