00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #if defined(ENABLE_NETWORK)
00013
00014 #include "../stdafx.h"
00015 #include "../rev.h"
00016 #include "../ai/ai.hpp"
00017 #include "../game/game.hpp"
00018 #include "../window_func.h"
00019 #include "../error.h"
00020 #include "../base_media_base.h"
00021 #include "../settings_type.h"
00022 #include "network_content.h"
00023
00024 #include "table/strings.h"
00025
00026 #if defined(WITH_ZLIB)
00027 #include <zlib.h>
00028 #endif
00029
00030 extern bool HasScenario(const ContentInfo *ci, bool md5sum);
00031
00033 ClientNetworkContentSocketHandler _network_content_client;
00034
00036 static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
00037 {
00038 return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : NULL) != NULL;
00039 }
00040
00048 typedef bool (*HasProc)(const ContentInfo *ci, bool md5sum);
00049
00050 bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p)
00051 {
00052 ContentInfo *ci = new ContentInfo();
00053 ci->type = (ContentType)p->Recv_uint8();
00054 ci->id = (ContentID)p->Recv_uint32();
00055 ci->filesize = p->Recv_uint32();
00056
00057 p->Recv_string(ci->name, lengthof(ci->name));
00058 p->Recv_string(ci->version, lengthof(ci->name));
00059 p->Recv_string(ci->url, lengthof(ci->url));
00060 p->Recv_string(ci->description, lengthof(ci->description), SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
00061
00062 ci->unique_id = p->Recv_uint32();
00063 for (uint j = 0; j < sizeof(ci->md5sum); j++) {
00064 ci->md5sum[j] = p->Recv_uint8();
00065 }
00066
00067 ci->dependency_count = p->Recv_uint8();
00068 ci->dependencies = MallocT<ContentID>(ci->dependency_count);
00069 for (uint i = 0; i < ci->dependency_count; i++) ci->dependencies[i] = (ContentID)p->Recv_uint32();
00070
00071 ci->tag_count = p->Recv_uint8();
00072 ci->tags = MallocT<char[32]>(ci->tag_count);
00073 for (uint i = 0; i < ci->tag_count; i++) p->Recv_string(ci->tags[i], lengthof(*ci->tags));
00074
00075 if (!ci->IsValid()) {
00076 delete ci;
00077 this->Close();
00078 return false;
00079 }
00080
00081
00082 HasProc proc = NULL;
00083 switch (ci->type) {
00084 case CONTENT_TYPE_NEWGRF:
00085 proc = HasGRFConfig;
00086 break;
00087
00088 case CONTENT_TYPE_BASE_GRAPHICS:
00089 proc = BaseGraphics::HasSet;
00090 break;
00091
00092 case CONTENT_TYPE_BASE_MUSIC:
00093 proc = BaseMusic::HasSet;
00094 break;
00095
00096 case CONTENT_TYPE_BASE_SOUNDS:
00097 proc = BaseSounds::HasSet;
00098 break;
00099
00100 case CONTENT_TYPE_AI:
00101 proc = AI::HasAI; break;
00102 break;
00103
00104 case CONTENT_TYPE_AI_LIBRARY:
00105 proc = AI::HasAILibrary; break;
00106 break;
00107
00108 case CONTENT_TYPE_GAME:
00109 proc = Game::HasGame; break;
00110 break;
00111
00112 case CONTENT_TYPE_GAME_LIBRARY:
00113 proc = Game::HasGameLibrary; break;
00114 break;
00115
00116 case CONTENT_TYPE_SCENARIO:
00117 case CONTENT_TYPE_HEIGHTMAP:
00118 proc = HasScenario;
00119 break;
00120
00121 default:
00122 break;
00123 }
00124
00125 if (proc != NULL) {
00126 if (proc(ci, true)) {
00127 ci->state = ContentInfo::ALREADY_HERE;
00128 } else {
00129 ci->state = ContentInfo::UNSELECTED;
00130 if (proc(ci, false)) ci->upgrade = true;
00131 }
00132 } else {
00133 ci->state = ContentInfo::UNSELECTED;
00134 }
00135
00136
00137 if (ci->state == ContentInfo::UNSELECTED && ci->filesize == 0) ci->state = ContentInfo::DOES_NOT_EXIST;
00138
00139
00140 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00141 ContentInfo *ici = *iter;
00142 if (ici->type == ci->type && ici->unique_id == ci->unique_id &&
00143 memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) {
00144
00145 if (StrEmpty(ci->name)) strecpy(ci->name, ici->name, lastof(ci->name));
00146 if (ici->IsSelected()) ci->state = ici->state;
00147
00148
00149
00150
00151
00152
00153
00154 ici->TransferFrom(ci);
00155 delete ci;
00156
00157 this->OnReceiveContentInfo(ici);
00158 return true;
00159 }
00160 }
00161
00162
00163 if (ci->filesize == 0) {
00164 delete ci;
00165 return true;
00166 }
00167
00168 *this->infos.Append() = ci;
00169
00170
00171 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00172 this->CheckDependencyState(*iter);
00173 }
00174
00175 this->OnReceiveContentInfo(ci);
00176
00177 return true;
00178 }
00179
00184 void ClientNetworkContentSocketHandler::RequestContentList(ContentType type)
00185 {
00186 if (type == CONTENT_TYPE_END) {
00187 this->RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
00188 this->RequestContentList(CONTENT_TYPE_BASE_MUSIC);
00189 this->RequestContentList(CONTENT_TYPE_BASE_SOUNDS);
00190 this->RequestContentList(CONTENT_TYPE_SCENARIO);
00191 this->RequestContentList(CONTENT_TYPE_HEIGHTMAP);
00192 this->RequestContentList(CONTENT_TYPE_AI);
00193 this->RequestContentList(CONTENT_TYPE_AI_LIBRARY);
00194 this->RequestContentList(CONTENT_TYPE_GAME);
00195 this->RequestContentList(CONTENT_TYPE_GAME_LIBRARY);
00196 this->RequestContentList(CONTENT_TYPE_NEWGRF);
00197 return;
00198 }
00199
00200 this->Connect();
00201
00202 Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_LIST);
00203 p->Send_uint8 ((byte)type);
00204 p->Send_uint32(_openttd_newgrf_version);
00205
00206 this->SendPacket(p);
00207 }
00208
00214 void ClientNetworkContentSocketHandler::RequestContentList(uint count, const ContentID *content_ids)
00215 {
00216 this->Connect();
00217
00218 while (count > 0) {
00219
00220
00221
00222
00223
00224 uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
00225
00226 Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID);
00227 p->Send_uint16(p_count);
00228
00229 for (uint i = 0; i < p_count; i++) {
00230 p->Send_uint32(content_ids[i]);
00231 }
00232
00233 this->SendPacket(p);
00234 count -= p_count;
00235 content_ids += p_count;
00236 }
00237 }
00238
00244 void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bool send_md5sum)
00245 {
00246 if (cv == NULL) return;
00247
00248 this->Connect();
00249
00250
00251 assert(cv->Length() < 255);
00252 assert(cv->Length() < (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / (send_md5sum ? 20 : sizeof(uint32)));
00253
00254 Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID);
00255 p->Send_uint8(cv->Length());
00256
00257 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) {
00258 const ContentInfo *ci = *iter;
00259 p->Send_uint8((byte)ci->type);
00260 p->Send_uint32(ci->unique_id);
00261 if (!send_md5sum) continue;
00262
00263 for (uint j = 0; j < sizeof(ci->md5sum); j++) {
00264 p->Send_uint8(ci->md5sum[j]);
00265 }
00266 }
00267
00268 this->SendPacket(p);
00269
00270 for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) {
00271 ContentInfo *ci = *iter;
00272 bool found = false;
00273 for (ContentIterator iter2 = this->infos.Begin(); iter2 != this->infos.End(); iter2++) {
00274 ContentInfo *ci2 = *iter2;
00275 if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
00276 (!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) {
00277 found = true;
00278 break;
00279 }
00280 }
00281 if (!found) {
00282 *this->infos.Append() = ci;
00283 } else {
00284 delete ci;
00285 }
00286 }
00287 }
00288
00295 void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uint &bytes, bool fallback)
00296 {
00297 bytes = 0;
00298
00299 ContentIDList content;
00300 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00301 const ContentInfo *ci = *iter;
00302 if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue;
00303
00304 *content.Append() = ci->id;
00305 bytes += ci->filesize;
00306 }
00307
00308 files = content.Length();
00309
00310
00311 if (files == 0) return;
00312
00313 if (_settings_client.network.no_http_content_downloads || fallback) {
00314 this->DownloadSelectedContentFallback(content);
00315 } else {
00316 this->DownloadSelectedContentHTTP(content);
00317 }
00318 }
00319
00324 void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const ContentIDList &content)
00325 {
00326 uint count = content.Length();
00327
00328
00329
00330
00331
00332 uint bytes = (10 + 1) * count + 1;
00333 char *content_request = MallocT<char>(bytes);
00334 const char *lastof = content_request + bytes - 1;
00335
00336 char *p = content_request;
00337 for (const ContentID *id = content.Begin(); id != content.End(); id++) {
00338 p += seprintf(p, lastof, "%d\n", *id);
00339 }
00340
00341 this->http_response_index = -1;
00342
00343 NetworkAddress address(NETWORK_CONTENT_MIRROR_HOST, NETWORK_CONTENT_MIRROR_PORT);
00344 new NetworkHTTPContentConnecter(address, this, NETWORK_CONTENT_MIRROR_URL, content_request);
00345
00346 }
00347
00352 void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const ContentIDList &content)
00353 {
00354 uint count = content.Length();
00355 const ContentID *content_ids = content.Begin();
00356 this->Connect();
00357
00358 while (count > 0) {
00359
00360
00361
00362
00363 uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
00364
00365 Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT);
00366 p->Send_uint16(p_count);
00367
00368 for (uint i = 0; i < p_count; i++) {
00369 p->Send_uint32(content_ids[i]);
00370 }
00371
00372 this->SendPacket(p);
00373 count -= p_count;
00374 content_ids += p_count;
00375 }
00376 }
00377
00385 static char *GetFullFilename(const ContentInfo *ci, bool compressed)
00386 {
00387 Subdirectory dir = GetContentInfoSubDir(ci->type);
00388 if (dir == NO_DIRECTORY) return NULL;
00389
00390 static char buf[MAX_PATH];
00391 FioGetFullPath(buf, lengthof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename);
00392 strecat(buf, compressed ? ".tar.gz" : ".tar", lastof(buf));
00393
00394 return buf;
00395 }
00396
00402 static bool GunzipFile(const ContentInfo *ci)
00403 {
00404 #if defined(WITH_ZLIB)
00405 bool ret = true;
00406 FILE *ftmp = fopen(GetFullFilename(ci, true), "rb");
00407 gzFile fin = gzdopen(fileno(ftmp), "rb");
00408 FILE *fout = fopen(GetFullFilename(ci, false), "wb");
00409
00410 if (fin == NULL || fout == NULL) {
00411 ret = false;
00412 } else {
00413 byte buff[8192];
00414 for (;;) {
00415 int read = gzread(fin, buff, sizeof(buff));
00416 if (read == 0) {
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 int errnum;
00430 gzerror(fin, &errnum);
00431 if (errnum != 0 && errnum != Z_STREAM_END) ret = false;
00432 break;
00433 }
00434 if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
00435
00436 ret = false;
00437 break;
00438 }
00439
00440
00441 }
00442 }
00443
00444 if (fin != NULL) {
00445
00446 gzclose(fin);
00447 } else if (ftmp != NULL) {
00448
00449
00450 fclose(ftmp);
00451 }
00452 if (fout != NULL) fclose(fout);
00453
00454 return ret;
00455 #else
00456 NOT_REACHED();
00457 #endif
00458 }
00459
00460 bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p)
00461 {
00462 if (this->curFile == NULL) {
00463 delete this->curInfo;
00464
00465 this->curInfo = new ContentInfo;
00466 this->curInfo->type = (ContentType)p->Recv_uint8();
00467 this->curInfo->id = (ContentID)p->Recv_uint32();
00468 this->curInfo->filesize = p->Recv_uint32();
00469 p->Recv_string(this->curInfo->filename, lengthof(this->curInfo->filename));
00470
00471 if (!this->BeforeDownload()) {
00472 this->Close();
00473 return false;
00474 }
00475 } else {
00476
00477 size_t toRead = (size_t)(p->size - p->pos);
00478 if (fwrite(p->buffer + p->pos, 1, toRead, this->curFile) != toRead) {
00479 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
00480 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
00481 this->Close();
00482 fclose(this->curFile);
00483 this->curFile = NULL;
00484
00485 return false;
00486 }
00487
00488 this->OnDownloadProgress(this->curInfo, (int)toRead);
00489
00490 if (toRead == 0) this->AfterDownload();
00491 }
00492
00493 return true;
00494 }
00495
00500 bool ClientNetworkContentSocketHandler::BeforeDownload()
00501 {
00502 if (!this->curInfo->IsValid()) {
00503 delete this->curInfo;
00504 this->curInfo = NULL;
00505 return false;
00506 }
00507
00508 if (this->curInfo->filesize != 0) {
00509
00510 const char *filename = GetFullFilename(this->curInfo, true);
00511 if (filename == NULL || (this->curFile = fopen(filename, "wb")) == NULL) {
00512
00513 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
00514 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
00515 return false;
00516 }
00517 }
00518 return true;
00519 }
00520
00525 void ClientNetworkContentSocketHandler::AfterDownload()
00526 {
00527
00528
00529 fclose(this->curFile);
00530 this->curFile = NULL;
00531
00532 if (GunzipFile(this->curInfo)) {
00533 unlink(GetFullFilename(this->curInfo, true));
00534
00535 Subdirectory sd = GetContentInfoSubDir(this->curInfo->type);
00536 if (sd == NO_DIRECTORY) NOT_REACHED();
00537
00538 TarScanner ts;
00539 ts.AddFile(sd, GetFullFilename(this->curInfo, false));
00540
00541 if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) {
00542
00543 ExtractTar(GetFullFilename(this->curInfo, false), BASESET_DIR);
00544 unlink(GetFullFilename(this->curInfo, false));
00545 }
00546
00547 this->OnDownloadComplete(this->curInfo->id);
00548 } else {
00549 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);
00550 }
00551 }
00552
00553
00554 void ClientNetworkContentSocketHandler::OnFailure()
00555 {
00556
00557 uint files, bytes;
00558 this->DownloadSelectedContent(files, bytes, true);
00559
00560 this->http_response.Reset();
00561 this->http_response_index = -2;
00562
00563 if (this->curFile != NULL) {
00564
00565 long size = ftell(this->curFile);
00566 if (size > 0) this->OnDownloadProgress(this->curInfo, (int)-size);
00567
00568 fclose(this->curFile);
00569 this->curFile = NULL;
00570 }
00571 }
00572
00573 void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length)
00574 {
00575 assert(data == NULL || length != 0);
00576
00577
00578 if (this->http_response_index == -2) return;
00579
00580 if (this->http_response_index == -1) {
00581 if (data != NULL) {
00582
00583 memcpy(this->http_response.Append((uint)length), data, length);
00584 return;
00585 } else {
00586
00587 *this->http_response.Append() = '\0';
00588
00589
00590 this->http_response_index = 0;
00591 }
00592 }
00593
00594 if (data != NULL) {
00595
00596 if (fwrite(data, 1, length, this->curFile) != length) {
00597
00598 this->OnFailure();
00599 } else {
00600
00601 this->OnDownloadProgress(this->curInfo, (int)length);
00602 }
00603
00604 return;
00605 }
00606
00607 if (this->curFile != NULL) {
00608
00609 this->AfterDownload();
00610 }
00611
00612 if ((uint)this->http_response_index >= this->http_response.Length()) {
00613
00614
00615
00616 this->OnFailure();
00617 return;
00618 }
00619
00620 delete this->curInfo;
00621
00622 this->curInfo = new ContentInfo;
00623
00625 #define check_not_null(p) { if ((p) == NULL) { this->OnFailure(); return; } }
00626
00627 #define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; }
00628
00629 for (;;) {
00630 char *str = this->http_response.Begin() + this->http_response_index;
00631 char *p = strchr(str, '\n');
00632 check_and_terminate(p);
00633
00634
00635 this->http_response_index += (int)strlen(str) + 1;
00636
00637
00638 p = strchr(str, ',');
00639 check_and_terminate(p);
00640 this->curInfo->id = (ContentID)atoi(str);
00641
00642
00643 str = p + 1;
00644 p = strchr(str, ',');
00645 check_and_terminate(p);
00646 this->curInfo->type = (ContentType)atoi(str);
00647
00648
00649 str = p + 1;
00650 p = strchr(str, ',');
00651 check_and_terminate(p);
00652 this->curInfo->filesize = atoi(str);
00653
00654
00655 str = p + 1;
00656
00657 if (strncmp(str, "ottd", 4) == 0) {
00658 if ((uint)this->http_response_index >= this->http_response.Length()) {
00659
00660 this->OnFailure();
00661 return;
00662 }
00663 continue;
00664 }
00665
00666 p = strrchr(str, '/');
00667 check_not_null(p);
00668 p++;
00669
00670 char tmp[MAX_PATH];
00671 if (strecpy(tmp, p, lastof(tmp)) == lastof(tmp)) {
00672 this->OnFailure();
00673 return;
00674 }
00675
00676 for (uint i = 0; i < 2; i++) {
00677 p = strrchr(tmp, '.');
00678 check_and_terminate(p);
00679 }
00680
00681
00682 strecpy(this->curInfo->filename, tmp, lastof(this->curInfo->filename));
00683
00684
00685 if (!this->BeforeDownload()) {
00686 this->OnFailure();
00687 return;
00688 }
00689
00690 NetworkHTTPSocketHandler::Connect(str, this);
00691 return;
00692 }
00693
00694 #undef check
00695 #undef check_and_terminate
00696 }
00697
00701 ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
00702 NetworkContentSocketHandler(),
00703 http_response_index(-2),
00704 curFile(NULL),
00705 curInfo(NULL),
00706 isConnecting(false)
00707 {
00708 }
00709
00711 ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler()
00712 {
00713 delete this->curInfo;
00714 if (this->curFile != NULL) fclose(this->curFile);
00715
00716 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
00717 }
00718
00720 class NetworkContentConnecter : TCPConnecter {
00721 public:
00726 NetworkContentConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00727
00728 virtual void OnFailure()
00729 {
00730 _network_content_client.isConnecting = false;
00731 _network_content_client.OnConnect(false);
00732 }
00733
00734 virtual void OnConnect(SOCKET s)
00735 {
00736 assert(_network_content_client.sock == INVALID_SOCKET);
00737 _network_content_client.isConnecting = false;
00738 _network_content_client.sock = s;
00739 _network_content_client.Reopen();
00740 _network_content_client.OnConnect(true);
00741 }
00742 };
00743
00747 void ClientNetworkContentSocketHandler::Connect()
00748 {
00749 this->lastActivity = _realtime_tick;
00750
00751 if (this->sock != INVALID_SOCKET || this->isConnecting) return;
00752 this->isConnecting = true;
00753 new NetworkContentConnecter(NetworkAddress(NETWORK_CONTENT_SERVER_HOST, NETWORK_CONTENT_SERVER_PORT, AF_UNSPEC));
00754 }
00755
00759 void ClientNetworkContentSocketHandler::Close()
00760 {
00761 if (this->sock == INVALID_SOCKET) return;
00762 NetworkContentSocketHandler::Close();
00763
00764 this->OnDisconnect();
00765 }
00766
00771 void ClientNetworkContentSocketHandler::SendReceive()
00772 {
00773 if (this->sock == INVALID_SOCKET || this->isConnecting) return;
00774
00775 if (this->lastActivity + IDLE_TIMEOUT < _realtime_tick) {
00776 this->Close();
00777 return;
00778 }
00779
00780 if (this->CanSendReceive()) {
00781 this->ReceivePackets();
00782 this->lastActivity = _realtime_tick;
00783 }
00784
00785 this->SendPackets();
00786 }
00787
00792 void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid)
00793 {
00794
00795 if (this->requested.Contains(cid)) return;
00796
00797 *this->requested.Append() = cid;
00798 assert(this->requested.Contains(cid));
00799 this->RequestContentList(1, &cid);
00800 }
00801
00807 ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid)
00808 {
00809 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00810 ContentInfo *ci = *iter;
00811 if (ci->id == cid) return ci;
00812 }
00813 return NULL;
00814 }
00815
00816
00821 void ClientNetworkContentSocketHandler::Select(ContentID cid)
00822 {
00823 ContentInfo *ci = this->GetContent(cid);
00824 if (ci == NULL || ci->state != ContentInfo::UNSELECTED) return;
00825
00826 ci->state = ContentInfo::SELECTED;
00827 this->CheckDependencyState(ci);
00828 }
00829
00834 void ClientNetworkContentSocketHandler::Unselect(ContentID cid)
00835 {
00836 ContentInfo *ci = this->GetContent(cid);
00837 if (ci == NULL || !ci->IsSelected()) return;
00838
00839 ci->state = ContentInfo::UNSELECTED;
00840 this->CheckDependencyState(ci);
00841 }
00842
00844 void ClientNetworkContentSocketHandler::SelectAll()
00845 {
00846 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00847 ContentInfo *ci = *iter;
00848 if (ci->state == ContentInfo::UNSELECTED) {
00849 ci->state = ContentInfo::SELECTED;
00850 this->CheckDependencyState(ci);
00851 }
00852 }
00853 }
00854
00856 void ClientNetworkContentSocketHandler::SelectUpgrade()
00857 {
00858 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00859 ContentInfo *ci = *iter;
00860 if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) {
00861 ci->state = ContentInfo::SELECTED;
00862 this->CheckDependencyState(ci);
00863 }
00864 }
00865 }
00866
00868 void ClientNetworkContentSocketHandler::UnselectAll()
00869 {
00870 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00871 ContentInfo *ci = *iter;
00872 if (ci->IsSelected() && ci->state != ContentInfo::ALREADY_HERE) ci->state = ContentInfo::UNSELECTED;
00873 }
00874 }
00875
00877 void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *ci)
00878 {
00879 switch (ci->state) {
00880 case ContentInfo::SELECTED:
00881 case ContentInfo::AUTOSELECTED:
00882 this->Unselect(ci->id);
00883 break;
00884
00885 case ContentInfo::UNSELECTED:
00886 this->Select(ci->id);
00887 break;
00888
00889 default:
00890 break;
00891 }
00892 }
00893
00899 void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const
00900 {
00901 for (ConstContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00902 const ContentInfo *ci = *iter;
00903 if (ci == child) continue;
00904
00905 for (uint i = 0; i < ci->dependency_count; i++) {
00906 if (ci->dependencies[i] == child->id) {
00907 *parents.Append() = ci;
00908 break;
00909 }
00910 }
00911 }
00912 }
00913
00919 void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const
00920 {
00921 *tree.Append() = child;
00922
00923
00924
00925
00926
00927 for (uint i = 0; i < tree.Length(); i++) {
00928 ConstContentVector parents;
00929 this->ReverseLookupDependency(parents, tree[i]);
00930
00931 for (ConstContentIterator piter = parents.Begin(); piter != parents.End(); piter++) {
00932 tree.Include(*piter);
00933 }
00934 }
00935 }
00936
00941 void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci)
00942 {
00943 if (ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) {
00944
00945
00946
00947 for (uint i = 0; i < ci->dependency_count; i++) {
00948 ContentInfo *c = this->GetContent(ci->dependencies[i]);
00949 if (c == NULL) {
00950 this->DownloadContentInfo(ci->dependencies[i]);
00951 } else if (c->state == ContentInfo::UNSELECTED) {
00952 c->state = ContentInfo::AUTOSELECTED;
00953 this->CheckDependencyState(c);
00954 }
00955 }
00956 return;
00957 }
00958
00959 if (ci->state != ContentInfo::UNSELECTED) return;
00960
00961
00962
00963
00964
00965 ConstContentVector parents;
00966 this->ReverseLookupDependency(parents, ci);
00967 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00968 const ContentInfo *c = *iter;
00969 if (!c->IsSelected()) continue;
00970
00971 this->Unselect(c->id);
00972 }
00973
00974 for (uint i = 0; i < ci->dependency_count; i++) {
00975 const ContentInfo *c = this->GetContent(ci->dependencies[i]);
00976 if (c == NULL) {
00977 DownloadContentInfo(ci->dependencies[i]);
00978 continue;
00979 }
00980 if (c->state != ContentInfo::AUTOSELECTED) continue;
00981
00982
00983 parents.Clear();
00984 this->ReverseLookupDependency(parents, c);
00985
00986
00987 int sel_count = 0;
00988 bool force_selection = false;
00989 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00990 if ((*iter)->IsSelected()) sel_count++;
00991 if ((*iter)->state == ContentInfo::SELECTED) force_selection = true;
00992 }
00993 if (sel_count == 0) {
00994
00995 this->Unselect(c->id);
00996 continue;
00997 }
00998
00999 if (force_selection) continue;
01000
01001
01002 parents.Clear();
01003 this->ReverseLookupTreeDependency(parents, c);
01004
01005
01006 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01007 if ((*iter)->state != ContentInfo::SELECTED) continue;
01008
01009 force_selection = true;
01010 break;
01011 }
01012
01013
01014 if (force_selection) continue;
01015
01016
01017
01018
01019
01020 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01021 const ContentInfo *c = *iter;
01022 if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id);
01023 }
01024 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01025 this->CheckDependencyState(this->GetContent((*iter)->id));
01026 }
01027 }
01028 }
01029
01031 void ClientNetworkContentSocketHandler::Clear()
01032 {
01033 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
01034
01035 this->infos.Clear();
01036 this->requested.Clear();
01037 }
01038
01039
01040
01041 void ClientNetworkContentSocketHandler::OnConnect(bool success)
01042 {
01043 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01044 ContentCallback *cb = *iter;
01045 cb->OnConnect(success);
01046 if (iter != this->callbacks.End() && *iter == cb) iter++;
01047 }
01048 }
01049
01050 void ClientNetworkContentSocketHandler::OnDisconnect()
01051 {
01052 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01053 ContentCallback *cb = *iter;
01054 cb->OnDisconnect();
01055 if (iter != this->callbacks.End() && *iter == cb) iter++;
01056 }
01057 }
01058
01059 void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo *ci)
01060 {
01061 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01062 ContentCallback *cb = *iter;
01063 cb->OnReceiveContentInfo(ci);
01064 if (iter != this->callbacks.End() && *iter == cb) iter++;
01065 }
01066 }
01067
01068 void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo *ci, int bytes)
01069 {
01070 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01071 ContentCallback *cb = *iter;
01072 cb->OnDownloadProgress(ci, bytes);
01073 if (iter != this->callbacks.End() && *iter == cb) iter++;
01074 }
01075 }
01076
01077 void ClientNetworkContentSocketHandler::OnDownloadComplete(ContentID cid)
01078 {
01079 ContentInfo *ci = this->GetContent(cid);
01080 if (ci != NULL) {
01081 ci->state = ContentInfo::ALREADY_HERE;
01082 }
01083
01084 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01085 ContentCallback *cb = *iter;
01086 cb->OnDownloadComplete(cid);
01087 if (iter != this->callbacks.End() && *iter == cb) iter++;
01088 }
01089 }
01090
01091 #endif