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 if (ftmp == NULL) return false;
00408
00409 gzFile fin = gzdopen(fileno(ftmp), "rb");
00410 FILE *fout = fopen(GetFullFilename(ci, false), "wb");
00411
00412 if (fin == NULL || fout == NULL) {
00413 ret = false;
00414 } else {
00415 byte buff[8192];
00416 for (;;) {
00417 int read = gzread(fin, buff, sizeof(buff));
00418 if (read == 0) {
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 int errnum;
00432 gzerror(fin, &errnum);
00433 if (errnum != 0 && errnum != Z_STREAM_END) ret = false;
00434 break;
00435 }
00436 if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) {
00437
00438 ret = false;
00439 break;
00440 }
00441
00442
00443 }
00444 }
00445
00446 if (fin != NULL) {
00447
00448 gzclose(fin);
00449 } else if (ftmp != NULL) {
00450
00451
00452 fclose(ftmp);
00453 }
00454 if (fout != NULL) fclose(fout);
00455
00456 return ret;
00457 #else
00458 NOT_REACHED();
00459 #endif
00460 }
00461
00462 bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p)
00463 {
00464 if (this->curFile == NULL) {
00465 delete this->curInfo;
00466
00467 this->curInfo = new ContentInfo;
00468 this->curInfo->type = (ContentType)p->Recv_uint8();
00469 this->curInfo->id = (ContentID)p->Recv_uint32();
00470 this->curInfo->filesize = p->Recv_uint32();
00471 p->Recv_string(this->curInfo->filename, lengthof(this->curInfo->filename));
00472
00473 if (!this->BeforeDownload()) {
00474 this->Close();
00475 return false;
00476 }
00477 } else {
00478
00479 size_t toRead = (size_t)(p->size - p->pos);
00480 if (fwrite(p->buffer + p->pos, 1, toRead, this->curFile) != toRead) {
00481 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
00482 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
00483 this->Close();
00484 fclose(this->curFile);
00485 this->curFile = NULL;
00486
00487 return false;
00488 }
00489
00490 this->OnDownloadProgress(this->curInfo, (int)toRead);
00491
00492 if (toRead == 0) this->AfterDownload();
00493 }
00494
00495 return true;
00496 }
00497
00502 bool ClientNetworkContentSocketHandler::BeforeDownload()
00503 {
00504 if (!this->curInfo->IsValid()) {
00505 delete this->curInfo;
00506 this->curInfo = NULL;
00507 return false;
00508 }
00509
00510 if (this->curInfo->filesize != 0) {
00511
00512 const char *filename = GetFullFilename(this->curInfo, true);
00513 if (filename == NULL || (this->curFile = fopen(filename, "wb")) == NULL) {
00514
00515 DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
00516 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
00517 return false;
00518 }
00519 }
00520 return true;
00521 }
00522
00527 void ClientNetworkContentSocketHandler::AfterDownload()
00528 {
00529
00530
00531 fclose(this->curFile);
00532 this->curFile = NULL;
00533
00534 if (GunzipFile(this->curInfo)) {
00535 unlink(GetFullFilename(this->curInfo, true));
00536
00537 Subdirectory sd = GetContentInfoSubDir(this->curInfo->type);
00538 if (sd == NO_DIRECTORY) NOT_REACHED();
00539
00540 TarScanner ts;
00541 ts.AddFile(sd, GetFullFilename(this->curInfo, false));
00542
00543 if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) {
00544
00545 ExtractTar(GetFullFilename(this->curInfo, false), BASESET_DIR);
00546 unlink(GetFullFilename(this->curInfo, false));
00547 }
00548
00549 this->OnDownloadComplete(this->curInfo->id);
00550 } else {
00551 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);
00552 }
00553 }
00554
00555
00556 void ClientNetworkContentSocketHandler::OnFailure()
00557 {
00558
00559 uint files, bytes;
00560 this->DownloadSelectedContent(files, bytes, true);
00561
00562 this->http_response.Reset();
00563 this->http_response_index = -2;
00564
00565 if (this->curFile != NULL) {
00566
00567 long size = ftell(this->curFile);
00568 if (size > 0) this->OnDownloadProgress(this->curInfo, (int)-size);
00569
00570 fclose(this->curFile);
00571 this->curFile = NULL;
00572 }
00573 }
00574
00575 void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length)
00576 {
00577 assert(data == NULL || length != 0);
00578
00579
00580 if (this->http_response_index == -2) return;
00581
00582 if (this->http_response_index == -1) {
00583 if (data != NULL) {
00584
00585 memcpy(this->http_response.Append((uint)length), data, length);
00586 return;
00587 } else {
00588
00589 *this->http_response.Append() = '\0';
00590
00591
00592 this->http_response_index = 0;
00593 }
00594 }
00595
00596 if (data != NULL) {
00597
00598 if (fwrite(data, 1, length, this->curFile) != length) {
00599
00600 this->OnFailure();
00601 } else {
00602
00603 this->OnDownloadProgress(this->curInfo, (int)length);
00604 }
00605
00606 return;
00607 }
00608
00609 if (this->curFile != NULL) {
00610
00611 this->AfterDownload();
00612 }
00613
00614 if ((uint)this->http_response_index >= this->http_response.Length()) {
00615
00616
00617
00618 this->OnFailure();
00619 return;
00620 }
00621
00622 delete this->curInfo;
00623
00624 this->curInfo = new ContentInfo;
00625
00627 #define check_not_null(p) { if ((p) == NULL) { this->OnFailure(); return; } }
00628
00629 #define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; }
00630
00631 for (;;) {
00632 char *str = this->http_response.Begin() + this->http_response_index;
00633 char *p = strchr(str, '\n');
00634 check_and_terminate(p);
00635
00636
00637 this->http_response_index += (int)strlen(str) + 1;
00638
00639
00640 p = strchr(str, ',');
00641 check_and_terminate(p);
00642 this->curInfo->id = (ContentID)atoi(str);
00643
00644
00645 str = p + 1;
00646 p = strchr(str, ',');
00647 check_and_terminate(p);
00648 this->curInfo->type = (ContentType)atoi(str);
00649
00650
00651 str = p + 1;
00652 p = strchr(str, ',');
00653 check_and_terminate(p);
00654 this->curInfo->filesize = atoi(str);
00655
00656
00657 str = p + 1;
00658
00659 if (strncmp(str, "ottd", 4) == 0) {
00660 if ((uint)this->http_response_index >= this->http_response.Length()) {
00661
00662 this->OnFailure();
00663 return;
00664 }
00665 continue;
00666 }
00667
00668 p = strrchr(str, '/');
00669 check_not_null(p);
00670 p++;
00671
00672 char tmp[MAX_PATH];
00673 if (strecpy(tmp, p, lastof(tmp)) == lastof(tmp)) {
00674 this->OnFailure();
00675 return;
00676 }
00677
00678 for (uint i = 0; i < 2; i++) {
00679 p = strrchr(tmp, '.');
00680 check_and_terminate(p);
00681 }
00682
00683
00684 strecpy(this->curInfo->filename, tmp, lastof(this->curInfo->filename));
00685
00686
00687 if (!this->BeforeDownload()) {
00688 this->OnFailure();
00689 return;
00690 }
00691
00692 NetworkHTTPSocketHandler::Connect(str, this);
00693 return;
00694 }
00695
00696 #undef check
00697 #undef check_and_terminate
00698 }
00699
00703 ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
00704 NetworkContentSocketHandler(),
00705 http_response_index(-2),
00706 curFile(NULL),
00707 curInfo(NULL),
00708 isConnecting(false),
00709 lastActivity(_realtime_tick)
00710 {
00711 }
00712
00714 ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler()
00715 {
00716 delete this->curInfo;
00717 if (this->curFile != NULL) fclose(this->curFile);
00718
00719 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
00720 }
00721
00723 class NetworkContentConnecter : TCPConnecter {
00724 public:
00729 NetworkContentConnecter(const NetworkAddress &address) : TCPConnecter(address) {}
00730
00731 virtual void OnFailure()
00732 {
00733 _network_content_client.isConnecting = false;
00734 _network_content_client.OnConnect(false);
00735 }
00736
00737 virtual void OnConnect(SOCKET s)
00738 {
00739 assert(_network_content_client.sock == INVALID_SOCKET);
00740 _network_content_client.isConnecting = false;
00741 _network_content_client.sock = s;
00742 _network_content_client.Reopen();
00743 _network_content_client.OnConnect(true);
00744 }
00745 };
00746
00750 void ClientNetworkContentSocketHandler::Connect()
00751 {
00752 this->lastActivity = _realtime_tick;
00753
00754 if (this->sock != INVALID_SOCKET || this->isConnecting) return;
00755 this->isConnecting = true;
00756 new NetworkContentConnecter(NetworkAddress(NETWORK_CONTENT_SERVER_HOST, NETWORK_CONTENT_SERVER_PORT, AF_UNSPEC));
00757 }
00758
00762 void ClientNetworkContentSocketHandler::Close()
00763 {
00764 if (this->sock == INVALID_SOCKET) return;
00765 NetworkContentSocketHandler::Close();
00766
00767 this->OnDisconnect();
00768 }
00769
00774 void ClientNetworkContentSocketHandler::SendReceive()
00775 {
00776 if (this->sock == INVALID_SOCKET || this->isConnecting) return;
00777
00778 if (this->lastActivity + IDLE_TIMEOUT < _realtime_tick) {
00779 this->Close();
00780 return;
00781 }
00782
00783 if (this->CanSendReceive()) {
00784 if (this->ReceivePackets()) {
00785
00786 this->lastActivity = _realtime_tick;
00787 }
00788 }
00789
00790 this->SendPackets();
00791 }
00792
00797 void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid)
00798 {
00799
00800 if (this->requested.Contains(cid)) return;
00801
00802 *this->requested.Append() = cid;
00803 assert(this->requested.Contains(cid));
00804 this->RequestContentList(1, &cid);
00805 }
00806
00812 ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid)
00813 {
00814 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00815 ContentInfo *ci = *iter;
00816 if (ci->id == cid) return ci;
00817 }
00818 return NULL;
00819 }
00820
00821
00826 void ClientNetworkContentSocketHandler::Select(ContentID cid)
00827 {
00828 ContentInfo *ci = this->GetContent(cid);
00829 if (ci == NULL || ci->state != ContentInfo::UNSELECTED) return;
00830
00831 ci->state = ContentInfo::SELECTED;
00832 this->CheckDependencyState(ci);
00833 }
00834
00839 void ClientNetworkContentSocketHandler::Unselect(ContentID cid)
00840 {
00841 ContentInfo *ci = this->GetContent(cid);
00842 if (ci == NULL || !ci->IsSelected()) return;
00843
00844 ci->state = ContentInfo::UNSELECTED;
00845 this->CheckDependencyState(ci);
00846 }
00847
00849 void ClientNetworkContentSocketHandler::SelectAll()
00850 {
00851 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00852 ContentInfo *ci = *iter;
00853 if (ci->state == ContentInfo::UNSELECTED) {
00854 ci->state = ContentInfo::SELECTED;
00855 this->CheckDependencyState(ci);
00856 }
00857 }
00858 }
00859
00861 void ClientNetworkContentSocketHandler::SelectUpgrade()
00862 {
00863 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00864 ContentInfo *ci = *iter;
00865 if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) {
00866 ci->state = ContentInfo::SELECTED;
00867 this->CheckDependencyState(ci);
00868 }
00869 }
00870 }
00871
00873 void ClientNetworkContentSocketHandler::UnselectAll()
00874 {
00875 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00876 ContentInfo *ci = *iter;
00877 if (ci->IsSelected() && ci->state != ContentInfo::ALREADY_HERE) ci->state = ContentInfo::UNSELECTED;
00878 }
00879 }
00880
00882 void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *ci)
00883 {
00884 switch (ci->state) {
00885 case ContentInfo::SELECTED:
00886 case ContentInfo::AUTOSELECTED:
00887 this->Unselect(ci->id);
00888 break;
00889
00890 case ContentInfo::UNSELECTED:
00891 this->Select(ci->id);
00892 break;
00893
00894 default:
00895 break;
00896 }
00897 }
00898
00904 void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const
00905 {
00906 for (ConstContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) {
00907 const ContentInfo *ci = *iter;
00908 if (ci == child) continue;
00909
00910 for (uint i = 0; i < ci->dependency_count; i++) {
00911 if (ci->dependencies[i] == child->id) {
00912 *parents.Append() = ci;
00913 break;
00914 }
00915 }
00916 }
00917 }
00918
00924 void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const
00925 {
00926 *tree.Append() = child;
00927
00928
00929
00930
00931
00932 for (uint i = 0; i < tree.Length(); i++) {
00933 ConstContentVector parents;
00934 this->ReverseLookupDependency(parents, tree[i]);
00935
00936 for (ConstContentIterator piter = parents.Begin(); piter != parents.End(); piter++) {
00937 tree.Include(*piter);
00938 }
00939 }
00940 }
00941
00946 void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci)
00947 {
00948 if (ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) {
00949
00950
00951
00952 for (uint i = 0; i < ci->dependency_count; i++) {
00953 ContentInfo *c = this->GetContent(ci->dependencies[i]);
00954 if (c == NULL) {
00955 this->DownloadContentInfo(ci->dependencies[i]);
00956 } else if (c->state == ContentInfo::UNSELECTED) {
00957 c->state = ContentInfo::AUTOSELECTED;
00958 this->CheckDependencyState(c);
00959 }
00960 }
00961 return;
00962 }
00963
00964 if (ci->state != ContentInfo::UNSELECTED) return;
00965
00966
00967
00968
00969
00970 ConstContentVector parents;
00971 this->ReverseLookupDependency(parents, ci);
00972 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00973 const ContentInfo *c = *iter;
00974 if (!c->IsSelected()) continue;
00975
00976 this->Unselect(c->id);
00977 }
00978
00979 for (uint i = 0; i < ci->dependency_count; i++) {
00980 const ContentInfo *c = this->GetContent(ci->dependencies[i]);
00981 if (c == NULL) {
00982 DownloadContentInfo(ci->dependencies[i]);
00983 continue;
00984 }
00985 if (c->state != ContentInfo::AUTOSELECTED) continue;
00986
00987
00988 parents.Clear();
00989 this->ReverseLookupDependency(parents, c);
00990
00991
00992 int sel_count = 0;
00993 bool force_selection = false;
00994 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
00995 if ((*iter)->IsSelected()) sel_count++;
00996 if ((*iter)->state == ContentInfo::SELECTED) force_selection = true;
00997 }
00998 if (sel_count == 0) {
00999
01000 this->Unselect(c->id);
01001 continue;
01002 }
01003
01004 if (force_selection) continue;
01005
01006
01007 parents.Clear();
01008 this->ReverseLookupTreeDependency(parents, c);
01009
01010
01011 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01012 if ((*iter)->state != ContentInfo::SELECTED) continue;
01013
01014 force_selection = true;
01015 break;
01016 }
01017
01018
01019 if (force_selection) continue;
01020
01021
01022
01023
01024
01025 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01026 const ContentInfo *c = *iter;
01027 if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id);
01028 }
01029 for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) {
01030 this->CheckDependencyState(this->GetContent((*iter)->id));
01031 }
01032 }
01033 }
01034
01036 void ClientNetworkContentSocketHandler::Clear()
01037 {
01038 for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter;
01039
01040 this->infos.Clear();
01041 this->requested.Clear();
01042 }
01043
01044
01045
01046 void ClientNetworkContentSocketHandler::OnConnect(bool success)
01047 {
01048 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01049 ContentCallback *cb = *iter;
01050 cb->OnConnect(success);
01051 if (iter != this->callbacks.End() && *iter == cb) iter++;
01052 }
01053 }
01054
01055 void ClientNetworkContentSocketHandler::OnDisconnect()
01056 {
01057 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01058 ContentCallback *cb = *iter;
01059 cb->OnDisconnect();
01060 if (iter != this->callbacks.End() && *iter == cb) iter++;
01061 }
01062 }
01063
01064 void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo *ci)
01065 {
01066 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01067 ContentCallback *cb = *iter;
01068 cb->OnReceiveContentInfo(ci);
01069 if (iter != this->callbacks.End() && *iter == cb) iter++;
01070 }
01071 }
01072
01073 void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo *ci, int bytes)
01074 {
01075 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01076 ContentCallback *cb = *iter;
01077 cb->OnDownloadProgress(ci, bytes);
01078 if (iter != this->callbacks.End() && *iter == cb) iter++;
01079 }
01080 }
01081
01082 void ClientNetworkContentSocketHandler::OnDownloadComplete(ContentID cid)
01083 {
01084 ContentInfo *ci = this->GetContent(cid);
01085 if (ci != NULL) {
01086 ci->state = ContentInfo::ALREADY_HERE;
01087 }
01088
01089 for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); ) {
01090 ContentCallback *cb = *iter;
01091 cb->OnDownloadComplete(cid);
01092 if (iter != this->callbacks.End() && *iter == cb) iter++;
01093 }
01094 }
01095
01096 #endif