00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <client/ClientFileHandler.h>
00022 #include <client/ClientState.h>
00023 #include <client/ScorchedClient.h>
00024 #include <engine/ModFiles.h>
00025 #include <dialogs/ProgressDialog.h>
00026 #include <common/Logger.h>
00027 #include <common/Defines.h>
00028 #include <common/OptionsScorched.h>
00029 #include <coms/ComsMessageSender.h>
00030 #include <coms/ComsFileMessage.h>
00031 #include <coms/ComsFileAkMessage.h>
00032 #include <lang/LangResource.h>
00033
00034 ClientFileHandler *ClientFileHandler::instance_ = 0;
00035
00036 ClientFileHandler *ClientFileHandler::instance()
00037 {
00038 if (!instance_)
00039 {
00040 instance_ = new ClientFileHandler;
00041 }
00042 return instance_;
00043 }
00044
00045 ClientFileHandler::ClientFileHandler() : totalBytes_(0)
00046 {
00047 ScorchedClient::instance()->getComsMessageHandler().addHandler(
00048 "ComsFileMessage",
00049 this);
00050 }
00051
00052 ClientFileHandler::~ClientFileHandler()
00053 {
00054 }
00055
00056 bool ClientFileHandler::processMessage(
00057 NetMessage &netMessage,
00058 const char *messageType,
00059 NetBufferReader &mainreader)
00060 {
00061 ComsFileMessage message;
00062 if (!message.readMessage(mainreader)) return false;
00063 NetBufferReader reader(message.fileBuffer);
00064
00065 if (ScorchedClient::instance()->getGameState().getState() !=
00066 ClientState::StateLoadFiles)
00067 {
00068 ScorchedClient::instance()->getGameState().stimulate(
00069 ClientState::StimLoadFiles);
00070 }
00071
00072 std::map<std::string, ModFileEntry *> &files =
00073 ScorchedClient::instance()->getModFiles().getFiles();
00074
00075
00076 for (;;)
00077 {
00078
00079
00080 std::string fileName;
00081 reader.getFromBuffer(fileName);
00082 if (fileName.size() == 0) break;
00083
00084
00085 bool firstChunk = false;
00086 bool lastChunk = false;
00087 reader.getFromBuffer(firstChunk);
00088 reader.getFromBuffer(lastChunk);
00089
00090
00091 unsigned int bytesLeft = 0;
00092 reader.getFromBuffer(bytesLeft);
00093 if (totalBytes_ == 0) totalBytes_ = bytesLeft;
00094
00095
00096 const char *shortFileName = fileName.c_str();
00097 if (strrchr(shortFileName, '/')) shortFileName = strrchr(shortFileName, '/') + 1;
00098 unsigned int doneBytes = totalBytes_ - bytesLeft;
00099 ProgressDialog::instance()->progressChange(
00100 LANG_RESOURCE_1("DOWNLOADING_FILE", "Downloading {0}", shortFileName),
00101 float(doneBytes * 100 / totalBytes_));
00102
00103
00104 unsigned int maxsize = 0;
00105 unsigned int uncompressedsize = 0;
00106 unsigned int crc = 0;
00107 unsigned int size = 0;
00108 reader.getFromBuffer(maxsize);
00109 reader.getFromBuffer(uncompressedsize);
00110 reader.getFromBuffer(crc);
00111 reader.getFromBuffer(size);
00112
00113
00114 if (firstChunk)
00115 {
00116
00117 std::map<std::string, ModFileEntry *>::iterator findItor =
00118 files.find(fileName);
00119 if (findItor != files.end())
00120 {
00121 delete (*findItor).second;
00122 files.erase(findItor);
00123 }
00124
00125
00126 ModFileEntry *fileEntry = new ModFileEntry;
00127 fileEntry->setFileName(fileName.c_str());
00128 fileEntry->setCompressedCrc(crc);
00129 fileEntry->setUncompressedSize(uncompressedsize);
00130 files[fileName] = fileEntry;
00131 }
00132
00133
00134 std::map<std::string, ModFileEntry *>::iterator findItor =
00135 files.find(fileName);
00136 if (findItor == files.end())
00137 {
00138 Logger::log(S3D::formatStringBuffer("Failed to find partial mod file \"%s\"",
00139 fileName.c_str()));
00140 return false;
00141 }
00142 ModFileEntry *entry = (*findItor).second;
00143
00144
00145 entry->getCompressedBuffer().addDataToBuffer(
00146 reader.getBuffer() + reader.getReadSize(), size);
00147 reader.setReadSize(reader.getReadSize() + size);
00148
00149
00150 if (lastChunk)
00151 {
00152
00153 Logger::log(S3D::formatStringBuffer(" %u/%u %s - %i bytes",
00154 doneBytes,
00155 totalBytes_,
00156 fileName.c_str(),
00157 entry->getCompressedSize()));
00158
00159
00160 if (entry->getCompressedSize() != maxsize)
00161 {
00162 Logger::log(S3D::formatStringBuffer("Downloaded mod file incorrect size \"%s\".\n"
00163 "Expected %u, got %u.",
00164 fileName.c_str(), entry->getCompressedSize(), maxsize));
00165 return false;
00166 }
00167
00168
00169 if (!entry->writeModFile(fileName.c_str(),
00170 ScorchedClient::instance()->getOptionsGame().getMod()))
00171 {
00172 Logger::log(S3D::formatStringBuffer("Failed to write mod file \"%s\"",
00173 fileName.c_str()));
00174 return false;
00175 }
00176 }
00177 }
00178
00179
00180 ComsFileAkMessage akMessage;
00181 ComsMessageSender::sendToServer(akMessage);
00182
00183 return true;
00184 }