//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2004 // // This file is part of Scorched3D. // // Scorched3D is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Scorched3D is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include ServerHaveModFilesHandler *ServerHaveModFilesHandler::instance() { static ServerHaveModFilesHandler *instance = new ServerHaveModFilesHandler; return instance; } ServerHaveModFilesHandler::ServerHaveModFilesHandler() { ScorchedServer::instance()->getComsMessageHandler().addHandler( "ComsHaveModFilesMessage", this); } ServerHaveModFilesHandler::~ServerHaveModFilesHandler() { } bool ServerHaveModFilesHandler::processMessage(unsigned int destinationId, const char *messageType, NetBufferReader &reader) { ComsHaveModFilesMessage message; if (!message.readMessage(reader)) return false; std::list neededEntries_; unsigned int neededLength = 0; // Build up a list of mod files that this client needs // and does not already have { std::map &modFiles = ScorchedServer::instance()->getModFiles().getFiles(); std::map::iterator itor; for (itor = modFiles.begin(); itor != modFiles.end(); itor++) { const std::string &fileName = (*itor).first; ModFileEntry *fileEntry = (*itor).second; ModIdentifierEntry *hasEntry = message.getFile(fileName.c_str()); if (!hasEntry || hasEntry->crc != fileEntry->getCompressedCrc() || hasEntry->length != fileEntry->getCompressedSize()) { #ifdef _DEBUG if (!hasEntry) { ServerCommon::serverLog( formatString("Mod download \"%s\" new file", fileName.c_str())); } else if (hasEntry->length != fileEntry->getCompressedSize()) { ServerCommon::serverLog( formatString("Mod download \"%s\" size difference %u %u", fileName.c_str(), hasEntry->length, fileEntry->getCompressedSize())); } else if (hasEntry->crc != fileEntry->getCompressedCrc()) { ServerCommon::serverLog( formatString("Mod download \"%s\" crc difference %u %u", fileName.c_str(), hasEntry->crc, fileEntry->getCompressedCrc())); } #endif //_DEBUG neededEntries_.push_back(fileEntry); neededLength += fileEntry->getCompressedSize(); } } } if (neededEntries_.empty()) { // No files need downloading ServerCommon::sendString(destinationId, "No mod files need downloading", false); } else if (OptionsParam::instance()->getSinglePlayer()) { // Do a sanity check that single player games don't need to download // any mod files. As the server and client is the same process and // should be using the same mod directory. dialogExit("ModFiles", "ERROR: Single player client required mod files"); } else if (ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed() == 0) { // If this server does not allow file downloads tell the client // and disconnect them Logger::log("No mod and mod download disabled"); ServerCommon::sendString(destinationId, formatString("This server requires the \"%s\" Scorched3D mod.\n" "The server does not allow in game file downloads.\n" "You must download and install this mod before you\n" "can connect to this server.", ScorchedServer::instance()->getOptionsGame().getMod()), false); ServerCommon::kickDestination(destinationId, true); } else { int timeLeft = int( float(neededLength) / float(ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed()) ); int timeMinutes = timeLeft / 60; int timeSeconds = timeLeft % 60; // This server allows file downloads // The the client how much needs to be downloaded ServerCommon::sendString(destinationId, formatString("This server requires the \"%s\" Scorched3D mod.\n" "This will require downloading %u bytes\n" "Maximun %i bytes per second = Minimum of %i minutes, %i seconds.\n" "Note: This will also depend on how many server\n" "downloads and your link speed.", ScorchedServer::instance()->getOptionsGame().getMod(), neededLength, ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed(), timeMinutes, timeSeconds), false); } // Set the files to download in this tanks profile std::map &tanks = ScorchedServer::instance()->getTankContainer().getPlayingTanks(); std::map::iterator itor; for (itor = tanks.begin(); itor != tanks.end(); itor++) { // For each tank Tank *tank = (*itor).second; if (destinationId == tank->getDestinationId()) { // and for each needed entry std::list::iterator neededItor; for (neededItor = neededEntries_.begin(); neededItor != neededEntries_.end(); neededItor ++) { ModFileEntry *entry = (*neededItor); // Add the entry this tank needs to download ModIdentifierEntry newEntry(entry->getFileName(), 0, entry->getCompressedCrc()); tank->getMod().addFile(newEntry); } tank->getMod().setInit(true); tank->getMod().setTotalLeft(neededLength); } } return true; }