Browse Source

Merge pull request #117 from Hoikas/patcher-cleanup

ResPatcher Cleaup
Branan Purvine-Riley 13 years ago
parent
commit
d264b4d3e8
  1. 54
      Sources/Plasma/Apps/plClient/plClient.cpp
  2. 2
      Sources/Plasma/Apps/plClient/plClient.h
  3. 5
      Sources/Plasma/Apps/plClient/winmain.cpp
  4. 2
      Sources/Plasma/NucleusLib/inc/plCreatableIndex.h
  5. 2
      Sources/Plasma/PubUtilLib/plAgeLoader/CMakeLists.txt
  6. 25
      Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.cpp
  7. 2
      Sources/Plasma/PubUtilLib/plAgeLoader/plAgeLoader.h
  8. 545
      Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.cpp
  9. 98
      Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.h
  10. 562
      Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.cpp
  11. 71
      Sources/Plasma/PubUtilLib/plAgeLoader/plResPatcher.h
  12. 3
      Sources/Plasma/PubUtilLib/plMessage/CMakeLists.txt
  13. 4
      Sources/Plasma/PubUtilLib/plMessage/plMessageCreatable.h
  14. 48
      Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp
  15. 40
      Sources/Plasma/PubUtilLib/plMessage/plResPatcherMsg.h
  16. 29
      Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeJoiner.cpp
  17. 4
      Sources/Plasma/PubUtilLib/plNetClient/plNetCliAgeLeaver.cpp
  18. 2
      Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp
  19. 1
      Sources/Plasma/PubUtilLib/plNetClient/plNetLinkingMgr.cpp

54
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();
}
//============================================================================

2
Sources/Plasma/Apps/plClient/plClient.h

@ -152,8 +152,6 @@ protected:
hsBool fQuitIntro;
hsTArray<plBinkPlayer*> fMovies;
hsBool fPatchGlobalAges;
plMessagePumpProc fMessagePumpProc;
#ifndef PLASMA_EXTERNAL_RELEASE

5
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";

2
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),

2
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
)

25
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
@ -64,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"
@ -77,7 +77,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
extern hsBool gDataServerLocal;
extern hsBool gUseBackgroundDownloader;
// static
plAgeLoader* plAgeLoader::fInstance=nil;
@ -112,7 +111,7 @@ plAgeLoader::~plAgeLoader()
void plAgeLoader::Shutdown()
{
plResPatcher::GetInstance()->Shutdown();
}
void plAgeLoader::Init()
@ -120,9 +119,6 @@ void plAgeLoader::Init()
RegisterAs( kAgeLoader_KEY );
plgDispatch::Dispatch()->RegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey());
plgDispatch::Dispatch()->RegisterForExactType(plClientMsg::Index(), GetKey());
if (!gDataServerLocal && gUseBackgroundDownloader)
plBackgroundDownloader::StartThread();
}
//
@ -175,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;
}
//============================================================================

2
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; }

545
Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.cpp

@ -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 <http://www.gnu.org/licenses/>.
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 <process.h>
#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;
}

98
Sources/Plasma/PubUtilLib/plAgeLoader/plBackgroundDownloader.h

@ -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 <http://www.gnu.org/licenses/>.
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 <vector>
#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<plManifestFile*> 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

562
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);
}
}

71
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 <queue>
#include <string>
#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<plManifestFile*> 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<Request> 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

3
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

4
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);

48
Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.cpp

@ -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 <http://www.gnu.org/licenses/>.
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"

40
Sources/Plasma/PubUtilLib/plMessage/plNCAgeJoinerMsg.h → 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

29
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"
@ -69,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"
@ -201,8 +201,6 @@ void plNCAgeJoiner::Complete (bool success, const char msg[]) {
DEL(this);
}
if (plBackgroundDownloader::GetInstance())
plBackgroundDownloader::GetInstance()->UnPause();
}
//============================================================================
@ -226,13 +224,6 @@ void plNCAgeJoiner::Start () {
plAgeLoader* al = plAgeLoader::GetInstance();
al->UpdateAge(age.ageDatasetName);
nc->ResetServerTimeOffset();
NetCommLinkToAge(
age,
this
);
}
//============================================================================
@ -376,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
//========================================================================

4
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;
}

2
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();

1
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"
/*****************************************************************************

Loading…
Cancel
Save