00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <server/ServerHaveModFilesHandler.h>
00022 #include <server/ServerChannelManager.h>
00023 #include <server/ScorchedServer.h>
00024 #include <server/ServerCommon.h>
00025 #include <engine/ModFiles.h>
00026 #include <coms/ComsHaveModFilesMessage.h>
00027 #include <common/OptionsScorched.h>
00028 #include <common/Defines.h>
00029 #include <common/Logger.h>
00030 #include <tank/TankMod.h>
00031 #include <tank/TankContainer.h>
00032 #include <time.h>
00033
00034 ServerHaveModFilesHandler *ServerHaveModFilesHandler::instance()
00035 {
00036 static ServerHaveModFilesHandler *instance =
00037 new ServerHaveModFilesHandler;
00038 return instance;
00039 }
00040
00041 ServerHaveModFilesHandler::ServerHaveModFilesHandler()
00042 {
00043 ScorchedServer::instance()->getComsMessageHandler().addHandler(
00044 "ComsHaveModFilesMessage",
00045 this);
00046 }
00047
00048 ServerHaveModFilesHandler::~ServerHaveModFilesHandler()
00049 {
00050 }
00051
00052 bool ServerHaveModFilesHandler::processMessage(
00053 NetMessage &netMessage,
00054 const char *messageType,
00055 NetBufferReader &reader)
00056 {
00057 ComsHaveModFilesMessage message;
00058 if (!message.readMessage(reader)) return false;
00059
00060 unsigned int destinationId = netMessage.getDestinationId();
00061
00062 std::list<ModFileEntry *> neededEntries_;
00063 unsigned int neededLength = 0;
00064
00065
00066
00067 {
00068 std::map<std::string, ModFileEntry *> &modFiles =
00069 ScorchedServer::instance()->getModFiles().getFiles();
00070 std::map<std::string, ModFileEntry *>::iterator itor;
00071 for (itor = modFiles.begin();
00072 itor != modFiles.end();
00073 itor++)
00074 {
00075 const std::string &fileName = (*itor).first;
00076 ModFileEntry *fileEntry = (*itor).second;
00077
00078 ModIdentifierEntry *hasEntry =
00079 message.getFile(fileName.c_str());
00080 if (!hasEntry ||
00081 hasEntry->crc != fileEntry->getCompressedCrc() ||
00082 hasEntry->length != fileEntry->getCompressedSize())
00083 {
00084 #ifdef _DEBUG
00085 if (!hasEntry)
00086 {
00087 ServerCommon::serverLog(
00088 S3D::formatStringBuffer("Mod download \"%s\" new file",
00089 fileName.c_str()));
00090 }
00091 else if (hasEntry->length != fileEntry->getCompressedSize())
00092 {
00093 ServerCommon::serverLog(
00094 S3D::formatStringBuffer("Mod download \"%s\" size difference %u %u",
00095 fileName.c_str(),
00096 hasEntry->length,
00097 fileEntry->getCompressedSize()));
00098 }
00099 else if (hasEntry->crc != fileEntry->getCompressedCrc())
00100 {
00101 ServerCommon::serverLog(
00102 S3D::formatStringBuffer("Mod download \"%s\" crc difference %u %u",
00103 fileName.c_str(),
00104 hasEntry->crc,
00105 fileEntry->getCompressedCrc()));
00106 }
00107 #endif //_DEBUG
00108
00109 neededEntries_.push_back(fileEntry);
00110 neededLength += fileEntry->getCompressedSize();
00111 }
00112 }
00113 }
00114
00115 if (neededEntries_.empty())
00116 {
00117
00118 ServerChannelManager::instance()->sendText(
00119 ChannelText("info",
00120 "NO_MOD_FILES",
00121 "No mod files need downloading"),
00122 netMessage.getDestinationId(),
00123 false);
00124 }
00125 #ifndef S3D_SERVER
00126 else
00127 {
00128
00129
00130
00131 S3D::dialogExit("ModFiles",
00132 "ERROR: Single player client required mod files");
00133 }
00134 #else
00135 else if (ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed() == 0)
00136 {
00137
00138
00139 Logger::log("No mod and mod download disabled");
00140 ServerChannelManager::instance()->sendText(
00141 ChannelText("info",
00142 "SERVER_REQUIRES_MOD",
00143 "This server requires the \"{0}\" Scorched3D mod.\n"
00144 "The server does not allow in game file downloads.\n"
00145 "You must download and install this mod before you\n"
00146 "can connect to this server.",
00147 ScorchedServer::instance()->getOptionsGame().getMod()),
00148 destinationId,
00149 false);
00150 ServerCommon::kickDestination(destinationId);
00151 }
00152 else
00153 {
00154 int timeLeft = int(
00155 float(neededLength) /
00156 float(ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed())
00157 );
00158 int timeMinutes = timeLeft / 60;
00159 int timeSeconds = timeLeft % 60;
00160
00161
00162 ServerChannelManager::instance()->sendText(
00163 ChannelText("info",
00164 "SERVER_DOWNLOAD_MOD",
00165 "This server requires the \"{0}\" Scorched3D mod.\n"
00166 "This will require downloading {1} bytes\n"
00167 "Maximun {2} bytes per second = Minimum of {3} minutes\n"
00168 "Note: This will also depend on how many server\n"
00169 "downloads and your link speed.",
00170 ScorchedServer::instance()->getOptionsGame().getMod(),
00171 neededLength,
00172 ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed(),
00173 timeMinutes),
00174 destinationId,
00175 false);
00176 }
00177 #endif
00178
00179
00180 std::map<unsigned int, Tank *> &tanks =
00181 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00182 std::map<unsigned int, Tank *>::iterator itor;
00183 for (itor = tanks.begin();
00184 itor != tanks.end();
00185 itor++)
00186 {
00187
00188 Tank *tank = (*itor).second;
00189 if (netMessage.getDestinationId() == tank->getDestinationId())
00190 {
00191
00192 std::list<ModFileEntry *>::iterator neededItor;
00193 for (neededItor = neededEntries_.begin();
00194 neededItor != neededEntries_.end();
00195 neededItor ++)
00196 {
00197 ModFileEntry *entry = (*neededItor);
00198
00199
00200 ModIdentifierEntry newEntry(entry->getFileName(),
00201 0, entry->getCompressedCrc());
00202 tank->getMod().addFile(newEntry);
00203 }
00204 tank->getMod().setInit(true);
00205 tank->getMod().setTotalLeft(neededLength);
00206 }
00207 }
00208
00209 return true;
00210 }