ServerBrowserInfo.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <server/ServerBrowserInfo.h>
00022 #include <server/ScorchedServer.h>
00023 #include <server/ServerState.h>
00024 #include <common/OptionsScorched.h>
00025 #include <common/OptionsTransient.h>
00026 #include <common/Defines.h>
00027 #include <net/NetInterface.h>
00028 #include <tank/TankContainer.h>
00029 #include <tank/TankColorGenerator.h>
00030 #include <tank/TankState.h>
00031 #include <tank/TankScore.h>
00032 #include <string.h>
00033 
00034 ServerBrowserInfo *ServerBrowserInfo::instance_ = 0;
00035 
00036 ServerBrowserInfo *ServerBrowserInfo::instance()
00037 {
00038         if (!instance_)
00039         {
00040                 instance_ = new ServerBrowserInfo();
00041         }
00042         return instance_;
00043 }
00044 
00045 ServerBrowserInfo::ServerBrowserInfo() : udpsock_(0)
00046 {
00047         packetV_ = SDLNet_AllocPacketV(4, 10000);
00048         packetVOut_ = SDLNet_AllocPacketV(20, 10000);
00049 }
00050 
00051 ServerBrowserInfo::~ServerBrowserInfo()
00052 {
00053 }
00054 
00055 bool ServerBrowserInfo::start()
00056 {
00057         udpsock_ = SDLNet_UDP_Open(ScorchedServer::instance()->getOptionsGame().getPortNo() + 1);
00058         if(!udpsock_) return false;
00059         return true;
00060 }
00061 
00062 void ServerBrowserInfo::processMessages()
00063 { 
00064         if (!udpsock_) return;
00065 
00066         int numrecv = SDLNet_UDP_RecvV(udpsock_, packetV_);
00067         if(numrecv <=0) return;
00068         
00069         int numsent = 0;
00070         for(int i=0; i<numrecv; i++) 
00071         {
00072                 if (packetV_[i]->len == 0) packetV_[i]->data[0] = '\0';
00073 
00074                 //printf("Packet = %s\n", (char *) packetV_[i]->data);
00075                 NetInterface::getBytesIn() += packetV_[i]->len;
00076                 NetInterface::getPings() ++;
00077 
00078                 // Only compare the first few characters so a NULL is not needed
00079                 std::list<std::string> reply;
00080                 const char *wrapper = "pong";
00081                 if (0 == strncmp((char *) packetV_[i]->data, "status", 6))
00082                 {
00083                         wrapper = "status";
00084                         processStatusMessage(reply);
00085                 }
00086                 else if (0 == strncmp((char *) packetV_[i]->data, "info", 4))
00087                 {
00088                         wrapper = "info";
00089                         processInfoMessage(reply);
00090                 }
00091                 else if (0 == strncmp((char *) packetV_[i]->data, "players", 7))
00092                 {
00093                         wrapper = "players";
00094                         processPlayerMessage(reply);
00095                 }
00096 
00097                 bool first = true;
00098                 while (!reply.empty() || first)
00099                 {
00100                         first = false;
00101                         
00102                         std::string buffer = "<";
00103                         buffer += wrapper;
00104                         buffer += " ";
00105                         while (!reply.empty())
00106                         {
00107                                 std::string next = reply.front();
00108                                 reply.pop_front();
00109                                 if (strlen(next.c_str()) <= 75)
00110                                 {
00111                                         buffer += next;
00112                                 }
00113                         
00114                                 if (strlen(buffer.c_str()) > 800) break;
00115                         }
00116                         buffer += "/>";
00117                         
00118                         int len = (int) strlen(buffer.c_str())+1;
00119                         memcpy(packetVOut_[numsent]->data, buffer.c_str(), len);
00120                         packetVOut_[numsent]->len = len;
00121                         packetVOut_[numsent]->address.host = packetV_[i]->address.host;
00122                         packetVOut_[numsent]->address.port = packetV_[i]->address.port;
00123                         packetVOut_[numsent]->channel = packetV_[i]->channel;
00124                         
00125                         NetInterface::getBytesOut() += len;
00126                         //printf("Packet len = %i\n", packetVOut_[numsent]->len);
00127                         //printf("Packet = %s\n", packetVOut_[numsent]->data);
00128                         
00129                         if (++numsent > 20) break;
00130                 }
00131         }
00132         
00133         //printf("Sending %i packets\n", numsent);
00134         SDLNet_UDP_SendV(udpsock_, packetVOut_, numsent);
00135 }
00136 
00137 void ServerBrowserInfo::processStatusMessage(std::list<std::string> &reply)
00138 {
00139         char *serverName = (char *) ScorchedServer::instance()->getOptionsGame().getServerName();
00140         char version[256];
00141         snprintf(version, 256, "%s (%s)", S3D::ScorchedVersion.c_str(), S3D::ScorchedProtocolVersion.c_str());
00142         unsigned currentState = ScorchedServer::instance()->getGameState().getState();
00143         bool started = (currentState != ServerState::ServerStateTooFewPlayers);
00144         char players[25];
00145         snprintf(players, 25, "%i", ScorchedServer::instance()->getTankContainer().getNoOfTanks());
00146         char maxplayers[25];
00147         snprintf(maxplayers, 25, "%i", ScorchedServer::instance()->getOptionsGame().getNoMaxPlayers());
00148         char type[100];
00149         snprintf(type, 100, "%s (%s)", 
00150                 ScorchedServer::instance()->getOptionsTransient().getGameType(),
00151                 ((ScorchedServer::instance()->getOptionsGame().getTeams() > 1)?"Teams":"No Teams"));
00152         bool stats = (0 != strcmp(ScorchedServer::instance()->getOptionsGame().getStatsLogger(), "none"));
00153 
00154         int compplayers = 0;
00155         std::map<unsigned int, Tank *> &tanks =
00156                 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00157         std::map<unsigned int, Tank *>::iterator tanksitor;
00158         for (tanksitor = tanks.begin();
00159                 tanksitor != tanks.end();
00160                 tanksitor++)
00161         {
00162                 Tank *tank = (*tanksitor).second;
00163                 if (tank->getTankAI()) compplayers++;
00164         }
00165 
00166         reply.push_back(addTag("gametype", type));
00167         reply.push_back(addTag("state", (started?"Started":"Waiting")));
00168         reply.push_back(addTag("servername", serverName));
00169         reply.push_back(addTag("fullversion", version));
00170         reply.push_back(addTag("version", S3D::ScorchedVersion));
00171         reply.push_back(addTag("protocolversion", S3D::ScorchedProtocolVersion));
00172         reply.push_back(addTag("mod", 
00173                 ScorchedServer::instance()->getOptionsGame().getMod()));
00174         reply.push_back(addTag("password", 
00175                 ScorchedServer::instance()->getOptionsGame().getServerPassword()[0]?"On":"Off"));
00176         reply.push_back(addTag("noplayers", players));
00177         reply.push_back(addTag("maxplayers", maxplayers));
00178         reply.push_back(addTag("compplayers", S3D::formatStringBuffer("%i", compplayers)));
00179         reply.push_back(addTag("stats", (stats?"yes":"no")));
00180         reply.push_back(addTag("round", S3D::formatStringBuffer("%i/%i",
00181                 ScorchedServer::instance()->getOptionsTransient().getCurrentRoundNo(),
00182                 ScorchedServer::instance()->getOptionsGame().getNoRounds())));
00183         reply.push_back(addTag("os", S3D::getOSDesc()));
00184 }
00185 
00186 void ServerBrowserInfo::processInfoMessage(std::list<std::string> &reply)
00187 {
00188         // Add all of the other tank options
00189         // Currently nothing on the client uses this info
00190         std::list<OptionEntry *> &options = ScorchedServer::instance()->getOptionsGame().
00191                 getMainOptions().getOptions();
00192         std::list<OptionEntry *>::iterator optionItor;
00193         for (optionItor = options.begin();
00194                 optionItor != options.end();
00195                 optionItor ++)
00196         {
00197                 OptionEntry *entry = (*optionItor);
00198                 if (!(entry->getData() & OptionEntry::DataProtected) &&
00199                         !(entry->getData() & OptionEntry::DataDepricated))
00200                 {
00201                         reply.push_back(
00202                                 addTag(entry->getName(), entry->getValueAsString()));
00203                 }
00204         }       
00205 }
00206 
00207 void ServerBrowserInfo::processPlayerMessage(std::list<std::string> &reply)
00208 {
00209         // Add all of the player information
00210         char tmp[128];
00211         std::map<unsigned int, Tank *> &tanks =
00212                 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00213         std::map<unsigned int, Tank *>::iterator tankItor;
00214         int i=0;
00215         for (tankItor =  tanks.begin();
00216                 tankItor != tanks.end();
00217                 tankItor++, i++)
00218         {
00219                 Tank *tank = (*tankItor).second;
00220 
00221                 snprintf(tmp, 128, "pn%i", i);
00222                 reply.push_back(addTag(tmp, 
00223                         LangStringUtil::convertFromLang(tank->getTargetName())));
00224 
00225                 snprintf(tmp, 128, "ps%i", i);
00226                 reply.push_back(addTag(tmp, tank->getScore().getScoreString()));
00227 
00228                 snprintf(tmp, 128, "pt%i", i);
00229                 reply.push_back(addTag(tmp, tank->getScore().getTimePlayedString()));
00230 
00231                 snprintf(tmp, 128, "pm%i", i);
00232                 reply.push_back(addTag(tmp, TankColorGenerator::getTeamName(tank->getTeam()))); 
00233 
00234                 snprintf(tmp, 128, "pa%i", i);
00235                 reply.push_back(addTag(tmp, (tank->getTankAI()?"N":"Y")));
00236 
00237                 snprintf(tmp, 128, "pr%i", i);
00238                 reply.push_back(addTag(tmp, S3D::formatStringBuffer("%i", tank->getScore().getRank())));
00239         }
00240 
00241 }
00242 
00243 std::string ServerBrowserInfo::addTag(const std::string &name, const std::string &value)
00244 {
00245         std::string content(value), result;
00246         XMLNode::removeSpecialChars(content, result);
00247 
00248         return S3D::formatStringBuffer("%s='%s' ", name.c_str(), result.c_str());
00249 }

Generated on Mon Feb 16 15:14:53 2009 for Scorched3D by  doxygen 1.5.3