00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <server/ServerFileServer.h>
00022 #include <server/ScorchedServer.h>
00023 #include <server/ServerCommon.h>
00024 #include <tank/TankContainer.h>
00025 #include <tank/TankState.h>
00026 #include <tank/TankMod.h>
00027 #include <common/OptionsScorched.h>
00028 #include <common/Defines.h>
00029 #include <coms/ComsMessageSender.h>
00030 #include <coms/ComsInitializeMessage.h>
00031 #include <engine/ModFiles.h>
00032 #include <time.h>
00033
00034 ServerFileServer *ServerFileServer::instance_ = 0;
00035
00036 ServerFileServer *ServerFileServer::instance()
00037 {
00038 if (!instance_)
00039 {
00040 instance_ = new ServerFileServer;
00041 }
00042 return instance_;
00043 }
00044
00045 ServerFileServer::ServerFileServer() : lastTime_(0), bytesSent_(0)
00046 {
00047 }
00048
00049 ServerFileServer::~ServerFileServer()
00050 {
00051 }
00052
00053 void ServerFileServer::simulate(float timeDifference)
00054 {
00055 int downloadCount = 0;
00056
00057
00058
00059
00060
00061
00062 std::map<unsigned int, Tank *> tanks =
00063 ScorchedServer::instance()->getTankContainer().getPlayingTanks();
00064 std::map<unsigned int, Tank *>::iterator itor;
00065 for (itor = tanks.begin();
00066 itor != tanks.end();
00067 itor++)
00068 {
00069 Tank *tank = (*itor).second;
00070 if (tank->getState().getState() == TankState::sLoading)
00071 {
00072
00073 if (!tank->getMod().getFiles().empty())
00074 {
00075
00076 downloadCount++;
00077 }
00078 else
00079 {
00080
00081 if (tank->getMod().getInit())
00082 {
00083
00084 tank->getState().setState(TankState::sInitializing);
00085
00086
00087 bool allComplete = true;
00088 std::map<unsigned int, Tank *>::iterator seconditor;
00089 for (seconditor = tanks.begin();
00090 seconditor != tanks.end();
00091 seconditor++)
00092 {
00093 Tank *secondtank = (*seconditor).second;
00094 if (secondtank->getDestinationId() == tank->getDestinationId())
00095 {
00096 if (secondtank->getState().getState() ==
00097 TankState::sLoading)
00098 {
00099 allComplete = false;
00100 break;
00101 }
00102 }
00103 }
00104
00105
00106 if (allComplete)
00107 {
00108
00109 ComsInitializeMessage initMessage;
00110 ComsMessageSender::sendToSingleClient(initMessage,
00111 tank->getDestinationId());
00112 }
00113 }
00114 }
00115 }
00116 }
00117
00118
00119 if (ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed() == 0)
00120 {
00121 return;
00122 }
00123
00124
00125 if (downloadCount == 0) return;
00126
00127
00128
00129 int maxDownloadPerClient =
00130 ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed() /
00131 downloadCount;
00132
00133
00134 unsigned int theTime = (unsigned int) time(0);
00135 if (theTime > lastTime_)
00136 {
00137
00138 lastTime_ = theTime;
00139 bytesSent_ = 0;
00140
00141
00142 for (itor = tanks.begin();
00143 itor != tanks.end();
00144 itor++)
00145 {
00146 Tank *tank = (*itor).second;
00147 if (tank->getState().getState() == TankState::sLoading)
00148 {
00149 tank->getMod().setSent(false);
00150 }
00151 }
00152 }
00153
00154
00155 for (itor = tanks.begin();
00156 itor != tanks.end();
00157 itor++)
00158 {
00159
00160 if (bytesSent_ + maxDownloadPerClient >
00161 (unsigned int) ScorchedServer::instance()->getOptionsGame().getModDownloadSpeed() + 5)
00162 {
00163 return;
00164 }
00165
00166 Tank *tank = (*itor).second;
00167 if (tank->getState().getState() == TankState::sLoading)
00168 {
00169
00170
00171
00172 if (tank->getMod().getReadyToReceive() &&
00173 !tank->getMod().getFiles().empty() &&
00174 !tank->getMod().getSent())
00175 {
00176
00177 tank->getMod().setSent(true);
00178 tank->getMod().setReadyToReceive(false);
00179 bytesSent_ += maxDownloadPerClient;
00180
00181 sendBytes(tank, maxDownloadPerClient);
00182 }
00183 }
00184 }
00185 }
00186
00187 void ServerFileServer::sendBytes(Tank *tank, unsigned int size)
00188 {
00189 ComsFileMessage message;
00190
00191 while (size > 0)
00192 {
00193 unsigned int bytesSent = 0;
00194 if (!sendNextFile(message, tank, size, bytesSent)) break;
00195 size -= bytesSent;
00196 }
00197
00198 message.fileBuffer.addToBuffer("");
00199
00200
00201 ComsMessageSender::sendToSingleClient(message,
00202 tank->getDestinationId());
00203
00204 }
00205
00206 bool ServerFileServer::sendNextFile(ComsFileMessage &message,
00207 Tank *tank, unsigned int size,
00208 unsigned int &bytesSent)
00209 {
00210
00211 std::list<ModIdentifierEntry> &files =
00212 tank->getMod().getFiles();
00213 if (files.empty()) return false;
00214 ModIdentifierEntry &entry = files.front();
00215
00216
00217 std::map<std::string, ModFileEntry *> &modfiles =
00218 ScorchedServer::instance()->getModFiles().getFiles();
00219 std::map<std::string, ModFileEntry *>::iterator findItor =
00220 modfiles.find(entry.fileName);
00221 DIALOG_ASSERT(findItor != modfiles.end());
00222 ModFileEntry *modentry = (*findItor).second;
00223
00224
00225 unsigned int sizeSent = entry.length;
00226 unsigned int sizeLeftToSend = modentry->getCompressedSize() - sizeSent;
00227 unsigned int sizeToSend = MIN(sizeLeftToSend, size);
00228 unsigned int bytesLeft = tank->getMod().getTotalLeft();
00229 bool firstChunk = (sizeSent == 0);
00230 bool lastChunk = (sizeToSend == sizeLeftToSend);
00231
00232
00233 message.fileBuffer.addToBuffer(modentry->getFileName());
00234 message.fileBuffer.addToBuffer(firstChunk);
00235 message.fileBuffer.addToBuffer(lastChunk);
00236 message.fileBuffer.addToBuffer(bytesLeft);
00237 message.fileBuffer.addToBuffer(modentry->getCompressedSize());
00238 message.fileBuffer.addToBuffer(modentry->getUncompressedSize());
00239 message.fileBuffer.addToBuffer(modentry->getCompressedCrc());
00240 message.fileBuffer.addToBuffer(sizeToSend);
00241 message.fileBuffer.addDataToBuffer(modentry->getCompressedBytes() + entry.length,
00242 sizeToSend);
00243
00244
00245 entry.length += sizeToSend;
00246 tank->getMod().setTotalLeft(tank->getMod().getTotalLeft() - sizeToSend);
00247
00248
00249 if (sizeToSend == sizeLeftToSend)
00250 {
00251
00252
00253 std::string fileName = modentry->getFileName();
00254 tank->getMod().rmFile(fileName.c_str());
00255 }
00256
00257 bytesSent = sizeToSend;
00258 return true;
00259 }
00260