From 4661b470f623df94f8326c240d1473f8182df956 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 9 Jan 2012 11:57:42 -0500 Subject: [PATCH 1/3] Toss useless, Windows-only plBGDownloader --- Sources/Plasma/Apps/plClient/winmain.cpp | 5 - .../PubUtilLib/plAgeLoader/CMakeLists.txt | 2 - .../PubUtilLib/plAgeLoader/plAgeLoader.cpp | 5 - .../plAgeLoader/plBackgroundDownloader.cpp | 545 ------------------ .../plAgeLoader/plBackgroundDownloader.h | 98 ---- .../plNetClient/plNetCliAgeJoiner.cpp | 3 - .../plNetClient/plNetCliAgeLeaver.cpp | 4 - 7 files changed, 662 deletions(-) delete mode 100644 Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.cpp delete mode 100644 Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.h diff --git a/Sources/Plasma/Apps/plClient/winmain.cpp b/Sources/Plasma/Apps/plClient/winmain.cpp index f2f9f5e8..ecaa639c 100644 --- a/Sources/Plasma/Apps/plClient/winmain.cpp +++ b/Sources/Plasma/Apps/plClient/winmain.cpp @@ -92,21 +92,18 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com hsBool gHasMouse = false; extern hsBool gDataServerLocal; -extern hsBool gUseBackgroundDownloader; enum { kArgSkipLoginDialog, kArgServerIni, kArgLocalData, - kArgBackgroundDownloader, }; static const CmdArgDef s_cmdLineArgs[] = { { kCmdArgFlagged | kCmdTypeBool, L"SkipLoginDialog", kArgSkipLoginDialog }, { kCmdArgFlagged | kCmdTypeString, L"ServerIni", kArgServerIni }, { kCmdArgFlagged | kCmdTypeBool, L"LocalData", kArgLocalData }, - { kCmdArgFlagged | kCmdTypeBool, L"BGDownload", kArgBackgroundDownloader }, }; /// Made globals now, so we can set them to zero if we take the border and @@ -1431,8 +1428,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC doIntroDialogs = false; if(cmdParser.IsSpecified(kArgLocalData)) gDataServerLocal = true; - if(cmdParser.IsSpecified(kArgBackgroundDownloader)) - gUseBackgroundDownloader = true; #endif const wchar *serverIni = L"server.ini"; diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/CMakeLists.txt b/Sources/Plasma/PubUtilLib/plAgeLoader/CMakeLists.txt index bab47702..5ea91cf5 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/CMakeLists.txt +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/CMakeLists.txt @@ -7,14 +7,12 @@ include_directories("../../PubUtilLib") set(plAgeLoader_SOURCES plAgeLoader.cpp plAgeLoaderPaging.cpp - plBackgroundDownloader.cpp plResPatcher.cpp ) set(plAgeLoader_HEADERS plAgeLoader.h plAgeLoaderCreatable.h - plBackgroundDownloader.h plResPatcher.h ) diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp b/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp index f07ebbee..1eb32b84 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp @@ -45,7 +45,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsResMgr.h" //#include "hsTimer.h" #include "plResPatcher.h" -#include "plBackgroundDownloader.h" #if HS_BUILD_FOR_WIN32 # include "process.h" // for getpid() #else @@ -77,7 +76,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com extern hsBool gDataServerLocal; -extern hsBool gUseBackgroundDownloader; // static plAgeLoader* plAgeLoader::fInstance=nil; @@ -120,9 +118,6 @@ void plAgeLoader::Init() RegisterAs( kAgeLoader_KEY ); plgDispatch::Dispatch()->RegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plClientMsg::Index(), GetKey()); - - if (!gDataServerLocal && gUseBackgroundDownloader) - plBackgroundDownloader::StartThread(); } // diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.cpp b/Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.cpp deleted file mode 100644 index f9d48161..00000000 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.cpp +++ /dev/null @@ -1,545 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -#include "plBackgroundDownloader.h" - -#include - -#include "pnUtils/pnUtils.h" -#include "pnNetBase/pnNetBase.h" -#include "plEncryption/plChecksum.h" - -#include "hsResMgr.h" - -#include "plAgeDescription/plAgeManifest.h" -#include "plResMgr/plResManager.h" -#include "plFile/plFileUtils.h" -#include "plFile/plEncryptedStream.h" -#include "plCompression/plZlibStream.h" -#include "plAudioCore/plAudioFileReader.h" -#include "plProgressMgr/plProgressMgr.h" - -#include "pnAsyncCore/pnAsyncCore.h" -#include "pnNetCli/pnNetCli.h" -#include "plNetGameLib/plNetGameLib.h" - -#include "pnDispatch/plDispatch.h" -#include "plStatusLog/plStatusLog.h" - -static const unsigned kMaxDownloadTries = 10; -static const wchar s_manifest[] = L"AllAges"; - -plBackgroundDownloader* plBackgroundDownloader::fInstance = NULL; - -hsBool gUseBackgroundDownloader = false; - -//============================================================================ -enum DownloaderLogType -{ - kHeader, - kInfo, - kMajorStatus, - kStatus, - kError, -}; -void BackgroundDownloaderLog(DownloaderLogType type, const char* format, ...) -{ - UInt32 color = 0; - switch (type) - { - case kHeader: color = plStatusLog::kWhite; break; - case kInfo: color = plStatusLog::kBlue; break; - case kMajorStatus: color = plStatusLog::kYellow; break; - case kStatus: color = plStatusLog::kGreen; break; - case kError: color = plStatusLog::kRed; break; - } - - static plStatusLog* gStatusLog = nil; - if (!gStatusLog) - { - gStatusLog = plStatusLogMgr::GetInstance().CreateStatusLog( - 20, - "bgdownload.log", - plStatusLog::kFilledBackground | plStatusLog::kAlignToTop | plStatusLog::kDeleteForMe); - } - - va_list args; - va_start(args, format); - - gStatusLog->AddLineV(color, format, args); - - va_end(args); -} - -//============================================================================ -class plBGDownloadStream : public plZlibStream -{ -public: - plBGDownloadStream() : plZlibStream() {} - virtual ~plBGDownloadStream() {} - - virtual UInt32 Write(UInt32 byteCount, const void* buffer); -}; - -UInt32 plBGDownloadStream::Write(UInt32 byteCount, const void* buffer) -{ - return plZlibStream::Write(byteCount, buffer); -} - -//============================================================================ -static void DownloadFileCallback(ENetError result, void* param, const wchar filename[], hsStream* writer) -{ - plBackgroundDownloader* bgdownloader = (plBackgroundDownloader*)param; - - // Retry download unless shutting down or file not found - switch (result) { - case kNetSuccess: - writer->Close(); - bgdownloader->DoneWithFile(true); - break; - - case kNetErrFileNotFound: - case kNetErrRemoteShutdown: - writer->Close(); - bgdownloader->DoneWithFile(false); - break; - - default: - writer->Rewind(); - NetCliFileDownloadRequest( - filename, - writer, - DownloadFileCallback, - param - ); - break; - } -} - -static void ManifestCallback(ENetError result, void* param, const wchar group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) -{ - plBackgroundDownloader* bgdownloader = (plBackgroundDownloader*)param; - bgdownloader->DoneWithManifest(result == kNetSuccess, manifest, entryCount); -} - -//============================================================================ -plBackgroundDownloader* plBackgroundDownloader::GetInstance() -{ - return fInstance; -} - -void plBackgroundDownloader::ThreadMain(void * param) -{ - Init(); - - plBackgroundDownloader::GetInstance()->Run(); - plBackgroundDownloader::GetInstance()->CleanUp(); - - Shutdown(); -} - -void plBackgroundDownloader::StartThread() -{ - _beginthread(plBackgroundDownloader::ThreadMain, 0, NULL); -} - -void plBackgroundDownloader::Init() -{ - fInstance = TRACKED_NEW plBackgroundDownloader(); -} - -void plBackgroundDownloader::Shutdown() -{ - delete fInstance; - fInstance = NULL; -} - -plBackgroundDownloader::plBackgroundDownloader() -{ - BackgroundDownloaderLog(kHeader, "--- Starting background download ---"); - - fBGDownloaderRun = CreateEvent( - NULL, // default security attributes - TRUE, // manual-reset event - FALSE, // initial state is signaled - NULL // unnamed - ); - - fBGDownloaderIsPaused = CreateEvent( - NULL, // default security attributes - FALSE, // manual-reset event - TRUE, // initial state is signaled - NULL // unnamed - ); -} - -plBackgroundDownloader::~plBackgroundDownloader() -{ - HANDLE runHandle = fBGDownloaderRun; - fBGDownloaderRun = NULL; - CloseHandle(runHandle); - - HANDLE pausedHandle = fBGDownloaderIsPaused; - fBGDownloaderIsPaused = NULL; - CloseHandle(pausedHandle); - - BackgroundDownloaderLog(kHeader, "--- Background download done ---"); -} - -UInt32 plBackgroundDownloader::IGetDownloadSize() -{ - if (!IGetDataManifest()) - return 0; - - UInt32 downloadSize = 0; - UInt32 downloadFiles = 0; - for (MfsFileVec::iterator i = fMfsVec.begin(); i != fMfsVec.end(); ++i) - { - plManifestFile* mfsFile = (*i); - - if (!mfsFile->IsLocalUpToDate()) - { - downloadFiles++; - downloadSize += mfsFile->GetDownloadSize(); - } - } - - BackgroundDownloaderLog(kInfo, "Got download stats, %d files, %d bytes", downloadFiles, downloadSize); - - return downloadSize; -} - -bool plBackgroundDownloader::CheckFreeSpace(UInt32 bytesNeeded) -{ -#ifdef HS_BUILD_FOR_WIN32 - ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, neededBytes; - if (GetDiskFreeSpaceEx(NULL, &freeBytesAvailable, &totalNumberOfBytes, NULL)) - { - neededBytes.HighPart = 0; - neededBytes.LowPart = bytesNeeded; - - if (neededBytes.QuadPart > freeBytesAvailable.QuadPart) - { - BackgroundDownloaderLog(kInfo, "Not enough disk space (asked for %d bytes)", bytesNeeded); - return false; - } - } -#endif // HS_BUILD_FOR_WIN32 - - return true; -} - -bool plBackgroundDownloader::IDecompressSound(plManifestFile* mfsFile, bool noOverwrite) -{ - UInt32 flags = mfsFile->GetFlags(); - - if ( (hsCheckBits(flags, plManifestFile::kSndFlagCacheSplit) || hsCheckBits(flags, plManifestFile::kSndFlagCacheStereo)) && stricmp(plFileUtils::GetFileExt(mfsFile->GetName()), "ogg") == 0) - { - plAudioFileReader* reader = plAudioFileReader::CreateReader(mfsFile->GetName(), plAudioCore::kAll, plAudioFileReader::kStreamNative); - if (!reader) - { - BackgroundDownloaderLog(kInfo, "Unable to create audio file reader for %s", mfsFile->GetName()); - return false; - } - - UInt32 size = reader->GetDataSize(); - delete reader; - - // Make sure we have enough free space - if (!CheckFreeSpace(size)) - return false; - - if (hsCheckBits(flags, plManifestFile::kSndFlagCacheSplit)) - plAudioFileReader::CacheFile(mfsFile->GetName(), true, noOverwrite); - if (hsCheckBits(flags, plManifestFile::kSndFlagCacheStereo)) - plAudioFileReader::CacheFile(mfsFile->GetName(), false, noOverwrite); - } - - return true; -} - -bool plBackgroundDownloader::Run() -{ - // Wait to be signaled that we've gotten at least as far as the startup age - WaitForSingleObject(fBGDownloaderRun, INFINITE); - - IGetDataManifest(); - - plFileUtils::CreateDir("dat"); - plFileUtils::CreateDir("sfx"); - - bool result = true; - plResManager* resMgr = ((plResManager*)hsgResMgr::ResMgr()); - - for (MfsFileVec::iterator i = fMfsVec.begin(); i != fMfsVec.end(); ++i) - { - plManifestFile* mfsFile = (*i); - - if (!mfsFile->IsLocalUpToDate()) - { - if (!CheckFreeSpace(mfsFile->GetDiskSize())) - return false; - - FileType type = IGetFile(mfsFile); - if (type == kPrp) - { - // Checks for existence before attempting to remove - resMgr->RemoveSinglePage(mfsFile->GetName()); - if (!resMgr->FindSinglePage(mfsFile->GetName())) - { - resMgr->AddSinglePage(mfsFile->GetName()); - } - } - else if (type == kOther) - { - if (!IDecompressSound(mfsFile, false)) - { - char text[MAX_PATH]; - StrPrintf(text, arrsize(text), "%s could not be decompressed", mfsFile->GetName()); - BackgroundDownloaderLog(kInfo, text ); - hsAssert(false, text); - result = false; - } - } - else - { - char text[MAX_PATH]; - StrPrintf(text, arrsize(text), "Failed downloading file: %s", mfsFile->GetName()); - BackgroundDownloaderLog(kInfo, text ); - hsAssert(false, text); - result = false; - } - } - } - - return result; -} - -void plBackgroundDownloader::CleanUp() -{ - BackgroundDownloaderLog(kMajorStatus, "Cleaning up background downloader..." ); - - for (MfsFileVec::iterator i = fMfsVec.begin(); i != fMfsVec.end(); ++i) - { - plManifestFile* file = (*i); - delete file; - } - fMfsVec.clear(); -} - -void plBackgroundDownloader::Pause() -{ - if (fBGDownloaderRun != NULL && fBGDownloaderIsPaused != NULL) - { - ResetEvent(fBGDownloaderRun); - WaitForSingleObject(fBGDownloaderIsPaused, INFINITE); - - BackgroundDownloaderLog(kStatus, "--- Background download paused ---"); - } -} - -void plBackgroundDownloader::UnPause() -{ - if (fBGDownloaderRun != NULL && fBGDownloaderIsPaused != NULL) - { - SetEvent(fBGDownloaderRun); - - BackgroundDownloaderLog(kStatus, "--- Background download resumed ---"); - } -} - -plBackgroundDownloader::FileType plBackgroundDownloader::IGetFile(const plManifestFile* mfsFile) -{ - BackgroundDownloaderLog(kInfo, " Setting up to download file %s", mfsFile->GetName()); - - bool downloadDone = false; - wchar* wServerPath = hsStringToWString(mfsFile->GetServerPath()); - int numTries = 0; - - while (!downloadDone) - { - if (WaitForSingleObject(fBGDownloaderRun, 0) == WAIT_TIMEOUT) - SignalObjectAndWait(fBGDownloaderIsPaused, fBGDownloaderRun, INFINITE, FALSE); - - if (numTries >= kMaxDownloadTries) - { - BackgroundDownloaderLog(kInfo, " Max download tries exceeded (%d). Aborting download...", kMaxDownloadTries); - return kFail; - } - - plBGDownloadStream* downloadStream = TRACKED_NEW plBGDownloadStream(); - if (!downloadStream->Open(mfsFile->GetName(), "wb")) - { - BackgroundDownloaderLog(kInfo, " Unable to create file. Aborting download..."); - return kFail; - } - - BackgroundDownloaderLog(kInfo, " Downloading file %s...", mfsFile->GetName()); - - fSuccess = false; - fDoneWithFile = false; - NetCliFileDownloadRequest( - wServerPath, - downloadStream, - DownloadFileCallback, - this - ); - - while (!fDoneWithFile) { - AsyncSleep(100); - } - - if (!fSuccess) { - // remove partial file and die (server didn't have the file or server is shutting down) - plFileUtils::RemoveFile(mfsFile->GetName(), true); - BackgroundDownloaderLog(kError, " File %s failed to download.", mfsFile->GetName()); - } - else { - AsyncSleep(100); - if (downloadStream->DecompressedOk()) { - BackgroundDownloaderLog(kInfo, " Decompress successful." ); - // download and decompress successful, do a md5 check on the resulting file - plMD5Checksum localMD5(mfsFile->GetName()); - if (localMD5 != mfsFile->GetChecksum()) { - plFileUtils::RemoveFile(mfsFile->GetName(), true); - BackgroundDownloaderLog(kError, " File %s MD5 check FAILED.", mfsFile->GetName()); - // don't set downloadDone so we attempt to re-download from the server - } - else { - BackgroundDownloaderLog(kInfo, " MD5 check succeeded."); - downloadDone = true; - } - } - else { - plFileUtils::RemoveFile(mfsFile->GetName(), true); - BackgroundDownloaderLog(kError, " File %s failed to decompress.", mfsFile->GetName()); - // don't set downloadDone so we attempt to re-download from the server - } - } - - delete downloadStream; - - ++numTries; - } - delete [] wServerPath; - - if (!fSuccess) - return kFail; - - if (stricmp(plFileUtils::GetFileExt(mfsFile->GetName()), "prp") == 0) - return kPrp; - - return kOther; -} - -bool plBackgroundDownloader::IGetDataManifest() -{ - if (fMfsVec.size() > 0) - return true; - - BackgroundDownloaderLog(kMajorStatus, "Downloading new manifest from data server..." ); - - fSuccess = false; - unsigned numTries = 0; - while (!fSuccess) - { - numTries++; - fDoneWithFile = false; - NetCliFileManifestRequest(ManifestCallback, this, s_manifest); - while (!fDoneWithFile) - { - NetClientUpdate(); - plgDispatch::Dispatch()->MsgQueueProcess(); - AsyncSleep(10); - } - - if (!fSuccess) - { - fMfsVec.clear(); // clear out any bad data - if (numTries > kMaxDownloadTries) - break; // abort - } - } - - if (fSuccess) - BackgroundDownloaderLog(kStatus, "New manifest read; number of files: %d", fMfsVec.size() ); - else - BackgroundDownloaderLog(kStatus, "Failed to download manifest after trying %d times", kMaxDownloadTries); - - return fSuccess; -} - -void plBackgroundDownloader::DoneWithFile(bool success) -{ - fDoneWithFile = true; - fSuccess = success; -} - -void plBackgroundDownloader::DoneWithManifest(bool success, const NetCliFileManifestEntry manifestEntires[], unsigned entryCount) -{ - BackgroundDownloaderLog(kStatus, "New age manifest received. Reading..."); - - if (success) - { - for (unsigned i = 0; i < entryCount; i++) - { - char* name = hsWStringToString(manifestEntires[i].clientName); - char* serverPath = hsWStringToString(manifestEntires[i].downloadName); - char* md5Str = hsWStringToString(manifestEntires[i].md5); - int size = manifestEntires[i].fileSize; - int zipsize = manifestEntires[i].zipSize; - int flags = manifestEntires[i].flags; - if (stricmp(plFileUtils::GetFileExt(name), "gz")) - flags |= plManifestFile::kFlagZipped; // add zipped flag if necessary - - plMD5Checksum sum; - sum.SetFromHexString(md5Str); - fMfsVec.push_back(TRACKED_NEW plManifestFile(name, serverPath, sum, size, zipsize, flags, false)); - - delete [] name; - delete [] serverPath; - delete [] md5Str; - } - } - - fDoneWithFile = true; - fSuccess = success; -} diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.h b/Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.h deleted file mode 100644 index a9802fca..00000000 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.h +++ /dev/null @@ -1,98 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -#ifndef plBackgroundDownloader_h_inc -#define plBackgroundDownloader_h_inc - -#include - -#include "hsTypes.h" - -class plManifestFile; -struct NetCliFileManifestEntry; - -class plBackgroundDownloader -{ -protected: - static plBackgroundDownloader* fInstance; - static void Init(); - static void Shutdown(); - static void ThreadMain(void * param); - - plBackgroundDownloader(); - ~plBackgroundDownloader(); - - HANDLE fBGDownloaderRun; - HANDLE fBGDownloaderIsPaused; - - enum FileType {kFail, kPrp, kOther}; - - typedef std::vector MfsFileVec; - MfsFileVec fMfsVec; - -public: - - bool fDoneWithFile; - bool fSuccess; - - bool IGetDataManifest(); - FileType IGetFile(const plManifestFile* mfsFile); - UInt32 IGetDownloadSize(); - bool IDecompressSound(plManifestFile* mfsFile, bool noOverwrite = false); - -public: - static plBackgroundDownloader* GetInstance(); - static void StartThread(); - - bool Run(); - void CleanUp(); - - void Pause(); - void UnPause(); - - static bool CheckFreeSpace(UInt32 bytesNeeded); - - // called by download callbacks to tell it we are done with the current file - void DoneWithFile(bool success); - void DoneWithManifest(bool success, const NetCliFileManifestEntry manifestEntires[], unsigned entryCount); -}; - -#endif //plBackgroundDownloader_h_inc \ No newline at end of file diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp index 36ef1dcf..a917f177 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp @@ -59,7 +59,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plNetClientComm/plNetClientComm.h" #include "plAgeLoader/plAgeLoader.h" -#include "plAgeLoader/plBackgroundDownloader.h" #include "plAvatar/plAvatarMgr.h" #include "plVault/plVault.h" @@ -201,8 +200,6 @@ void plNCAgeJoiner::Complete (bool success, const char msg[]) { DEL(this); } - if (plBackgroundDownloader::GetInstance()) - plBackgroundDownloader::GetInstance()->UnPause(); } //============================================================================ diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeLeaver.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeLeaver.cpp index 4dfb0108..c52ce77a 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeLeaver.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeLeaver.cpp @@ -54,7 +54,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plNetClientComm/plNetClientComm.h" #include "plNetGameLib/plNetGameLib.h" #include "plAgeLoader/plAgeLoader.h" -#include "plAgeLoader/plBackgroundDownloader.h" #include "plAvatar/plAvatarMgr.h" #include "plVault/plVault.h" @@ -126,9 +125,6 @@ plNCAgeLeaver::~plNCAgeLeaver () { //============================================================================ void plNCAgeLeaver::Start () { - if (plBackgroundDownloader::GetInstance()) - plBackgroundDownloader::GetInstance()->Pause(); - nextOp = kLinkOutFX; } From 846f2c870b5d97bdc917b7e2c2b351f0b5a95a02 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 16 Jan 2012 18:43:57 -0500 Subject: [PATCH 2/3] Replaced the unused plNCAgeJoinerMsg with plResPatcherMsg --- .../Plasma/NucleusLib/inc/plCreatableIndex.h | 2 +- .../PubUtilLib/plMessage/CMakeLists.txt | 3 +- .../PubUtilLib/plMessage/plMessageCreatable.h | 4 +- .../PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp | 48 ------------------- .../{plNCAgeJoinerMsg.h => plResPatcherMsg.h} | 40 +++++++++------- .../plNetClient/plNetLinkingMgr.cpp | 1 - 6 files changed, 26 insertions(+), 72 deletions(-) delete mode 100644 Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp rename Sources/Plasma/PubUtilLib/plMessage/{plNCAgeJoinerMsg.h => plResPatcherMsg.h} (65%) diff --git a/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h b/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h index eed0148b..bb02102f 100644 --- a/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h +++ b/Sources/Plasma/NucleusLib/inc/plCreatableIndex.h @@ -565,7 +565,7 @@ CLASS_INDEX_LIST_START CLASS_INDEX(plNetServerMsgFindVaultServer), CLASS_INDEX(plNetServerMsgFindVaultServerReply), CLASS_INDEX(plAvTaskSeekDoneMsg), - CLASS_INDEX(plNCAgeJoinerMsg), + CLASS_INDEX(plResPatcherMsg), CLASS_INDEX(plNetServerMsgVaultTask), CLASS_INDEX(plNetMsgVaultTask), CLASS_INDEX(plAgeLinkStruct), diff --git a/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt b/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt index bdd8e12e..a6be9e4c 100644 --- a/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt +++ b/Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt @@ -29,7 +29,6 @@ set(plMessage_SOURCES plLOSRequestMsg.cpp plMatrixUpdateMsg.cpp plMultistageMsg.cpp - plNCAgeJoinerMsg.cpp plNetClientMgrMsg.cpp plNetCommMsgs.cpp plNetVoiceListMsg.cpp @@ -92,7 +91,6 @@ set(plMessage_HEADERS plMessageCreatable.h plMovieMsg.h plMultistageMsg.h - plNCAgeJoinerMsg.h plNetClientMgrMsg.h plNetCommMsgs.h plNetOwnershipMsg.h @@ -107,6 +105,7 @@ set(plMessage_HEADERS plRenderRequestMsg.h plReplaceGeometryMsg.h plResMgrHelperMsg.h + plResPatcherMsg.h plResponderMsg.h plRideAnimatedPhysMsg.h plRippleShapeMsg.h diff --git a/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h b/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h index 266db8e9..6cbdbdbc 100644 --- a/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h +++ b/Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h @@ -337,8 +337,8 @@ REGISTER_CREATABLE(plPreloaderMsg); #include "plNetClientMgrMsg.h" REGISTER_CREATABLE(plNetClientMgrMsg); -#include "plNCAgeJoinerMsg.h" -REGISTER_CREATABLE(plNCAgeJoinerMsg); +#include "plResPatcherMsg.h" +REGISTER_CREATABLE(plResPatcherMsg); #include "plAccountUpdateMsg.h" REGISTER_CREATABLE(plAccountUpdateMsg); diff --git a/Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp b/Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp deleted file mode 100644 index 00908a8c..00000000 --- a/Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ -/***************************************************************************** -* -* $/Plasma20/Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp -* -***/ - -#include "plNCAgeJoinerMsg.h" diff --git a/Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.h b/Sources/Plasma/PubUtilLib/plMessage/plResPatcherMsg.h similarity index 65% rename from Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.h rename to Sources/Plasma/PubUtilLib/plMessage/plResPatcherMsg.h index 23710b66..be26542c 100644 --- a/Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.h +++ b/Sources/Plasma/PubUtilLib/plMessage/plResPatcherMsg.h @@ -39,32 +39,36 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -/***************************************************************************** -* -* $/Plasma20/Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.h -* -***/ - -#ifndef PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLMESSAGE_PLNCAGEJOINERMSG_H -#define PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLMESSAGE_PLNCAGEJOINERMSG_H +#ifndef _PLMESSAGE_PLRESPATCHERMSG_H +#define _PLMESSAGE_PLRESPATCHERMSG_H +#include "HeadSpin.h" #include "pnMessage/plMessage.h" +// This message is sent when plResPatcher has completed its async operation +class plResPatcherMsg : public plMessage { + bool fSuccess; + char* fError; -class plNCAgeJoinerMsg : public plMessage { public: - enum { - kHACK_NotifyRcvdAllSDLStates, // Just until the server is working again - }; + plResPatcherMsg() : fSuccess(true), fError(nil) { SetBCastFlag(kBCastByExactType); } + plResPatcherMsg(bool success, const char* error) : fSuccess(success) + { + SetBCastFlag(kBCastByExactType); + fError = hsStrcpy(error); + } - unsigned type; + ~plResPatcherMsg() { delete[] fError; } - CLASSNAME_REGISTER(plNCAgeJoinerMsg); - GETINTERFACE_ANY(plNCAgeJoinerMsg, plMessage); + CLASSNAME_REGISTER(plResPatcherMsg); + GETINTERFACE_ANY(plResPatcherMsg, plMessage); - void Read (hsStream *, hsResMgr *) { FATAL("plNCAgeJoinerMsg::Read"); } - void Write (hsStream *, hsResMgr *) { FATAL("plNCAgeJoinerMsg::Write"); } + void Read (hsStream *, hsResMgr *) { FATAL("What the hell are you doing?"); } + void Write (hsStream *, hsResMgr *) { FATAL("What the hell are you doing?"); } + + const char* GetError() const { return fError; } + bool Success() const { return fSuccess; } }; -#endif // PLASMA20_SOURCES_PLASMA_PUBUTILLIB_PLMESSAGE_PLNCAGEJOINERMSG_H +#endif // _PLMESSAGE_PLRESPATCHERMSG_H diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp index b6416c9c..89d0d1d2 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp @@ -61,7 +61,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plAvatar/plAvatarMgr.h" #include "plAvatar/plArmatureMod.h" #include "plFile/hsFiles.h" -#include "plMessage/plNCAgeJoinerMsg.h" /***************************************************************************** From 032a577111e4373fc1b4c9b64ddcd7b3abdb1bdc Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 16 Jan 2012 21:28:00 -0500 Subject: [PATCH 3/3] Implement a new, asynchronous plResPatcher singleton --- Sources/Plasma/Apps/plClient/plClient.cpp | 54 +- Sources/Plasma/Apps/plClient/plClient.h | 2 - .../PubUtilLib/plAgeLoader/plAgeLoader.cpp | 20 +- .../PubUtilLib/plAgeLoader/plAgeLoader.h | 2 +- .../PubUtilLib/plAgeLoader/plResPatcher.cpp | 562 ++++++------------ .../PubUtilLib/plAgeLoader/plResPatcher.h | 71 +-- .../plNetClient/plNetCliAgeJoiner.cpp | 26 +- .../PubUtilLib/plNetClient/plNetClientMgr.cpp | 2 + 8 files changed, 268 insertions(+), 471 deletions(-) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index 39b5b5a4..24e802be 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -78,6 +78,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plMessage/plPreloaderMsg.h" #include "plMessage/plNetCommMsgs.h" #include "plMessage/plAgeLoadedMsg.h" +#include "plMessage/plResPatcherMsg.h" #include "pfConsoleCore/pfConsoleEngine.h" #include "pfConsole/pfConsole.h" @@ -199,8 +200,7 @@ plClient::plClient() fHoldLoadRequests(false), fNumLoadingRooms(0), fNumPostLoadMsgs(0), - fPostLoadMsgInc(0.f), - fPatchGlobalAges(false) + fPostLoadMsgInc(0.f) { #ifndef PLASMA_EXTERNAL_RELEASE bPythonDebugConnected = false; @@ -863,6 +863,14 @@ hsBool plClient::MsgReceive(plMessage* msg) return true; } + //============================================================================ + // plResPatcherMsg + //============================================================================ + if (plResPatcherMsg * resMsg = plResPatcherMsg::ConvertNoRef(msg)) { + plgDispatch::Dispatch()->UnRegisterForExactType(plResPatcherMsg::Index(), GetKey()); + IOnAsyncInitComplete(); + } + return hsKeyedObject::MsgReceive(msg); } @@ -1578,26 +1586,19 @@ hsBool plClient::StartInit() //============================================================================ void plClient::IPatchGlobalAgeFiles( void ) { - const char * ageFiles[] = { - "GlobalAnimations", - "GlobalAvatars", - "GlobalClothing", - "GlobalMarkers", - "GUI", - "CustomAvatars" - }; - - for (unsigned i = 0; i < arrsize(ageFiles); ++i) { - plResPatcher myPatcher(ageFiles[i], true); - - if (gDataServerLocal) - break; - - if (!myPatcher.Update()) { - SetDone(true); - break; - } + plResPatcher* patcher = plResPatcher::GetInstance(); + if (!gDataServerLocal) + { + patcher->RequestManifest(L"CustomAvatars"); + patcher->RequestManifest(L"GlobalAnimations"); + patcher->RequestManifest(L"GlobalAvatars"); + patcher->RequestManifest(L"GlobalClothing"); + patcher->RequestManifest(L"GlobalMarkers"); + patcher->RequestManifest(L"GUI"); } + + plgDispatch::Dispatch()->RegisterForExactType(plResPatcherMsg::Index(), GetKey()); + patcher->Start(); } void plClient::InitDLLs() @@ -1801,15 +1802,6 @@ hsBool plClient::IUpdate() plgDispatch::MsgSend(cameras); plProfile_EndTiming(CameraMsg); - if (fPatchGlobalAges) - { - // Download or patch our global ages, if necessary - IPatchGlobalAgeFiles(); - IOnAsyncInitComplete(); - - fPatchGlobalAges = false; - } - return false; } @@ -2530,7 +2522,7 @@ void plClient::IHandlePreloaderMsg (plPreloaderMsg * msg) { return; } - fPatchGlobalAges = true; + IPatchGlobalAgeFiles(); } //============================================================================ diff --git a/Sources/Plasma/Apps/plClient/plClient.h b/Sources/Plasma/Apps/plClient/plClient.h index 72f4b6ba..b99b4efd 100644 --- a/Sources/Plasma/Apps/plClient/plClient.h +++ b/Sources/Plasma/Apps/plClient/plClient.h @@ -152,8 +152,6 @@ protected: hsBool fQuitIntro; hsTArray fMovies; - hsBool fPatchGlobalAges; - plMessagePumpProc fMessagePumpProc; #ifndef PLASMA_EXTERNAL_RELEASE diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp b/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp index 1eb32b84..fdbe432c 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp @@ -63,6 +63,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plResMgr/plKeyFinder.h" #include "plAgeDescription/plAgeDescription.h" #include "plSDL/plSDL.h" +#include "plMessage/plResPatcherMsg.h" #include "plNetClient/plNetClientMgr.h" #include "plResMgr/plRegistryHelpers.h" #include "plResMgr/plRegistryNode.h" @@ -110,7 +111,7 @@ plAgeLoader::~plAgeLoader() void plAgeLoader::Shutdown() { - + plResPatcher::GetInstance()->Shutdown(); } void plAgeLoader::Init() @@ -170,17 +171,18 @@ bool plAgeLoader::LoadAge(const char ageName[]) } //============================================================================ -bool plAgeLoader::UpdateAge(const char ageName[]) +void plAgeLoader::UpdateAge(const char ageName[]) { - bool result = true; - - if (!gDataServerLocal) + if (gDataServerLocal) + // We have to send this msg ourselves since we're not actually updating + plgDispatch::Dispatch()->MsgSend(new plResPatcherMsg); + else { - plResPatcher myPatcher(ageName); - result = myPatcher.Update(); + wchar_t* wideAgeName = hsStringToWString(ageName); + plResPatcher::GetInstance()->RequestManifest(wideAgeName); + plResPatcher::GetInstance()->Start(); + delete[] wideAgeName; } - - return result; } //============================================================================ diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.h b/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.h index 22a6599c..7ec3baff 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.h +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.h @@ -110,7 +110,7 @@ public: hsBool MsgReceive(plMessage* msg); bool LoadAge(const char ageName[]); bool UnloadAge() { return IUnloadAge(); } - bool UpdateAge(const char ageName[]); + void UpdateAge(const char ageName[]); void NotifyAgeLoaded( bool loaded ); const plKeyVec& PendingPageOuts() const { return fPendingPageOuts; } diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp index ad5d0cff..57154f9a 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp @@ -39,455 +39,245 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com Mead, WA 99021 *==LICENSE==*/ -#include "plResPatcher.h" -#include "hsResMgr.h" +#include "plResPatcher.h" -#include "plAgeDescription/plAgeManifest.h" -#include "plResMgr/plResManager.h" -#include "plFile/plFileUtils.h" -#include "plFile/plEncryptedStream.h" +#include "plAgeLoader/plAgeLoader.h" #include "plCompression/plZlibStream.h" -#include "plAudioCore/plAudioFileReader.h" -#include "plProgressMgr/plProgressMgr.h" - -#include "pnAsyncCore/pnAsyncCore.h" -#include "pnNetCli/pnNetCli.h" +#include "plEncryption/plChecksum.h" +#include "plFile/plFileUtils.h" +#include "plMessage/plResPatcherMsg.h" +#include "pnNetBase/pnNbError.h" #include "plNetGameLib/plNetGameLib.h" - -#include "pnDispatch/plDispatch.h" +#include "plProgressMgr/plProgressMgr.h" #include "plStatusLog/plStatusLog.h" -static const unsigned kMaxDownloadTries = 10; - -////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// -class plDownloadStream : public plZlibStream +class plResDownloadStream : public plZlibStream { -private: plOperationProgress* fProgress; - unsigned fBytesReceived; -public: - plDownloadStream(plOperationProgress* progress) : fProgress(progress), fBytesReceived(0), plZlibStream() {} - virtual ~plDownloadStream() {} + bool fIsZipped; - virtual UInt32 Write(UInt32 byteCount, const void* buffer); +public: + plResDownloadStream(plOperationProgress* prog, const wchar_t* reqFile) + : fProgress(prog) + { + fIsZipped = wcscmp(plFileUtils::GetFileExt(reqFile), L"gz") == 0; + } - void RewindProgress() {fProgress->Increment(-(hsScalar)fBytesReceived);} // rewind the progress bar by as far as we got + UInt32 Write(UInt32 count, const void* buf) + { + fProgress->Increment((hsScalar)count); + if (fIsZipped) + return plZlibStream::Write(count, buf); + else + return fOutput->Write(count, buf); + } }; -UInt32 plDownloadStream::Write(UInt32 byteCount, const void* buffer) -{ - fProgress->Increment((hsScalar)byteCount); - fBytesReceived += byteCount; +///////////////////////////////////////////////////////////////////////////// - return plZlibStream::Write(byteCount, buffer); -} - -////////////////////////////////////////////////////////////////////////////// - -static void DownloadFileCallback(ENetError result, void* param, const wchar filename[], hsStream* writer) +static void FileDownloaded( + ENetError result, + void* param, + const wchar_t filename[], + hsStream* writer) { plResPatcher* patcher = (plResPatcher*)param; + char* name = hsWStringToString(filename); + writer->Close(); + delete writer; - // Retry download unless shutting down or file not found - switch (result) { + switch (result) + { case kNetSuccess: - writer->Close(); - patcher->DoneWithFile(true); - break; - + PatcherLog(kStatus, " Download Complete: %s", name); + patcher->IssueRequest(); + delete[] name; + return; case kNetErrFileNotFound: - case kNetErrRemoteShutdown: - writer->Close(); - patcher->DoneWithFile(false); - break; - + PatcherLog(kError, " Download Failed: %s not found", name); + break; default: - writer->Rewind(); - NetCliFileDownloadRequest( - filename, - writer, - DownloadFileCallback, - param - ); - break; + char* error = hsWStringToString(NetErrorToString(result)); + PatcherLog(kError, " Download Failed: %s", error); + delete[] error; + break; } + // Failure case + patcher->Finish(false); + delete[] name; } -static void ManifestCallback(ENetError result, void* param, const wchar group[], const NetCliFileManifestEntry manifest[], unsigned entryCount) +static void ManifestDownloaded( + ENetError result, + void* param, + const wchar_t group[], + const NetCliFileManifestEntry manifest[], + UInt32 entryCount) { plResPatcher* patcher = (plResPatcher*)param; - patcher->DoneWithManifest(result == kNetSuccess, manifest, entryCount); -} - -//// Constructor/Destructor ////////////////////////////////////////////////// - -plResPatcher::plResPatcher(const char* ageToPatch, bool showAgeName) -{ - fAgeToPatch = ageToPatch; - fAlwaysShowAgeName = showAgeName; - IInit(); -} - -void plResPatcher::IInit() -{ - PatcherLog(kHeader, "--- Starting patch process for %s ---", fAgeToPatch.c_str()); -} - -plResPatcher::~plResPatcher() -{ - PatcherLog(kHeader, "--- Patch process done for %s ---", fAgeToPatch.c_str()); - - for (MfsFileVec::iterator i = fMfsVec.begin(); i != fMfsVec.end(); ++i) - { - plManifestFile* file = (*i); - delete file; + char* name = hsWStringToString(group); + if (IS_NET_SUCCESS(result)) + PatcherLog(kInfo, " Downloaded manifest %s", name); + else { + PatcherLog(kError, " Failed to download manifest %s", name); + patcher->Finish(false); + delete[] name; + return; } - fMfsVec.clear(); -} - -UInt32 plResPatcher::IGetDownloadSize() -{ - if (!IGetAgeManifest()) - return 0; - -#ifdef PLASMA_EXTERNAL_RELEASE - bool showAgeName = fAlwaysShowAgeName; -#else - bool showAgeName = true; -#endif - char msg[128]; - if (!fAgeToPatch.empty()) + for (UInt32 i = 0; i < entryCount; ++i) { - if (showAgeName) - sprintf(msg, "Checking age %s...", fAgeToPatch.c_str()); - else - strcpy(msg, "Checking age..."); - } - else - sprintf(msg, "Checking..."); - - plOperationProgress* progress = plProgressMgr::GetInstance()->RegisterOperation((hsScalar)(fMfsVec.size()), msg, plProgressMgr::kNone, false, true); + const NetCliFileManifestEntry mfs = manifest[i]; + char* fileName = hsWStringToString(mfs.clientName); - UInt32 downloadSize = 0; - UInt32 downloadFiles = 0; - for (MfsFileVec::iterator i = fMfsVec.begin(); i != fMfsVec.end(); ++i) - { - plManifestFile* mfsFile = (*i); - - if (!mfsFile->IsLocalUpToDate()) + // See if the files are the same + // 1. Check file size before we do time consuming md5 operations + // 2. Do wasteful md5. We should consider implementing a CRC instead. + if (plFileUtils::GetFileSize(fileName) == mfs.fileSize) { - downloadFiles++; - downloadSize += mfsFile->GetDownloadSize(); - } + plMD5Checksum cliMD5(fileName); + plMD5Checksum srvMD5; + char* eapSucksString = hsWStringToString(mfs.md5); + srvMD5.SetFromHexString(eapSucksString); + delete[] eapSucksString; - progress->Increment(1.f); + if (cliMD5 == srvMD5) + { + delete[] fileName; + continue; + } else + PatcherLog(kInfo, " Enqueueing %s: MD5 Checksums Differ", fileName); + } else + PatcherLog(kInfo, " Enqueueing %s: File Sizes Differ", fileName); + + // If we're still here, then we need to update the file. + patcher->GetProgress()->SetLength((hsScalar)mfs.fileSize + patcher->GetProgress()->GetMax()); + patcher->RequestFile(mfs.downloadName, mfs.clientName); } - delete progress; - - PatcherLog(kInfo, "Got download stats, %d files, %d bytes", downloadFiles, downloadSize); - - return downloadSize; + patcher->IssueRequest(); + delete[] name; } -bool plResPatcher::CheckFreeSpace(UInt32 bytesNeeded) -{ -#ifdef HS_BUILD_FOR_WIN32 - ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, neededBytes; - if (GetDiskFreeSpaceEx(NULL, &freeBytesAvailable, &totalNumberOfBytes, NULL)) - { - neededBytes.HighPart = 0; - neededBytes.LowPart = bytesNeeded; +///////////////////////////////////////////////////////////////////////////// - if (neededBytes.QuadPart > freeBytesAvailable.QuadPart) - { - PatcherLog(kInfo, "Not enough disk space (asked for %d bytes)", bytesNeeded); - return false; - } - } -#endif // HS_BUILD_FOR_WIN32 +static char* sLastError = nil; +plResPatcher* plResPatcher::fInstance = nil; - return true; +plResPatcher* plResPatcher::GetInstance() +{ + if (!fInstance) + fInstance = new plResPatcher; + return fInstance; } -bool plResPatcher::IDecompressSound(plManifestFile* mfsFile, bool noOverwrite) +void plResPatcher::Shutdown() { - UInt32 flags = mfsFile->GetFlags(); - - if ( (hsCheckBits(flags, plManifestFile::kSndFlagCacheSplit) || hsCheckBits(flags, plManifestFile::kSndFlagCacheStereo)) && stricmp(plFileUtils::GetFileExt(mfsFile->GetName()), "ogg") == 0) - { - plAudioFileReader* reader = plAudioFileReader::CreateReader(mfsFile->GetName(), plAudioCore::kAll, plAudioFileReader::kStreamNative); - if (!reader) - { - PatcherLog(kInfo, "Unable to create audio file reader for %s", mfsFile->GetName()); - return false; - } - - UInt32 size = reader->GetDataSize(); - delete reader; + // Better not call this while we're patching + delete fInstance; +} - // Make sure we have enough free space - if (!CheckFreeSpace(size)) - return false; +///////////////////////////////////////////////////////////////////////////// - if (hsCheckBits(flags, plManifestFile::kSndFlagCacheSplit)) - plAudioFileReader::CacheFile(mfsFile->GetName(), true, noOverwrite); - if (hsCheckBits(flags, plManifestFile::kSndFlagCacheStereo)) - plAudioFileReader::CacheFile(mfsFile->GetName(), false, noOverwrite); - } +plResPatcher::plResPatcher() + : fPatching(false), fProgress(nil) { } - return true; +plResPatcher::~plResPatcher() +{ + if (fProgress) + delete fProgress; } -bool plResPatcher::Update() +void plResPatcher::IssueRequest() { - UInt32 downloadSize = IGetDownloadSize(); - // if download size is 0, nothing to download, but we still need to tell the res manager about the files - - plFileUtils::CreateDir("dat"); - plFileUtils::CreateDir("sfx"); - - if (!CheckFreeSpace(downloadSize)) - return false; - -#ifdef PLASMA_EXTERNAL_RELEASE - bool showAgeName = fAlwaysShowAgeName; -#else - bool showAgeName = true; -#endif - - char msg[128]; - if (!fAgeToPatch.empty()) - { - if (showAgeName) - sprintf(msg, "Downloading %s data...", fAgeToPatch.c_str()); - else - strcpy(msg, "Downloading age data..."); - } - else - sprintf(msg, "Downloading..."); - - plOperationProgress* progress = plProgressMgr::GetInstance()->RegisterOverallOperation((hsScalar)downloadSize, msg, plProgressMgr::kUpdateText, true); - - bool result = true; - plResManager* resMgr = ((plResManager*)hsgResMgr::ResMgr()); - - for (MfsFileVec::iterator i = fMfsVec.begin(); i != fMfsVec.end(); ++i) - { - plManifestFile* mfsFile = (*i); - - if (!mfsFile->IsLocalUpToDate()) - { - FileType type = IGetFile(mfsFile, progress); - if (type == kPrp) - { - // Checks for existence before attempting to remove - resMgr->RemoveSinglePage(mfsFile->GetName()); - } - else if (type == kOther) - { - if (!IDecompressSound(mfsFile, false)) - { - char text[MAX_PATH]; - StrPrintf(text, arrsize(text), "%s could not be decompressed", mfsFile->GetName()); - PatcherLog(kInfo, text ); - hsAssert(false, text); - result = false; - } - } - else - { - char text[MAX_PATH]; - StrPrintf(text, arrsize(text), "Failed downloading file: %s", mfsFile->GetName()); - PatcherLog(kInfo, text ); - hsAssert(false, text); - result = false; - } - } - else + if (!fPatching) return; + if (fRequests.empty()) + // Wheee! + Finish(); + else { + Request req = fRequests.front(); + fRequests.pop(); + + std::wstring title; + if (req.fType == kManifest) { - if (!IDecompressSound(mfsFile, true)) - { - char text[MAX_PATH]; - StrPrintf(text, arrsize(text), "%s could not be decompressed", mfsFile->GetName()); - PatcherLog(kInfo, text ); - hsAssert(false, text); - result = false; + char* eapSucksString = hsWStringToString(req.fFile.c_str()); + PatcherLog(kMajorStatus, " Downloading manifest... %s", eapSucksString); + xtl::format(title, L"Checking %s for updates...", req.fFile.c_str()); + NetCliFileManifestRequest(ManifestDownloaded, this, req.fFile.c_str()); + delete[] eapSucksString; + } else if (req.fType == kFile) { + char* eapSucksString = hsWStringToString(req.fFriendlyName.c_str()); + PatcherLog(kMajorStatus, " Downloading file... %s", eapSucksString); + xtl::format(title, L"Downloading... %s", plFileUtils::GetFileName(req.fFriendlyName.c_str())); + + plFileUtils::EnsureFilePathExists(req.fFriendlyName.c_str()); + plResDownloadStream* stream = new plResDownloadStream(fProgress, req.fFile.c_str()); + if(stream->Open(eapSucksString, "wb")) + NetCliFileDownloadRequest(req.fFile.c_str(), stream, FileDownloaded, this); + else { + PatcherLog(kError, " Unable to create file %s", eapSucksString); + Finish(false); } + delete[] eapSucksString; } - if (!resMgr->FindSinglePage(mfsFile->GetName()) && stricmp(plFileUtils::GetFileExt(mfsFile->GetName()), "prp") == 0) - { - resMgr->AddSinglePage(mfsFile->GetName()); - } + char* hack = hsWStringToString(title.c_str()); + fProgress->SetTitle(hack); + delete[] hack; } - - PatcherLog(kMajorStatus, "Cleaning up patcher..." ); - delete progress; - - return result; } -plResPatcher::FileType plResPatcher::IGetFile(const plManifestFile* mfsFile, plOperationProgress* progressBar) +void plResPatcher::Finish(bool success) { - PatcherLog(kInfo, " Setting up to download file %s", mfsFile->GetName()); + while (fRequests.size()) + fRequests.pop(); + if (fProgress) { + delete fProgress; + fProgress = nil; + } - bool downloadDone = false; - wchar* wServerPath = hsStringToWString(mfsFile->GetServerPath()); - int numTries = 0; + fPatching = false; + if (success) + PatcherLog(kHeader, "--- Patch Completed Successfully ---"); + else + PatcherLog(kHeader, "--- Patch Killed by Error ---"); - while (!downloadDone) + plResPatcherMsg* pMsg = new plResPatcherMsg(success, sLastError); + pMsg->Send(); // whoosh... off it goes + if (sLastError) { - if (numTries >= kMaxDownloadTries) - { - PatcherLog(kInfo, " Max download tries exceeded (%d). Aborting download...", kMaxDownloadTries); - return kFail; - } - - plDownloadStream downloadStream(progressBar); - if (!downloadStream.Open(mfsFile->GetName(), "wb")) - { - PatcherLog(kInfo, " Unable to create file. Aborting download..."); - return kFail; - } - - PatcherLog(kInfo, " Downloading file %s...", mfsFile->GetName()); - - fSuccess = false; - fDoneWithFile = false; - NetCliFileDownloadRequest( - wServerPath, - &downloadStream, - DownloadFileCallback, - this - ); - - while (!fDoneWithFile) { - NetClientUpdate(); - plgDispatch::Dispatch()->MsgQueueProcess(); - AsyncSleep(10); - } - - if (!fSuccess) { - // remove partial file and die (server didn't have the file or server is shutting down) - downloadStream.RewindProgress(); - plFileUtils::RemoveFile(mfsFile->GetName(), true); - PatcherLog(kError, " File %s failed to download.", mfsFile->GetName()); - downloadDone = true; - } - else { - if (downloadStream.DecompressedOk()) { - PatcherLog(kInfo, " Decompress successful." ); - // download and decompress successful, do a md5 check on the resulting file - plMD5Checksum localMD5(mfsFile->GetName()); - if (localMD5 != mfsFile->GetChecksum()) { - downloadStream.RewindProgress(); - downloadStream.Close(); - plFileUtils::RemoveFile(mfsFile->GetName(), true); - PatcherLog(kError, " File %s MD5 check FAILED.", mfsFile->GetName()); - // don't set downloadDone so we attempt to re-download from the server - } - else { - downloadStream.Close(); - PatcherLog(kInfo, " MD5 check succeeded."); - downloadDone = true; - } - } - else { - downloadStream.RewindProgress(); - downloadStream.Close(); - plFileUtils::RemoveFile(mfsFile->GetName(), true); - PatcherLog(kError, " File %s failed to decompress.", mfsFile->GetName()); - // don't set downloadDone so we attempt to re-download from the server - } - } - ++numTries; + delete[] sLastError; + sLastError = nil; } - FREE(wServerPath); - - if (!fSuccess) - return kFail; - - if (stricmp(plFileUtils::GetFileExt(mfsFile->GetName()), "prp") == 0) - return kPrp; - - return kOther; } -bool plResPatcher::IGetAgeManifest() +void plResPatcher::RequestFile(const wchar_t* srvName, const wchar_t* cliName) { - if (fMfsVec.size() > 0) - return true; - - PatcherLog(kMajorStatus, "Downloading new manifest from data server..." ); - - fSuccess = false; - wchar* group = hsStringToWString(fAgeToPatch.c_str()); - unsigned numTries = 0; - while (!fSuccess) - { - numTries++; - fDoneWithFile = false; - NetCliFileManifestRequest(ManifestCallback, this, group); - while (!fDoneWithFile) - { - NetClientUpdate(); - plgDispatch::Dispatch()->MsgQueueProcess(); - AsyncSleep(10); - } - - if (!fSuccess) - { - fMfsVec.clear(); // clear out any bad data - if (numTries > kMaxDownloadTries) - break; // abort - } - } - delete [] group; - - if (fSuccess) - PatcherLog(kStatus, "New age manifest read; number of files: %d", fMfsVec.size() ); - else - PatcherLog(kStatus, "Failed to download manifest after trying %d times", kMaxDownloadTries); - - return fSuccess; + fRequests.push(Request(srvName, kFile, cliName)); } -void plResPatcher::DoneWithManifest(bool success, const NetCliFileManifestEntry manifestEntires[], unsigned entryCount) +void plResPatcher::RequestManifest(const wchar_t* age) { - PatcherLog(kStatus, "New age manifest received. Reading..."); - - if (success) - { - for (unsigned i = 0; i < entryCount; i++) - { - char* name = hsWStringToString(manifestEntires[i].clientName); - char* serverPath = hsWStringToString(manifestEntires[i].downloadName); - char* md5Str = hsWStringToString(manifestEntires[i].md5); - int size = manifestEntires[i].fileSize; - int zipsize = manifestEntires[i].zipSize; - int flags = manifestEntires[i].flags; - if (stricmp(plFileUtils::GetFileExt(name), "gz")) - flags |= plManifestFile::kFlagZipped; // add zipped flag if necessary - - plMD5Checksum sum; - sum.SetFromHexString(md5Str); - fMfsVec.push_back(TRACKED_NEW plManifestFile(name, serverPath, sum, size, zipsize, flags)); - - delete [] name; - delete [] serverPath; - delete [] md5Str; - } - } + fRequests.push(Request(age, kManifest)); +} - fDoneWithFile = true; - fSuccess = success; +void plResPatcher::Start() +{ + hsAssert(!fPatching, "Too many calls to plResPatcher::Start"); + fPatching = true; + PatcherLog(kHeader, "--- Patch Started (%i requests) ---", fRequests.size()); + fProgress = plProgressMgr::GetInstance()->RegisterOperation(0.0, "Checking for updates...", + plProgressMgr::kUpdateText, false, true); + IssueRequest(); } +///////////////////////////////////////////////////////////////////////////// + void PatcherLog(PatcherLogType type, const char* format, ...) { UInt32 color = 0; @@ -512,7 +302,13 @@ void PatcherLog(PatcherLogType type, const char* format, ...) va_list args; va_start(args, format); - gStatusLog->AddLineV(color, format, args); + if (type == kError) + { + sLastError = new char[1024]; // Deleted by Finish(false) + vsprintf(sLastError, format, args); + gStatusLog->AddLine(sLastError, color); + } else + gStatusLog->AddLineV(color, format, args); va_end(args); -} \ No newline at end of file +} diff --git a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h index cec09cc6..0a4d9c75 100644 --- a/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h +++ b/Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h @@ -42,52 +42,48 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #ifndef plResPatcher_h_inc #define plResPatcher_h_inc -#include "hsStlUtils.h" +#include "HeadSpin.h" +#include +#include -#include "pnUtils/pnUtils.h" -#include "pnNetBase/pnNetBase.h" -#include "plEncryption/plChecksum.h" - - -class plManifest; -class plManifestFile; class plOperationProgress; -struct NetCliFileManifestEntry; class plResPatcher { -protected: - enum FileType {kFail, kPrp, kOther}; - std::string fAgeToPatch; - - typedef std::vector MfsFileVec; - MfsFileVec fMfsVec; - - bool fDoneWithFile; - bool fSuccess; - bool fAlwaysShowAgeName; - - void IInit(); - static void ILog(UInt32 type, const char* format, ...); - - FileType IGetFile(const plManifestFile* mfsFile, plOperationProgress* progressBar); - bool IGetAgeManifest(); - - UInt32 IGetDownloadSize(); - - bool IDecompressSound(plManifestFile* mfsFile, bool noOverwrite = false); - -public: - plResPatcher(const char* ageToPatch, bool showAgeName = false); + enum { kManifest, kFile }; + struct Request + { + std::wstring fFile; + std::wstring fFriendlyName; + uint8_t fType; + + Request(const wchar_t* file, uint8_t type, const wchar_t* friendly = nil) + : fFile(file), fType(type) + { + if (friendly) + fFriendlyName = std::wstring(friendly); + } + }; + + static plResPatcher* fInstance; + std::queue fRequests; + plOperationProgress* fProgress; + bool fPatching; + + plResPatcher(); ~plResPatcher(); - bool Update(); +public: + static plResPatcher* GetInstance(); + static void Shutdown(); - static bool CheckFreeSpace(UInt32 bytesNeeded); + plOperationProgress* GetProgress() { return fProgress; } - // called by download callbacks to tell it we are done with the current file - void DoneWithFile(bool success) {fDoneWithFile = true; fSuccess = success;} - void DoneWithManifest(bool success, const NetCliFileManifestEntry manifestEntires[], unsigned entryCount); + void Finish(bool success = true); + void IssueRequest(); + void RequestFile(const wchar_t* file, const wchar_t* friendlyName); + void RequestManifest(const wchar_t* age); + void Start(); }; enum PatcherLogType @@ -99,5 +95,4 @@ enum PatcherLogType kError, }; void PatcherLog(PatcherLogType type, const char* format, ...); - #endif // _plResPatcher_h diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp index a917f177..f5955522 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp @@ -68,6 +68,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plMessage/plAgeLoadedMsg.h" #include "plMessage/plInputIfaceMgrMsg.h" #include "plMessage/plNetClientMgrMsg.h" +#include "plMessage/plResPatcherMsg.h" #include "plProgressMgr/plProgressMgr.h" #include "pnDispatch/plDispatch.h" @@ -223,13 +224,6 @@ void plNCAgeJoiner::Start () { plAgeLoader* al = plAgeLoader::GetInstance(); al->UpdateAge(age.ageDatasetName); - - nc->ResetServerTimeOffset(); - - NetCommLinkToAge( - age, - this - ); } //============================================================================ @@ -373,6 +367,24 @@ bool plNCAgeJoiner::MsgReceive (plMessage * msg) { plAvatarMgr * am = plAvatarMgr::GetInstance(); plAgeLoader * al = plAgeLoader::GetInstance(); + //======================================================================== + // Finished updating the age from FileSrv + //======================================================================== + if (plResPatcherMsg * resMsg = plResPatcherMsg::ConvertNoRef(msg)) { + + if (resMsg->Success()) + { + nc->ResetServerTimeOffset(); + NetCommLinkToAge( + age, + this + ); + LogMsg(kLogPerf, L"AgeJoiner: Next:kNoOp (age updated)"); + } else + Complete(false, resMsg->GetError()); + return true; + } + //======================================================================== // Connected to age instance //======================================================================== diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp index d6ed4c98..f8462da7 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp @@ -84,6 +84,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "plMessage/plNetVoiceListMsg.h" #include "plMessage/plNetCommMsgs.h" #include "plMessage/plNetClientMgrMsg.h" +#include "plMessage/plResPatcherMsg.h" #include "plMessage/plVaultNotifyMsg.h" #include "plResMgr/plKeyFinder.h" #include "plResMgr/plPageInfo.h" @@ -355,6 +356,7 @@ int plNetClientMgr::Init() // We need plVaultNotifyMsgs for the NetLinkingMgr plgDispatch::Dispatch()->RegisterForType(plVaultNotifyMsg::Index(), GetKey()); + plgDispatch::Dispatch()->RegisterForExactType(plResPatcherMsg::Index(), GetKey()); IInitNetClientComm();