diff --git a/Sources/Plasma/Apps/CMakeLists.txt b/Sources/Plasma/Apps/CMakeLists.txt
index fef53526..f3a1efa7 100644
--- a/Sources/Plasma/Apps/CMakeLists.txt
+++ b/Sources/Plasma/Apps/CMakeLists.txt
@@ -6,7 +6,6 @@ if(PLASMA_BUILD_LAUNCHER)
endif()
if(PLASMA_BUILD_TOOLS)
- add_subdirectory(plClientPatcher)
add_subdirectory(plPythonPack)
add_subdirectory(plFileSecure)
add_subdirectory(plFileEncrypt)
diff --git a/Sources/Plasma/Apps/plClientPatcher/CMakeLists.txt b/Sources/Plasma/Apps/plClientPatcher/CMakeLists.txt
deleted file mode 100644
index 10046d95..00000000
--- a/Sources/Plasma/Apps/plClientPatcher/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-add_definitions(-D_LIB)
-
-include_directories("../../CoreLib")
-include_directories("../../NucleusLib/inc")
-include_directories("../../NucleusLib")
-include_directories("../../PubUtilLib")
-
-include_directories(${OPENSSL_INCLUDE_DIR})
-
-set(plClientPatcher_HEADERS
- Intern.h
- Pch.h
- UruPlayer.h
-)
-
-set(plClientPatcher_SOURCES
- UruPlayer.cpp
-)
-
-add_library(plClientPatcher STATIC ${plClientPatcher_HEADERS} ${plClientPatcher_SOURCES})
-target_link_libraries(plClientPatcher CoreLib plAudioCore plStatusLog)
-
-if(USE_VLD)
- target_link_libraries(plClientPatcher ${VLD_LIBRARY})
-endif()
-
-source_group("Header Files" FILES ${plClientPatcher_HEADERS})
-source_group("Source Files" FILES ${plClientPatcher_SOURCES})
diff --git a/Sources/Plasma/Apps/plClientPatcher/Intern.h b/Sources/Plasma/Apps/plClientPatcher/Intern.h
deleted file mode 100644
index 692e602f..00000000
--- a/Sources/Plasma/Apps/plClientPatcher/Intern.h
+++ /dev/null
@@ -1,58 +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/Apps/plClientPatcher/Intern.h
-*
-***/
-
-#ifdef PLASMA20_SOURCES_PLASMA_APPS_PLCLIENTPATCHER_INTERN_H
-#error "Header $/Plasma20/Sources/Plasma/Apps/plClientPatcher/Intern.h included more than once"
-#endif
-#define PLASMA20_SOURCES_PLASMA_APPS_PLCLIENTPATCHER_INTERN_H
-
-
-/*****************************************************************************
-*
-* SelfPatcher.cpp
-*
-***/
diff --git a/Sources/Plasma/Apps/plClientPatcher/Pch.h b/Sources/Plasma/Apps/plClientPatcher/Pch.h
deleted file mode 100644
index 39eb2515..00000000
--- a/Sources/Plasma/Apps/plClientPatcher/Pch.h
+++ /dev/null
@@ -1,75 +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/Apps/plClientPatcher/Pch.h
-*
-***/
-
-#ifdef PLASMA20_SOURCES_PLASMA_APPS_PLCLIENTPATCHER_PCH_H
-#error "Header $/Plasma20/Sources/Plasma/Apps/plClientPatcher/Pch.h included more than once"
-#endif
-#define PLASMA20_SOURCES_PLASMA_APPS_PLCLIENTPATCHER_PCH_H
-
-#include "hsWindows.h"
-#include
-#include
-#include "pnUtils/pnUtils.h"
-#include "pnNetBase/pnNetBase.h"
-#include "pnAsyncCore/pnAsyncCore.h"
-#include "plProduct.h"
-#include "pnNetCli/pnNetCli.h"
-#include "plNetGameLib/plNetGameLib.h"
-#include "pnEncryption/plChecksum.h"
-#include "plAgeDescription/plAgeManifest.h"
-#include "plAudioCore/plAudioFileReader.h"
-
-#define USES_PROTOCOL_CLI2AUTH
-#include "pnNetProtocol/pnNetProtocol.h"
-
-#include "UruPlayer.h"
-
-#include "plCompression/plZlibStream.h"
-#include "Intern.h"
-#include "../plUruLauncher/plLauncherInfo.h"
-
-
diff --git a/Sources/Plasma/Apps/plClientPatcher/UruPlayer.cpp b/Sources/Plasma/Apps/plClientPatcher/UruPlayer.cpp
deleted file mode 100644
index a5957d6b..00000000
--- a/Sources/Plasma/Apps/plClientPatcher/UruPlayer.cpp
+++ /dev/null
@@ -1,1020 +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/Apps/plClientPatcher/UruPlayer.cpp
-*
-***/
-
-#include "Pch.h"
-#include "plStatusLog/plStatusLog.h"
-#include
-#pragma hdrstop
-
-
-/*****************************************************************************
-*
-* Private
-*
-***/
-#ifndef PLASMA_EXTERNAL_RELEASE
- static const wchar_t s_manifest[] = L"Internal";
- static const wchar_t s_thinmanifest[] = L"ThinInternal";
-#else
- static const wchar_t s_manifest[] = L"External";
- static const wchar_t s_thinmanifest[] = L"ThinExternal";
-#endif
-
-struct ManifestFile
-{
- ManifestFile(const plFileName &clientName, const plFileName &downloadName, const plString &md5val, int flags, plLauncherInfo *info)
- {
- filename = clientName;
- zipName = downloadName;
- md5 = md5val;
- this->flags = flags;
- this->info = info;
- md5failed = false;
- }
-
- plFileName filename;
- plFileName zipName;
- plString md5;
- int flags;
- bool md5failed;
- plLauncherInfo *info;
-};
-
-
-class ProgressStream : public plZlibStream {
-public:
- virtual uint32_t Write(uint32_t byteCount, const void* buffer);
- static plLauncherInfo *info;
- static long totalBytes;
- static unsigned progress;
-
- // for updating bytes per second
- static uint32_t startTime;
-};
-
-struct ProcessManifestEntryParam {
- struct ManifestResult * mr;
- unsigned index;
- static long totalSize;
- static long progress;
- static double startTime;
- bool exists; // marked as true if the file exists before MD5 check
-};
-
-struct ManifestResult {
- wchar_t group[MAX_PATH];
- ARRAY(NetCliFileManifestEntry) manifest;
- long * indicator;
- plLauncherInfo * info;
-
- hsMutex critsect;
- ARRAY(unsigned) indices;
-};
-
-
-static void DownloadCallback (
- ENetError result,
- void * param,
- const plFileName & filename,
- hsStream * writer
-);
-
-
-/*****************************************************************************
-*
-* Private data
-*
-***/
-
-static const unsigned kMaxManifestFileRequests = 5;
-static const unsigned kMinThreads = 16;
-static const unsigned kMaxThreads = 64;
-
-
-static unsigned s_fileRequests;
-static unsigned s_fileListRequests;
-static bool s_patchComplete;
-static PROCESS_INFORMATION s_pi;
-static long s_numFiles;
-static plFileName s_workingDir;
-static bool s_patchError;
-static long s_asyncCoreInitCount;
-static long s_numConnectFailures;
-static bool s_running;
-static std::queue manifestQueue;
-//static AsyncThreadTaskList * s_taskList;
-
-// error strings
-static const char s_fileOpenError[] = "Unable to create file. Hard drive may be full.";
-static const char s_md5CheckError[] = "Error downloading file from server, exiting...";
-
-enum {
- kPerfThreadTaskCount,
- kNumPerf
-};
-
-static long s_perf[kNumPerf];
-
-
-long ProgressStream::totalBytes;
-unsigned ProgressStream::progress;
-plLauncherInfo * ProgressStream::info;
-uint32_t ProgressStream::startTime = 0;
-long ProcessManifestEntryParam::progress = 0;
-long ProcessManifestEntryParam::totalSize = 0;
-double ProcessManifestEntryParam::startTime = 0;
-
-
-/*****************************************************************************
-*
-* Exported data
-*
-***/
-
-// IMPORTANT: This string may NEVER change. Doing so will break self-patching,
-// leaving clients with older patchers "dead in the water", without
-// a way to play Uru.
-#ifdef PLASMA_EXTERNAL_RELEASE
-plFileName kPatcherExeFilename = "UruLauncher.exe";
-#else
-plFileName kPatcherExeFilename = "plUruLauncher.exe";
-#endif
-
-
-//============================================================================
-// External client file list
-//============================================================================
-#ifdef PLASMA_EXTERNAL_RELEASE
-#ifdef HS_DEBUGGING
-static wchar_t s_clientExeName[] = L"plClient_dbg.exe";
-#else
-static wchar_t s_clientExeName[] = L"UruExplorer.exe";
-#endif // HS_DEBUGGING
-
-//============================================================================
-// Internal client file list
-//============================================================================
-#else
-#ifdef HS_DEBUGGING
-static wchar_t s_clientExeName[] = L"plClient_dbg.exe";
-#else
-static wchar_t s_clientExeName[] = L"plClient.exe";
-#endif // HS_DEBUGGING
-#endif // PLASMA_EXTERNAL_RELEASE
-
-
-/*****************************************************************************
-*
-* Private Functions
-*
-***/
-
-//============================================================================
-static void NetErrorHandler (ENetProtocol protocol, ENetError error) {
-
- const wchar_t * srv;
- switch (protocol) {
- case kNetProtocolNil: srv = L"Notify"; break;
- case kNetProtocolCli2File: srv = L"File"; break;
- case kNetProtocolCli2GateKeeper: srv = L"GateKeeper"; break;
- DEFAULT_FATAL(protocol);
- }
-
- switch (error) {
- case kNetErrConnectFailed:
- case kNetErrTimeout:
- ++s_numConnectFailures;
- break;
-
- case kNetErrDisconnected:
- s_patchError = true;
- break;
-
- case kNetErrServerBusy:
- MessageBox(0, "Due to the high demand, the server is currently busy. Please try again later, or for alternative download options visit: http://www.mystonline.com/play/", "UruLauncher", MB_OK);
- s_running = false;
- break;
- }
-
- plString msg = plString::Format("NetErr: %S: %S", srv, NetErrorToString(error));
- plStatusLog::AddLineS("patcher.log", msg.c_str());
-
- // Notify GameTap something bad happened.
- if (!s_patchError) {
- MessageBox(
- nil,
- "Unable to connect to server.",
- "Error",
- MB_ICONERROR
- );
- s_patchError = true;
- }
-
- /*AsyncAppCallback(
- kPlayerNotifyFailed,
- kCmdResultFailed,
- (void *)NetErrorToString(error)
- );*/
-}
-
-/*
-//============================================================================
-static void WaitUruExitProc (void * param) {
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- plLauncherInfo *info = (plLauncherInfo *) param;
- WaitForSingleObject(s_pi.hProcess, INFINITE);
- DWORD exitcode;
- GetExitCodeProcess(s_pi.hProcess, &exitcode);
- CloseHandle( s_pi.hThread );
- CloseHandle( s_pi.hProcess );
-
- if(exitcode == kExitCodeTerminated) {
- info->stopCallback(kStatusOk, nil); // notify of succesful stop
- }
- else {
- info->exitCallback(kStatusOk, nil);
- }
-}
-*/
-
-//============================================================================
-static bool MD5Check (const plFileName& filename, const char *md5) {
- plMD5Checksum existingMD5(filename);
- plMD5Checksum latestMD5;
-
- latestMD5.SetFromHexString(md5);
- return (existingMD5 == latestMD5);
-}
-
-//============================================================================
-static void DecompressOgg (ManifestFile *mf) {
- unsigned flags = mf->flags;
- for(;;)
- {
- // decompress ogg if necessary
- if ( (hsCheckBits(flags, plManifestFile::kSndFlagCacheSplit) || hsCheckBits(flags, plManifestFile::kSndFlagCacheStereo)) )
- {
- plFileName path = plFileName::Join(s_workingDir, mf->filename);
-
- plAudioFileReader* reader = plAudioFileReader::CreateReader(path, plAudioCore::kAll, plAudioFileReader::kStreamNative);
- if (!reader)
- {
- break;
- }
-
- uint32_t size = reader->GetDataSize();
- delete reader;
-
- ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, neededBytes;
- if (GetDiskFreeSpaceEx(NULL, &freeBytesAvailable, &totalNumberOfBytes, NULL))
- {
- neededBytes.HighPart = 0;
- neededBytes.LowPart = size;
-
- if (neededBytes.QuadPart > freeBytesAvailable.QuadPart)
- {
- //PatcherLog(kInfo, "Not enough disk space (asked for %d bytes)", bytesNeeded);
- break;
- }
- }
-
- if (hsCheckBits(flags, plManifestFile::kSndFlagCacheSplit))
- plAudioFileReader::CacheFile(path, true, true);
- if (hsCheckBits(flags, plManifestFile::kSndFlagCacheStereo))
- plAudioFileReader::CacheFile(path, false, true);
- }
- break;
- }
-}
-
-//============================================================================
-void Shutdown(plLauncherInfo *info) {
- info->SetText("Shutting Down...");
- s_patchError = true;
- s_running = false;
-}
-
-//============================================================================
-static void RequestNextManifestFile () {
- bool success = true;
-
- if (!manifestQueue.size())
- return;
-
- ManifestFile* nextfile = manifestQueue.front();
- manifestQueue.pop();
-
- plFileName path = plFileName::Join(s_workingDir, nextfile->filename);
- plFileSystem::CreateDir(path.StripFileName(), true);
-
- ProgressStream *writer = new ProgressStream(); // optimization: dont delete and recreate. Doesn't seem to be working currently, ZLibStream is breaking
- if(!writer->Open(path, "wb"))
- {
- writer->Close();
- delete writer;
- success = false;
- }
-
- if(success)
- {
-#ifndef PLASMA_EXTERNAL_RELEASE
- char text[256];
- StrPrintf(text, arrsize(text), "Updating URU... %s", nextfile->filename.AsString().c_str());
- nextfile->info->SetText(text);
-#endif
- NetCliFileDownloadRequest(nextfile->zipName, writer, DownloadCallback, nextfile, nextfile->info->buildId);
- }
-}
-
-//============================================================================
-static void DownloadCallback (
- ENetError result,
- void * param,
- const plFileName & filename,
- hsStream * writer
-) {
- s_numConnectFailures = 0;
-
- ManifestFile *mf = (ManifestFile *)param;
- if (IS_NET_ERROR(result) && s_running && !s_patchError) {
- if (result == kNetErrFileNotFound) {
- plString str = plString::Format("File not found on server: %s", filename.AsString().c_str());
- MessageBox(nil, str.c_str(), "URU Launcher", MB_ICONERROR);
- s_patchError = true;
- }
- else if (result == kNetErrRemoteShutdown) {
- s_patchError = true;
- }
- else {
- // failed, re-queue the file to be downloaded
- // (after rewinding the stream)
- writer->Rewind();
- plLauncherInfo *info = mf->info;
- NetCliFileDownloadRequest(filename, writer, DownloadCallback, mf, info->buildId);
- return;
- }
- }
-
- writer->Close();
- delete writer; // delete our stream
-
- plFileName path = plFileName::Join(s_workingDir, mf->filename);
- if (s_running)
- {
- if (!MD5Check(path, mf->md5.c_str())) {
- if (mf->md5failed)
- {
-#ifdef PLASMA_EXTERNAL_RELEASE
- MessageBox(nil, s_md5CheckError, "URU Launcher", MB_ICONERROR);
-#else
- char str[256];
- StrPrintf(str, arrsize(str), "%s %s ", path.AsString().c_str(), s_md5CheckError);
- MessageBox(nil, str, "URU Launcher", MB_ICONERROR);
-#endif // PLASMA_EXTERNAL_RELEASE
- Shutdown(mf->info);
- }
- writer = new ProgressStream();
- if (!writer->Open(path, "wb")) {
-#ifdef PLASMA_EXTERNAL_RELEASE
- MessageBox(nil, s_fileOpenError, "URU Launcher", MB_ICONERROR);
-#else
- char str[256];
- StrPrintf(str, arrsize(str), "%s %s", s_fileOpenError, path.AsString().c_str());
- MessageBox(nil, str, "URU Launcher", MB_ICONERROR);
-#endif // PLASMA_EXTERNAL_RELEASE
- Shutdown(mf->info);
- }
- mf->md5failed = true;
- plLauncherInfo *info = mf->info;
- NetCliFileDownloadRequest(filename, writer, DownloadCallback, mf, info->buildId);
- return;
- }
- }
-
- AtomicAdd(&s_numFiles, -1);
-
- if (s_running)
- {
- if (!mf->filename.GetFileExt().CompareI("ogg"))
- {
- DecompressOgg(mf);
- }
- }
-
- delete mf; // delete manifest file entry
-
- // if we are not still running don't request any more file downloads
- if(s_running)
- {
- if(!s_numFiles) {
- s_patchComplete = true;
- }
- else
- {
- RequestNextManifestFile();
- }
- }
-}
-
-//============================================================================
-static void ProcessManifestEntry (void * param, ENetError error) {
- ProcessManifestEntryParam * p = (ProcessManifestEntryParam*)param;
-
-#ifndef PLASMA_EXTERNAL_RELEASE
- char text[256];
- StrPrintf(text, arrsize(text), "Checking for updates... %S", p->mr->manifest[p->index].clientName);
- p->mr->info->SetText(text);
-#endif
- plFileName path = plFileName::Join(s_workingDir, plString::FromWchar(p->mr->manifest[p->index].clientName));
- uint32_t start = (uint32_t)(TimeGetTime() / kTimeIntervalsPerMs);
- if (!MD5Check(path, plString::FromWchar(p->mr->manifest[p->index].md5, 32).c_str())) {
- p->mr->critsect.Lock();
- p->mr->indices.Add(p->index);
- p->mr->critsect.Unlock();
- AtomicAdd(&ProgressStream::totalBytes, p->mr->manifest[p->index].zipSize);
- }
-
- // if we have a file that was cached the MD5 check will be really fast throwing off our approx time remaining.
- uint32_t t = (uint32_t)(TimeGetTime() / kTimeIntervalsPerMs - start);
- if(t < 25)
- {
- // cached file
- AtomicAdd(&ProcessManifestEntryParam::totalSize, -p->mr->manifest[p->index].zipSize);
- p->exists = false;
- }
-
- // p->mr->info->SetBytesRemaining(ProcessManifestEntryParam::totalSize); // for testing purposes only
- if(p->exists)
- {
- AtomicAdd(&ProcessManifestEntryParam::progress, p->mr->manifest[p->index].zipSize);
-
- PatchInfo patchInfo;
- patchInfo.stage = 0;
- patchInfo.progressStage = 0;
- patchInfo.progress = (unsigned)((float)(ProcessManifestEntryParam::progress) / (float)ProcessManifestEntryParam::totalSize * 1000.0f);
- p->mr->info->progressCallback(kStatusPending, &patchInfo);
- if(ProcessManifestEntryParam::progress > ProcessManifestEntryParam::totalSize)
- {
- p->mr->info->SetTimeRemaining(0);
- }
- else
- {
- if(TimeGetTime() / kTimeIntervalsPerMs != ProcessManifestEntryParam::startTime)
- {
- double timeElapsed = (TimeGetTime() / kTimeIntervalsPerMs - ProcessManifestEntryParam::startTime) / 1000;
- double bytesPerSec = (float)(ProcessManifestEntryParam::progress ) / timeElapsed;
- p->mr->info->SetTimeRemaining(bytesPerSec ? (int)((ProcessManifestEntryParam::totalSize - ProcessManifestEntryParam::progress) / bytesPerSec) : 0);
- }
- }
- }
-}
-
-//============================================================================
-static void ProcessManifest (void * param) {
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- AtomicAdd(&s_perf[kPerfThreadTaskCount], 1);
-
- ManifestResult * mr = (ManifestResult *)param;
-
- PatchInfo patchInfo;
- patchInfo.stage = 0;
- patchInfo.progressStage = 0;
- patchInfo.progress = 0;
- mr->info->progressCallback(kStatusPending, &patchInfo);
-
- char text[256];
- StrPrintf(text, arrsize(text), "Checking for updates...");
- mr->info->SetText(text);
-
- unsigned entryCount = mr->manifest.Count();
- NetCliFileManifestEntry * manifest = mr->manifest.Ptr();
-
- FILE *fd = nil;
- ARRAY(ProcessManifestEntryParam) params;
- params.Reserve(mr->manifest.Count());
- for (unsigned i = 0; i < entryCount; ++i) {
- ProcessManifestEntryParam * p = params.New();
- p->index = i;
- p->mr = mr;
- p->exists = false;
- plFileName path = plFileName::Join(s_workingDir, plString::FromWchar(mr->manifest[i].clientName));
- fd = plFileSystem::Open(path, "r");
- if (fd)
- {
- p->exists = true;
- p->totalSize += p->mr->manifest[i].zipSize;
- fclose(fd);
- }
- }
-
- ProcessManifestEntryParam::startTime = (double)(TimeGetTime() / kTimeIntervalsPerMs);
-
- for (unsigned i = 0; i < entryCount && s_running; ++i){
- ProcessManifestEntry(¶ms[i], kNetSuccess);
- }
-
- if(s_running)
- {
- PatchInfo patchInfo;
- patchInfo.stage = 0;
- patchInfo.progressStage = 0;
- patchInfo.progress = 1000;
- mr->info->progressCallback(kStatusPending, &patchInfo);
-
- AtomicAdd(&s_numFiles, mr->indices.Count());
- if(!s_numFiles || !s_running) {
- s_patchComplete = true;
- }
- else {
- mr->info->SetText("Updating URU...");
-
- PatchInfo patchInfo;
- patchInfo.stage = 0;
- patchInfo.progressStage = 0;
- patchInfo.progress = 0;
- mr->info->progressCallback(kStatusPending, &patchInfo);
-
- for (unsigned i = 0; i < mr->indices.Count(); ++i)
- {
- if(s_running)
- {
- unsigned index = mr->indices[i];
- plFileName path = plFileName::Join(s_workingDir, plString::FromWchar(manifest[index].clientName));
- plFileSystem::CreateDir(path.StripFileName(), true);
-
- ManifestFile* mf = new ManifestFile(
- plString::FromWchar(manifest[index].clientName),
- plString::FromWchar(manifest[index].downloadName),
- plString::FromWchar(manifest[index].md5),
- manifest[index].flags,
- mr->info
- );
-
- if (i < kMaxManifestFileRequests) {
- ProgressStream * stream = new ProgressStream;
- if (!stream->Open(path, "wb")) {
-#ifdef PLASMA_EXTERNAL_RELEASE
- MessageBox(nil, s_fileOpenError, "URU Launcher", MB_ICONERROR);
-#else
- char str[256];
- StrPrintf(str, arrsize(str), "%s %s", path.AsString().c_str(), s_fileOpenError);
- MessageBox(nil, str, "URU Launcher", MB_ICONERROR);
-#endif
- Shutdown(mr->info);
- }
-#ifndef PLASMA_EXTERNAL_RELEASE
- char text[256];
- StrPrintf(text, arrsize(text), "Updating URU... %S", manifest[i].clientName);
- mr->info->SetText(text);
-#endif
- // fire off our initial requests. The remaining will be added as files are downloaded
- NetCliFileDownloadRequest(mf->zipName, stream, DownloadCallback, mf, mr->info->buildId);
- }
- else {
- // queue up this file download
- manifestQueue.push(mf);
- }
- }
- }
- }
- }
- delete mr;
- AtomicAdd(&s_perf[kPerfThreadTaskCount], -1);
-}
-
-//============================================================================
-static void ManifestCallback (
- ENetError result,
- void * param,
- const wchar_t group[],
- const NetCliFileManifestEntry manifest[],
- unsigned entryCount
-){
- s_numConnectFailures = 0;
-
- plLauncherInfo * info = (plLauncherInfo *) param;
-
- if(!s_running || IS_NET_ERROR(result)) {
- if (s_running && !s_patchError) {
- switch (result) {
- case kNetErrTimeout:
- NetCliFileManifestRequest(ManifestCallback, param, group);
- break;
-
- default: {
- char str[256];
- StrPrintf(str, arrsize(str), "Failed to download manifest from server");
- MessageBox(nil, str, "URU Launcher", MB_ICONERROR);
- s_patchError = true;
- }
- break;
- }
- }
- return;
- }
-
- ManifestResult * mr = new ManifestResult();
- StrCopy(mr->group, group, arrsize(mr->group));
- mr->manifest.Set(manifest, entryCount);
- mr->info = info;
-
- // sort our requests by size(this must be done for the next step to work)
- QSORT(
- NetCliFileManifestEntry,
- mr->manifest.Ptr(),
- mr->manifest.Count(),
- elem1.fileSize > elem2.fileSize
- );
-
- // remove duplicate entries. This can cause some bad problems if not done. It will cause MD5 checks to fail, since it can be writing a file while MD5 checking it.
- ARRAY(NetCliFileManifestEntry) noDuplicates;
- noDuplicates.Reserve(mr->manifest.Count());
- for(unsigned i = 0; i < entryCount - 1; ++i)
- {
- if (mr->manifest[i].clientName != mr->manifest[i+1].clientName)
- {
- noDuplicates.Add(mr->manifest[i]);
- }
- }
- noDuplicates.Add(mr->manifest[entryCount - 1]);
-
- // adjust our array and set data
- mr->manifest.ShrinkBy(mr->manifest.Count() - noDuplicates.Count());
- mr->manifest.Set(noDuplicates.Ptr(), noDuplicates.Count());
-
- (void)_beginthread(ProcessManifest, 0, mr);
-}
-
-//============================================================================
-static void ThinManifestCallback (
- ENetError result,
- void * param,
- const wchar_t group[],
- const NetCliFileManifestEntry manifest[],
- unsigned entryCount
-){
- s_numConnectFailures = 0;
-
- plLauncherInfo * info = (plLauncherInfo *) param;
- char text[256];
- StrPrintf(text, arrsize(text), "Checking for updates...");
- info->SetText(text);
-
- if(!s_running || IS_NET_ERROR(result)) {
- if (s_running && !s_patchError) {
- switch (result) {
- case kNetErrTimeout:
- NetCliFileManifestRequest(ManifestCallback, param, group);
- break;
-
- default: {
- char str[256];
- StrPrintf(str, arrsize(str), "Failed to download manifest from server");
- MessageBox(nil, str, "URU Launcher", MB_ICONERROR);
- s_patchError = true;
- }
- break;
- }
- }
- return;
- }
- s_patchComplete = true;
- for (unsigned i = 0; i < entryCount; ++i) {
- if (!s_running)
- return;
-
- plFileName path = plFileName::Join(s_workingDir, plString::FromWchar(manifest[i].clientName));
- if (!MD5Check(path, plString::FromWchar(manifest[i].md5, 32).c_str())) {
- s_patchComplete = false;
- NetCliFileManifestRequest(ManifestCallback, info, s_manifest, info->buildId);
- break;
- }
- PatchInfo patchInfo;
- patchInfo.stage = 0;
- patchInfo.progressStage = 0;
- patchInfo.progress = (unsigned)((float)i / (float)entryCount * 1000.0f);
- info->progressCallback(kStatusPending, &patchInfo);
-#ifndef PLASMA_EXTERNAL_RELEASE
- char text[256];
- StrPrintf(text, arrsize(text), "Checking for updates... %S", manifest[i].clientName);
- info->SetText(text);
-#endif
- }
-}
-
-
-/*****************************************************************************
-*
-* ProgressStream Functions
-*
-***/
-
-//============================================================================
-uint32_t ProgressStream::Write(uint32_t byteCount, const void* buffer) {
- if(!s_running || s_patchError)
- return 0;
- if(!startTime) {
- startTime = TimeGetSecondsSince2001Utc();
- }
- progress += byteCount;
- float p = (float)progress / (float)totalBytes * 1000; // progress
-
- PatchInfo patchInfo;
- patchInfo.stage = 1;
- patchInfo.progress = (unsigned) p;
- patchInfo.progressStage = 50;
- info->progressCallback(kStatusPending, (void *)&patchInfo);
-
- // there seems to, sometimes, be a slight discrepency in progress and totalBytes.
- if(progress > totalBytes)
- {
- info->SetBytesRemaining(0);
- info->SetTimeRemaining(0);
- }
- else
- {
- info->SetBytesRemaining(totalBytes - progress);
- if(TimeGetSecondsSince2001Utc() != startTime)
- {
- uint32_t bytesPerSec = (progress ) / (TimeGetSecondsSince2001Utc() - startTime);
- info->SetTimeRemaining(bytesPerSec ? (totalBytes - progress) / bytesPerSec : 0);
- }
- }
- return plZlibStream::Write(byteCount, buffer);
-}
-
-
-//============================================================================
-static void FileSrvIpAddressCallback (
- ENetError result,
- void * param,
- const wchar_t addr[]
-) {
- NetCliGateKeeperDisconnect();
-
- if (IS_NET_ERROR(result)) {
- plString msg = plString::Format("FileSrvIpAddressRequest failed: %S", NetErrorToString(result));
- plStatusLog::AddLineS("patcher.log", msg.c_str());
-
- s_patchError = true;
- return;
- }
-
- plLauncherInfo *info = (plLauncherInfo *) param;
-
- // Start connecting to the server
- const char* caddr = hsWStringToString(addr);
- NetCliFileStartConnect(&caddr, 1, true);
- delete[] caddr;
-
- NetCliFileManifestRequest(ThinManifestCallback, info, s_thinmanifest, info->buildId);
-
- ProgressStream::info = info;
- PatchInfo patchInfo;
- patchInfo.stage = 0;
- patchInfo.progressStage = 0;
- patchInfo.progress = 0;
- info->progressCallback(kStatusPending, &patchInfo);
-}
-
-
-/*****************************************************************************
-*
-* Public Functions
-*
-***/
-
-//============================================================================
-void InitAsyncCore () {
- if(AtomicAdd(&s_asyncCoreInitCount, 1) > 0)
- return;
- AsyncCoreInitialize();
-
- plStatusLog::AddLineS("patcher.log", plProduct::ProductString().c_str());
-}
-
-//============================================================================
-void ShutdownAsyncCore () {
- if(AtomicAdd(&s_asyncCoreInitCount, -1) > 1)
- return;
- ASSERT(s_asyncCoreInitCount >= 0);
-
- while (s_perf[kPerfThreadTaskCount])
- AsyncSleep(10);
-
- AsyncCoreDestroy(30 * 1000);
-}
-
-//============================================================================
-// param = URU_PreparationRequest
-void UruPrepProc (void * param) {
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- s_running = true;
-
- plLauncherInfo *info = (plLauncherInfo *) param;
- s_workingDir = plString::FromWchar(info->path);
-
- InitAsyncCore();
- NetClientInitialize();
- NetClientSetErrorHandler(NetErrorHandler);
- NetClientSetTransTimeoutMs(5 * 60 * 1000); // five minute timeout
-
- s_patchComplete = false;
- s_patchError = false;
-
- const char** addrs;
- unsigned count;
-
- count = GetGateKeeperSrvHostnames(&addrs);
-
- // Start connecting to the server
- NetCliGateKeeperStartConnect(addrs, count);
-
- // request a file server ip address
- NetCliGateKeeperFileSrvIpAddressRequest(FileSrvIpAddressCallback, param, true);
-
- do {
- NetClientUpdate();
- AsyncSleep(10);
- } while ((!s_patchComplete && !s_patchError && s_running) || s_perf[kPerfThreadTaskCount]);
-
- while (manifestQueue.size())
- {
- ManifestFile* mf = manifestQueue.front();
- manifestQueue.pop();
- delete mf;
- }
- // If s_patchError, we don't wait around for s_numFiles
- // to drop to zero because it never does for reasons
- // I'm not willing to debug at the moment, so we just
- // bail on them. This causes a race condition with
- // the outstanding file object cancel/deletion and
- // subsequently a memory leak. -eap
-
- if (s_patchError) {
- info->SetText("Exiting...");
- }
- else {
- PatchInfo patchInfo;
- patchInfo.stage = 2;
- patchInfo.progressStage = 100;
- patchInfo.progress = 1000;
- info->progressCallback(kStatusOk, &patchInfo);
- }
-
- ProgressStream::info = nil;
-
- NetCliFileDisconnect ();
- NetClientUpdate();
-
- // Shutdown the client/server networking subsystem
- NetClientDestroy();
-
- info->prepCallback(s_patchError ? kStatusError : kStatusOk, nil);
-}
-
-//============================================================================
-void PlayerStopProc (void * param) {
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- s_running = false;
- plLauncherInfo *info = (plLauncherInfo *) param;
- //TerminateProcess(s_pi.hProcess, kExitCodeTerminated);
- info->stopCallback(kStatusOk, nil);
-}
-
-//============================================================================
-void PlayerTerminateProc (void * param) {
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- s_running = false;
- plLauncherInfo *info = (plLauncherInfo *) param;
- ShutdownAsyncCore();
- info->terminateCallback(kStatusOk, nil);
-}
-
-//============================================================================
-void UruStartProc (void * param) {
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- if(!s_running)
- return;
-
- plLauncherInfo *info = (plLauncherInfo *) param;
-
- wchar_t workDir[MAX_PATH];
- StrPrintf(workDir, arrsize(workDir), L"%s", info->path);
- //fprintf(stderr, "URUPlayer StartProc gamePath is:%ws\n", workDir);
-
- wchar_t cmdLine[MAX_PATH];
- StrPrintf(cmdLine, arrsize(cmdLine), L"%s\\%s %s", workDir, s_clientExeName, info->cmdLine);
-
- // Create the named event so the client won't restart us (Windows will clean it up when we exit)
- HANDLE hPatcherEvent = CreateEventW(nil, TRUE, FALSE, L"UruPatcherEvent");
- if (hPatcherEvent == NULL) {
- info->startCallback(kStatusError, nil);
- return;
- }
-
- fprintf(stderr, "URUPlayer StartProc, running game process at dir:%ws, cmd:%ws for application:%ws\n", workDir, cmdLine, s_clientExeName);
-
- STARTUPINFOW si;
- memset(&si, 0, sizeof(si));
- memset(&s_pi, 0, sizeof(s_pi));
- si.cb = sizeof(si);
-
- info->SetText("Launching URU...");
- BOOL success = CreateProcessW(
- NULL,
- cmdLine,
- NULL, // plProcessAttributes
- NULL, // plThreadAttributes
- FALSE, // bInheritHandles
- 0, // dwCreationFlags
- NULL, // lpEnvironment
- workDir, // lpCurrentDirectory
- &si,
- &s_pi
- );
-
- if (success)
- {
- fprintf(stderr, "%d", GetLastError());
- info->returnCode = s_pi.dwProcessId;
- CloseHandle( s_pi.hThread );
- CloseHandle( s_pi.hProcess );
- // This may smooth the visual transition from GameTap to Uru, or it may make it worse.
- WaitForInputIdle(s_pi.hProcess, INFINITE);
- //_beginthread(WaitUruExitProc, 0, param);
-
- // wait for the event to signal (give the client 10 seconds to start up, then die)
- DWORD wait = WaitForSingleObject(hPatcherEvent, 10000);
- if (wait == WAIT_TIMEOUT)
- info->startCallback(kStatusOk, nil);
- else
- info->startCallback(kStatusOk, nil);
- }
- else
- {
- info->startCallback(kStatusError, nil);
- }
-}
diff --git a/Sources/Plasma/Apps/plClientPatcher/UruPlayer.h b/Sources/Plasma/Apps/plClientPatcher/UruPlayer.h
deleted file mode 100644
index b769ed53..00000000
--- a/Sources/Plasma/Apps/plClientPatcher/UruPlayer.h
+++ /dev/null
@@ -1,67 +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/Apps/plClientPatcher/UruPlayer.h
-*
-***/
-
-#ifdef PLASMA20_SOURCES_PLASMA_APPS_PLCLIENTPATCHER_URUPLAYER_H
-#error "Header $/Plasma20/Sources/Plasma/Apps/plClientPatcher/UruPlayer.h included more than once"
-#endif
-#define PLASMA20_SOURCES_PLASMA_APPS_PLCLIENTPATCHER_URUPLAYER_H
-
-
-/*****************************************************************************
-*
-* UruPlayer.cpp
-*
-***/
-
-void InitAsyncCore ();
-void ShutdownAsyncCore () ;
-void UruPrepProc (void * param);
-void UruStartProc (void * param);
-void PlayerTerminateProc (void * param);
-void PlayerStopProc (void * param);
-
-extern plFileName kPatcherExeFilename;
diff --git a/Sources/Plasma/Apps/plClientPatcher/plLauncherCallback.h b/Sources/Plasma/Apps/plClientPatcher/plLauncherCallback.h
deleted file mode 100644
index e58275a7..00000000
--- a/Sources/Plasma/Apps/plClientPatcher/plLauncherCallback.h
+++ /dev/null
@@ -1,65 +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/Apps/plUruLauncher/plLauncherCallback.h
-*
-***/
-
-#ifdef PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_PLLAUNCHERCALLBACK_H
-#error "Header $/Plasma20/Sources/Plasma/Apps/plUruLauncher/plLauncherCallback.h included more than once"
-#endif
-#define PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_PLLAUNCHERCALLBACK_H
-
-enum EStatus {
- kStatusOk,
-};
-
-typedef void (*launcherCallback)(int status, void *param);
-struct plLauncherCallback {
- launcherCallback prepCallback;
- launcherCallback initCallback;
- launcherCallback startCallback;
- launcherCallback stopCallback;
- launcherCallback terminateCallback;
-
-};
\ No newline at end of file
diff --git a/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt b/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt
index 0ee292ed..40609b31 100644
--- a/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt
+++ b/Sources/Plasma/Apps/plUruLauncher/CMakeLists.txt
@@ -9,14 +9,12 @@ include_directories(${OPENSSL_INCLUDE_DIR})
include_directories(${CURL_INCLUDE_DIR})
set(plUruLauncher_HEADERS
- Intern.h
- Pch.h
- plLauncherInfo.h
+ plClientLauncher.h
)
set(plUruLauncher_SOURCES
- Main.cpp
- SelfPatcher.cpp
+ plClientLauncher.cpp
+ winmain.cpp
)
set(plUruLauncher_RESOURCES
@@ -34,12 +32,10 @@ if(PLASMA_EXTERNAL_RELEASE)
endif(PLASMA_EXTERNAL_RELEASE)
target_link_libraries(plUruLauncher CoreLib)
target_link_libraries(plUruLauncher pfConsoleCore)
+target_link_libraries(plUruLauncher pfPatcher)
target_link_libraries(plUruLauncher plAudioCore)
-target_link_libraries(plUruLauncher plClientPatcher)
target_link_libraries(plUruLauncher plCompression)
target_link_libraries(plUruLauncher plFile)
-target_link_libraries(plUruLauncher plNetClient)
-target_link_libraries(plUruLauncher plNetClientComm)
target_link_libraries(plUruLauncher plNetGameLib)
target_link_libraries(plUruLauncher plNetMessage)
target_link_libraries(plUruLauncher plNetTransport)
diff --git a/Sources/Plasma/Apps/plUruLauncher/Intern.h b/Sources/Plasma/Apps/plUruLauncher/Intern.h
deleted file mode 100644
index bdd81d6c..00000000
--- a/Sources/Plasma/Apps/plUruLauncher/Intern.h
+++ /dev/null
@@ -1,61 +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/Apps/plUruLauncher/Intern.h
-*
-***/
-
-#ifdef PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_INTERN_H
-#error "Header $/Plasma20/Sources/Plasma/Apps/plUruLauncher/Intern.h included more than once"
-#endif
-#define PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_INTERN_H
-
-
-
-/*****************************************************************************
-*
-* SelfPatcher.cpp
-*
-***/
-bool SelfPatch (bool noSelfPatch, bool * abort, ENetError * result, plLauncherInfo *info);
-void SetReturnCode (DWORD retCode);
\ No newline at end of file
diff --git a/Sources/Plasma/Apps/plUruLauncher/Main.cpp b/Sources/Plasma/Apps/plUruLauncher/Main.cpp
deleted file mode 100644
index 5578633e..00000000
--- a/Sources/Plasma/Apps/plUruLauncher/Main.cpp
+++ /dev/null
@@ -1,884 +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/Apps/plUruLauncher/Main.cpp
-*
-***/
-
-#include "Pch.h"
-#include "hsThread.h"
-#include
-#pragma hdrstop
-
-
-#include "resource.h"
-#include
-#define WIN32_LEAN_AND_MEAN
-#define WHITESPACE L" \"\t\r\n\x1A"
-#define UPDATE_STATUSMSG_SECONDS 30 // Must be an int
-
-
-/*****************************************************************************
-*
-* Private
-*
-***/
-
-enum ELogSev {
- kLogInfo,
- kLogErr,
- kNumLogSev
-};
-
-enum {
- kEventTimer = 1,
-};
-
-enum EEventType {
- kEventSetProgress,
- kEventSetText,
- kEventSetStatusText,
- kEventSetTimeRemaining,
- kEventSetBytesRemaining,
-};
-
-// base window event
-struct WndEvent {
- LINK(WndEvent) link;
- EEventType type;
-};
-
-struct SetProgressEvent : WndEvent {
- int progress;
-};
-
-struct SetTextEvent : WndEvent {
- char text[MAX_PATH];
-};
-
-struct SetStatusTextEvent : WndEvent {
- char text[MAX_PATH];
-};
-
-struct SetTimeRemainingEvent : WndEvent {
- unsigned seconds;
-};
-
-struct SetBytesRemainingEvent : WndEvent {
- unsigned bytes;
-};
-
-
-/*****************************************************************************
-*
-* Private data
-*
-***/
-
-static bool s_shutdown;
-static bool s_prepared;
-static int s_retCode = 1;
-static long s_terminationIssued;
-static bool s_terminated;
-static plLauncherInfo s_launcherInfo;
-static HANDLE s_thread;
-static HANDLE s_event;
-static HINSTANCE s_hInstance;
-static HWND s_dialog;
-static hsSemaphore s_dialogCreateEvent(0);
-static hsMutex s_critsect;
-static LISTDECL(WndEvent, link) s_eventQ;
-static hsSemaphore s_shutdownEvent(0);
-static plFileName s_workingDir;
-static hsSemaphore s_statusEvent(0);
-static char s_curlError[CURL_ERROR_SIZE];
-
-
-/*****************************************************************************
-*
-* Local functions
-*
-***/
-
-//============================================================================
-static void Abort () {
- s_retCode = 0;
- s_shutdown = true;
-}
-
-//============================================================================
-static void PostEvent (WndEvent *event) {
- s_critsect.Lock();
- s_eventQ.Link(event);
- s_critsect.Unlock();
-}
-
-//============================================================================
-static void LogV (ELogSev sev, const wchar_t fmt[], va_list args) {
- static struct { FILE * file; const wchar_t * pre; } s_log[] = {
- { stdout, L"Inf" },
- { stderr, L"Err" },
- };
- static_assert(arrsize(s_log) == kNumLogSev, "Log severity array and enum have different sizes");
-
- fwprintf (s_log[sev].file, L"%s: ", s_log[sev].pre);
- vfwprintf(s_log[sev].file, fmt, args);
- fwprintf (s_log[sev].file, L"\n");
-
- if (sev >= kLogErr)
- Abort();
-}
-
-//============================================================================
-static void Log (ELogSev sev, const wchar_t fmt[], ...) {
- va_list args;
- va_start(args, fmt);
- LogV(sev, fmt, args);
- va_end(args);
-}
-
-//============================================================================
-// NOTE: Must use LocalFree() on the return value of this function when finished with the string
-static wchar_t *TranslateErrorCode(DWORD errorCode) {
- LPVOID lpMsgBuf;
-
- FormatMessageW(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- errorCode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (wchar_t *) &lpMsgBuf,
- 0,
- NULL
- );
- return (wchar_t *)lpMsgBuf;
-}
-
-//============================================================================
-static BOOL WINAPI CtrlHandler (DWORD) {
- static unsigned s_ctrlCount;
- if (++s_ctrlCount == 3)
- _exit(1); // exit process immediately upon 3rd Ctrl-C.
- Abort();
- return TRUE;
-}
-
-//============================================================================
-static void PrepareGame () {
- SetText("Connecting to server...");
- (void)_beginthread(UruPrepProc, 0, (void *) &s_launcherInfo);
-}
-
-//============================================================================
-static void InitGame () {
- s_launcherInfo.initCallback(kStatusOk, nil);
-}
-
-//============================================================================
-static void StartGame () {
- (void)_beginthread(UruStartProc, 0, (void *) &s_launcherInfo);
-}
-
-//============================================================================
-static void StopGame () {
- (void)_beginthread(PlayerStopProc, 0, (void *) &s_launcherInfo);
-}
-
-//============================================================================
-static void TerminateGame () {
- if (!AtomicSet(&s_terminationIssued, 1))
- _beginthread(PlayerTerminateProc, 0, (void *) &s_launcherInfo);
-}
-
-//============================================================================
-static void Recv_SetProgress (HWND hwnd, const SetProgressEvent &event) {
- SendMessage(GetDlgItem(s_dialog, IDC_PROGRESS), PBM_SETPOS, event.progress, NULL);
-}
-
-//============================================================================
-static void Recv_SetText (HWND hwnd, const SetTextEvent &event) {
- bool b = SendMessage(GetDlgItem(s_dialog, IDC_TEXT), WM_SETTEXT, 0, (LPARAM) event.text);
-}
-
-//============================================================================
-static void Recv_SetStatusText (HWND hwnd, const SetStatusTextEvent &event) {
- bool b = SendMessage(GetDlgItem(s_dialog, IDC_STATUS_TEXT), WM_SETTEXT, 0, (LPARAM) event.text);
-}
-
-//============================================================================
-static void Recv_SetTimeRemaining (HWND hwnd, const SetTimeRemainingEvent &event) {
- unsigned days;
- unsigned hours;
- unsigned minutes;
- unsigned seconds;
-
- if(event.seconds == 0xffffffff)
- {
- SendMessage(GetDlgItem(s_dialog, IDC_TIMEREMAINING), WM_SETTEXT, 0, (LPARAM) "estimating...");
- return;
- }
-
- seconds = event.seconds;
-
- days = seconds / (60 * 60 * 24);
- seconds -= (days * 60 * 60 * 24);
- hours = seconds / (60 * 60);
- seconds -= hours * 60 * 60;
- minutes = seconds / 60;
- seconds -= minutes * 60;
- seconds = seconds;
-
- char text[64] = {0};
- if(days)
- {
- if(days > 1)
- StrPrintf(text, arrsize(text), "%d days ", days);
- else
- StrPrintf(text, arrsize(text), "%d day ", days);
- }
- if(hours)
- {
- if(hours > 1)
- StrPrintf(text, arrsize(text), "%s%d hours ", text, hours);
- else
- StrPrintf(text, arrsize(text), "%s%d hour ", text, hours);
- }
- if(minutes)
- StrPrintf(text, arrsize(text), "%s%d min ", text, minutes);
- if( seconds || !text[0])
- StrPrintf(text, arrsize(text), "%s%d sec", text, seconds);
- bool b = SendMessage(GetDlgItem(s_dialog, IDC_TIMEREMAINING), WM_SETTEXT, 0, (LPARAM) text);
-}
-
-//============================================================================
-static void Recv_SetBytesRemaining (HWND hwnd, const SetBytesRemainingEvent &event) {
- char text[32];
- unsigned MB;
- unsigned decimal;
- unsigned bytes = event.bytes;
-
- unsigned GB = bytes / 1000000000;
- if(GB)
- {
- bytes -= GB * 1000000000;
- decimal = bytes / 100000000; // to two decimal places
- StrPrintf(text, arrsize(text), "%d.%d GB", GB, decimal);
- }
- else
- {
- MB = bytes / 1000000;
- bytes -= MB * 1000000;
- decimal = bytes / 100000; // to one decimal place
- StrPrintf(text, arrsize(text), "%d.%d MB", MB, decimal);
- }
- bool b = SendMessage(GetDlgItem(s_dialog, IDC_BYTESREMAINING), WM_SETTEXT, 0, (LPARAM) text);
-}
-
-//============================================================================
-static void DispatchEvents (HWND hwnd) {
- LISTDECL(WndEvent, link) eventQ;
-
- s_critsect.Lock();
- {
- eventQ.Link(&s_eventQ);
- }
- s_critsect.Unlock();
-
-#define DISPATCH(a) case kEvent##a: Recv_##a(hwnd, *(const a##Event *) event); break
- while (WndEvent *event = eventQ.Head()) {
- switch (event->type) {
- DISPATCH(SetProgress);
- DISPATCH(SetText);
- DISPATCH(SetStatusText);
- DISPATCH(SetTimeRemaining);
- DISPATCH(SetBytesRemaining);
- DEFAULT_FATAL(event->type);
- }
- delete event; // unlinks from list
- }
-#undef DISPATCH
-}
-
-//============================================================================
-static void OnTimer(HWND hwnd, unsigned int timerId) {
- if(s_shutdown) return;
- switch (timerId) {
- case kEventTimer:
- DispatchEvents(hwnd);
- break;
-
- DEFAULT_FATAL(timerId);
- }
-}
-
-//===========================================================================
-static void MessagePump (HWND hwnd) {
- for (;;) {
- // wait for a message or the shutdown event
- const DWORD result = MsgWaitForMultipleObjects(
- 1,
- &s_event,
- false,
- INFINITE,
- QS_ALLEVENTS
- );
- if (result == WAIT_OBJECT_0)
- return;
-
- // process windows messages
- MSG msg;
-
- while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
- if (!IsDialogMessage(s_dialog, &msg)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- if (msg.message == WM_QUIT) {
- return;
- }
- }
- }
-}
-
-//============================================================================
-BOOL CALLBACK SplashDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
-{
- switch( uMsg )
- {
- case WM_INITDIALOG:
- {
- PostMessage( GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETRANGE, 0, MAKELPARAM(0, 1000));
- }
- break;
-
- case WM_COMMAND:
- if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL) {
- // we dont shutdown the window here, but instead let the patcher know it needs to shutdown, and display our shutting down message.
- // setting s_shutdown also wont allow any more Set text messages.
- if(!s_shutdown)
- {
- s_shutdown = true;
- SendMessage(GetDlgItem(s_dialog, IDC_TEXT), WM_SETTEXT, 0, (LPARAM) "Shutting Down...");
- EnableWindow(GetDlgItem(s_dialog, IDCANCEL), false);
- }
- }
- break;
-
- case WM_KEYDOWN:
- break;
-
- case WM_NCHITTEST:
- SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, (LONG_PTR)HTCAPTION);
- return TRUE;
-
- case WM_TIMER:
- OnTimer(hwndDlg, wParam);
- break;
-
- case WM_QUIT:
- ::DestroyWindow(hwndDlg);
- break;
-
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
-
- default:
- return DefWindowProc(hwndDlg, uMsg, wParam, lParam);
- }
- return TRUE;
-}
-
-//============================================================================
-static void WindowThreadProc(void *) {
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- InitCommonControls();
- s_event = CreateEvent(
- (LPSECURITY_ATTRIBUTES) 0,
- false, // auto reset
- false, // initial state off
- (LPCTSTR) 0 // name
- );
-
- s_dialog = ::CreateDialog( s_hInstance, MAKEINTRESOURCE( IDD_DIALOG ), NULL, SplashDialogProc );
- SetWindowText(s_dialog, "URU Launcher");
-
-
- ::SetDlgItemText( s_dialog, IDC_TEXT, "Initializing patcher...");
- SetTimer(s_dialog, kEventTimer, 250, 0);
-
- SendMessage(GetDlgItem(s_dialog, IDC_PRODUCTSTRING), WM_SETTEXT, 0,
- (LPARAM)plProduct::ProductString().c_str());
-
- s_dialogCreateEvent.Signal();
-
- MessagePump(s_dialog);
-
- s_dialog = 0;
- s_shutdown = true;
- s_shutdownEvent.Signal();
-}
-
-//============================================================================
-static size_t CurlCallback(void *buffer, size_t size, size_t nmemb, void *)
-{
- static char status[256];
-
- strncpy(status, (const char *)buffer, std::min(size * nmemb, 256));
- status[255] = 0;
- SetStatusText(status);
- return size * nmemb;
-}
-
-//============================================================================
-static void StatusCallback(void *)
-{
-#ifdef USE_VLD
- VLDEnable();
-#endif
-
- const char *serverUrl = GetServerStatusUrl();
-
- CURL * hCurl = curl_easy_init();
- curl_easy_setopt(hCurl, CURLOPT_ERRORBUFFER, s_curlError);
-
- // update while we are running
- while(!s_shutdown)
- {
- curl_easy_setopt(hCurl, CURLOPT_USERAGENT, "UruClient/1.0");
- curl_easy_setopt(hCurl, CURLOPT_URL, serverUrl);
- curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, &CurlCallback);
-
- if (serverUrl[0] && curl_easy_perform(hCurl) != 0) // only perform request if there's actually a URL set
- SetStatusText(s_curlError);
-
- for(unsigned i = 0; i < UPDATE_STATUSMSG_SECONDS && !s_shutdown; ++i)
- {
- Sleep(1000);
- }
- }
-
- curl_easy_cleanup(hCurl);
-
- s_statusEvent.Signal();
-}
-
-
-/*****************************************************************************
-*
-* Exports
-*
-***/
-
-//============================================================================
-void PrepCallback (int id, void *param) {
- s_prepared = true;
- if (id)
- s_shutdown = true;
-
- if (!s_shutdown)
- InitGame();
-}
-
-//============================================================================
-void InitCallback (int id, void *param) {
- if (id)
- s_shutdown = true;
- if (!s_shutdown)
- StartGame();
-}
-
-//=============================================================================
-void StartCallback( int id, void *param) {
- if(id == kStatusError) {
- MessageBox(nil, "Failed to launch URU", "URU Launcher", MB_ICONERROR);
- }
- StopGame();
-}
-
-//============================================================================
-void StopCallback (int id, void *param) {
- s_shutdown = true;
- TerminateGame();
-}
-
-//============================================================================
-void TerminateCallback (int id, void *param) {
- s_shutdown = true;
- s_terminated = true;
-}
-
-//============================================================================
-void ExitCallback (int id, void *param) {
- TerminateGame();
-}
-
-//============================================================================
-void ProgressCallback (int id, void *param) {
- PatchInfo *patchInfo = (PatchInfo *)param;
- SetProgress(patchInfo->progress);
-}
-
-//============================================================================
-void SetTextCallback (const char text[]) {
- SetText(text);
-}
-
-//============================================================================
-void SetStatusTextCallback (const char text[]) {
- SetStatusText(text);
-}
-
-//============================================================================
-void SetTimeRemainingCallback (unsigned seconds) {
- SetTimeRemaining(seconds);
-}
-
-//============================================================================
-void SetBytesRemainingCallback (unsigned bytes) {
- SetBytesRemaining(bytes);
-}
-
-
-enum {
- kArgServerIni,
- kArgNoSelfPatch,
- kArgBuildId,
- kArgCwd,
-};
-
-static const CmdArgDef s_cmdLineArgs[] = {
- { kCmdArgFlagged | kCmdTypeString, L"ServerIni", kArgServerIni },
- { kCmdArgFlagged | kCmdTypeBool, L"NoSelfPatch", kArgNoSelfPatch },
- { kCmdArgFlagged | kCmdTypeInt, L"BuildId", kArgBuildId },
- { kCmdArgFlagged | kCmdTypeBool, L"Cwd", kArgCwd },
-};
-
-#include "pfConsoleCore/pfConsoleEngine.h"
-PF_CONSOLE_LINK_FILE(Core)
-
-//============================================================================
-int __stdcall WinMain (
- HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow
-){
- PF_CONSOLE_INITIALIZE(Core)
-
- wchar_t token[256];
- const wchar_t *appCmdLine = AppGetCommandLine();
- StrTokenize(&appCmdLine, token, arrsize(token), WHITESPACE);
- while(!StrStr(token, L".exe") && !StrStr(token, L".tmp"))
- {
- StrTokenize(&appCmdLine, token, arrsize(token), WHITESPACE);
- }
- while (*appCmdLine == L' ')
- ++appCmdLine;
-
- bool isTempPatcher = false;
-
- plFileName curPatcherFile = plFileSystem::GetCurrentAppPath();
- plFileName newPatcherFile = plFileName::Join(curPatcherFile.StripFileName(), kPatcherExeFilename);
-
- // If our exe name doesn't match the "real" patcher exe name, then we are a newly
- // downloaded patcher that needs to be copied over to the "real" exe.. so do that,
- // exec it, and exit.
- if (0 != curPatcherFile.AsString().CompareI(newPatcherFile.AsString())) {
- isTempPatcher = true;
- }
-
- CCmdParser cmdParser(s_cmdLineArgs, arrsize(s_cmdLineArgs));
- cmdParser.Parse();
-
- if (!cmdParser.IsSpecified(kArgCwd))
- s_workingDir = plFileSystem::GetCurrentAppPath().StripFileName();
-
- s_hInstance = hInstance;
- memset(&s_launcherInfo, 0, sizeof(s_launcherInfo));
- StrPrintf(s_launcherInfo.cmdLine, arrsize(s_launcherInfo.cmdLine), appCmdLine);
- s_launcherInfo.returnCode = 0;
-
- curl_global_init(CURL_GLOBAL_ALL);
-
- plFileName serverIni = "server.ini";
- if (cmdParser.IsSpecified(kArgServerIni))
- serverIni = plString::FromWchar(cmdParser.GetString(kArgServerIni));
-
- // Load the server.ini so we know what to connect to
- FILE *serverini = plFileSystem::Open(serverIni, "rb");
- if (serverini)
- {
- fclose(serverini);
- pfConsoleEngine tempConsole;
- tempConsole.ExecuteFile(serverIni);
- }
- else
- {
- hsMessageBox("No server.ini file found. Please check your URU installation.", "Error", hsMessageBoxNormal);
- return 1;
- }
-
- if(!isTempPatcher)
- {
- // create window thread
- s_thread = (HANDLE)_beginthread(
- WindowThreadProc,
- 0,
- nil
- );
- if(cmdParser.IsSpecified(kArgBuildId))
- s_launcherInfo.buildId = cmdParser.GetInt(kArgBuildId);
-
- // Wait for the dialog to be created
- s_dialogCreateEvent.Wait();
- _beginthread(StatusCallback, 0, nil); // get status
- }
-
- for (;;) {
- // Wait for previous process to exit. This will happen if we just patched.
- HANDLE mutex = CreateMutexW(NULL, TRUE, kPatcherExeFilename.AsString().ToWchar());
- DWORD wait = WaitForSingleObject(mutex, 0);
- while(!s_shutdown && wait != WAIT_OBJECT_0)
- wait = WaitForSingleObject(mutex, 100);
-
- // User canceled
- if (s_shutdown)
- break;
-
- // If our exe name doesn't match the "real" patcher exe name, then we are a newly
- // downloaded patcher that needs to be copied over to the "real" exe.. so do that,
- // exec it, and exit.
- if (isTempPatcher) {
-// MessageBox(nil, "Replacing patcher file", "Msg", MB_OK);
-
- // Wait for the other process to exit
- Sleep(1000);
-
- if (!plFileSystem::Unlink(newPatcherFile)) {
- wchar_t error[256];
- DWORD errorCode = GetLastError();
- wchar_t *msg = TranslateErrorCode(errorCode);
-
- StrPrintf(error, arrsize(error), L"Failed to delete old patcher executable. %s", msg);
- MessageBoxW(GetTopWindow(nil), error, L"Error", MB_OK);
- LocalFree(msg);
- break;
- }
- if (!plFileSystem::Move(curPatcherFile, newPatcherFile)) {
- wchar_t error[256];
- DWORD errorCode = GetLastError();
- wchar_t *msg = TranslateErrorCode(errorCode);
-
- StrPrintf(error, arrsize(error), L"Failed to replace old patcher executable. %s", msg);
- MessageBoxW(GetTopWindow(nil), error, L"Error", MB_OK);
- // attempt to clean up this tmp file
- plFileSystem::Unlink(curPatcherFile);
- LocalFree(msg);
- break;
- }
-
- // launch new patcher
- STARTUPINFOW si;
- PROCESS_INFORMATION pi;
- memset(&si, 0, sizeof(si));
- memset(&pi, 0, sizeof(pi));
- si.cb = sizeof(si);
-
- wchar_t cmdline[MAX_PATH];
- StrPrintf(cmdline, arrsize(cmdline), L"%S %s", newPatcherFile.AsString().c_str(), s_launcherInfo.cmdLine);
-
- // we have only successfully patched if we actually launch the new version of the patcher
- (void)CreateProcessW(
- NULL,
- cmdline,
- NULL,
- NULL,
- FALSE,
- DETACHED_PROCESS,
- NULL,
- NULL,
- &si,
- &pi
- );
-
- SetReturnCode( pi.dwProcessId );
- CloseHandle( pi.hThread );
- CloseHandle( pi.hProcess );
-
- // We're done.
- break;
- }
-
- // Clean up old temp files
- plFileName fileSpec = plFileSystem::GetCurrentAppPath().StripFileName();
- std::vector tmpFiles = plFileSystem::ListDir(fileSpec, "*.tmp");
- std::for_each(tmpFiles.begin(), tmpFiles.end(), [](const plFileName &tmp) {
- plFileSystem::Unlink(tmp);
- });
-
- SetConsoleCtrlHandler(CtrlHandler, TRUE);
- InitAsyncCore(); // must do this before self patch, since it needs to connect to the file server
-
- // check to see if the patcher needs to be updated, and do it if so.
- ENetError selfPatchResult;
- if (false == (SelfPatch(cmdParser.IsSpecified(kArgNoSelfPatch), &s_shutdown, &selfPatchResult, &s_launcherInfo)) && IS_NET_SUCCESS(selfPatchResult)) {
- // We didn't self-patch, so check for client updates and download them, then exec the client
- StrCopy(s_launcherInfo.path, s_workingDir.AsString().ToWchar(), arrsize(s_launcherInfo.path));
- s_launcherInfo.prepCallback = PrepCallback;
- s_launcherInfo.initCallback = InitCallback;
- s_launcherInfo.startCallback = StartCallback;
- s_launcherInfo.stopCallback = StopCallback;
- s_launcherInfo.terminateCallback = TerminateCallback;
- s_launcherInfo.progressCallback = ProgressCallback;
- s_launcherInfo.exitCallback = ExitCallback;
- s_launcherInfo.SetText = SetTextCallback;
- s_launcherInfo.SetStatusText = SetStatusTextCallback;
- s_launcherInfo.SetTimeRemaining = SetTimeRemainingCallback;
- s_launcherInfo.SetBytesRemaining = SetBytesRemainingCallback;
- PrepareGame();
-
- while (!s_shutdown) // wait for window to be closed
- AsyncSleep(10);
-
- StopGame();
-
- // Wait for the PrepareGame thread to exit
- while (!s_prepared)
- AsyncSleep(10);
-
- // Wait for the StopGame thread to exit
- while (!s_terminated)
- Sleep(10);
- }
- else if (IS_NET_ERROR(selfPatchResult)) {
- // Self-patch failed
- SetText("Self-patch failed. Exiting...");
- if (!s_shutdown) {
- wchar_t str[256];
- StrPrintf(str, arrsize(str), L"Patcher update failed. Error %u, %s", selfPatchResult, NetErrorToString(selfPatchResult));
- MessageBoxW(GetTopWindow(nil), str, L"Error", MB_OK);
- }
- }
- else {
- // We self-patched, so just exit (self-patcher already launched the new patcher.
- // it is now waiting for our process to shutdown and release the shared mutex).
- SetText("Patcher updated. Restarting...");
- s_shutdown = true;
- }
-
- ShutdownAsyncCore();
- s_statusEvent.Wait();
-
- PostMessage(s_dialog, WM_QUIT, 0, 0); // tell our window to shutdown
- s_shutdownEvent.Wait(); // wait for our window to shutdown
-
- SetConsoleCtrlHandler(CtrlHandler, FALSE);
-
- if (s_event)
- CloseHandle(s_event);
-
- s_eventQ.Clear();
- break;
- }
-
- curl_global_cleanup();
-
- return s_launcherInfo.returnCode;
-}
-
-//============================================================================
-void SetReturnCode (DWORD retCode) {
- s_launcherInfo.returnCode = retCode;
-}
-
-
-/*****************************************************************************
-*
-* Window Events
-*
-***/
-
-//============================================================================
-void SetProgress (unsigned progress) {
- SetProgressEvent *event = new SetProgressEvent();
- event->type = kEventSetProgress;
- event->progress = progress;
- PostEvent(event);
-}
-
-//============================================================================
-void SetText (const char text[]) {
- SetTextEvent *event = new SetTextEvent();
- event->type = kEventSetText;
- StrCopy(event->text, text, arrsize(event->text));
- PostEvent(event);
-}
-
-//============================================================================
-void SetStatusText (const char text[]) {
- SetTextEvent *event = new SetTextEvent();
- event->type = kEventSetStatusText;
- StrCopy(event->text, text, arrsize(event->text));
- PostEvent(event);
-}
-
-//============================================================================
-void SetTimeRemaining (unsigned seconds) {
- SetTimeRemainingEvent *event = new SetTimeRemainingEvent;
- event->type = kEventSetTimeRemaining;
- event->seconds = seconds;
- PostEvent(event);
-}
-
-//============================================================================
-void SetBytesRemaining (unsigned bytes) {
- SetBytesRemainingEvent *event = new SetBytesRemainingEvent;
- event->type = kEventSetBytesRemaining;
- event->bytes = bytes;
- PostEvent(event);
-}
diff --git a/Sources/Plasma/Apps/plUruLauncher/Pch.h b/Sources/Plasma/Apps/plUruLauncher/Pch.h
deleted file mode 100644
index 262b5071..00000000
--- a/Sources/Plasma/Apps/plUruLauncher/Pch.h
+++ /dev/null
@@ -1,72 +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/Apps/plUruLauncher/Pch.h
-*
-***/
-
-#ifdef PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_PCH_H
-#error "Header $/Plasma20/Sources/Plasma/Apps/plUruLauncher/Pch.h included more than once"
-#endif
-#define PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_PCH_H
-
-#include "hsWindows.h"
-#include
-#include
-
-#include
-
-#include "pnUtils/pnUtils.h"
-#include "pnNetBase/pnNetBase.h"
-#include "pnAsyncCore/pnAsyncCore.h"
-#include "plProduct.h"
-#include "pnNetCli/pnNetCli.h"
-#include "plNetGameLib/plNetGameLib.h"
-#include "pnEncryption/plChecksum.h"
-
-#include "plCompression/plZlibStream.h"
-#include "plClientPatcher/UruPlayer.h"
-
-#include "plLauncherInfo.h"
-#include "Intern.h"
-
diff --git a/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp b/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp
deleted file mode 100644
index 1755b29c..00000000
--- a/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp
+++ /dev/null
@@ -1,338 +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/Apps/plUruLauncher/SelfPatcher.cpp
-*
-***/
-
-#include "Pch.h"
-#include "plStatusLog/plStatusLog.h"
-#pragma hdrstop
-
-
-/*****************************************************************************
-*
-* Private Data
-*
-***/
-
-#ifndef PLASMA_EXTERNAL_RELEASE
- static const wchar_t s_manifest[] = L"InternalPatcher";
-#else
- static const wchar_t s_manifest[] = L"ExternalPatcher";
-#endif
-
-class SelfPatcherStream : public plZlibStream {
- public:
- virtual uint32_t Write(uint32_t byteCount, const void* buffer);
- static plLauncherInfo *info;
- static unsigned totalBytes;
- static unsigned progress;
-};
-
-unsigned SelfPatcherStream::totalBytes = 0;
-unsigned SelfPatcherStream::progress = 0;
-
-static bool s_downloadComplete;
-static long s_numFiles;
-static ENetError s_patchResult;
-static bool s_updated;
-static plFileName s_newPatcherFile;
-
-
-/*****************************************************************************
-*
-* Private Functions
-*
-***/
-
-//============================================================================
-static void NetErrorHandler (ENetProtocol protocol, ENetError error) {
- plString msg = plString::Format("NetErr: %S", NetErrorToString(error));
- plStatusLog::AddLineS("patcher.log", msg.c_str());
-
- if (IS_NET_SUCCESS(s_patchResult))
- s_patchResult = error;
- s_downloadComplete = true;
-
- switch(error) {
- case kNetErrServerBusy:
- MessageBox(0, "Due to the high demand, the server is currently busy. Please try again later, or for alternative download options visit: http://www.mystonline.com/play/", "UruLauncher", MB_OK);
- s_patchResult = kNetErrServerBusy;
- s_downloadComplete = true;
- break;
- }
-}
-
-//============================================================================
-static void DownloadCallback (
- ENetError result,
- void * param,
- const plFileName & filename,
- hsStream * writer
-) {
- if(IS_NET_ERROR(result)) {
- switch (result) {
- case kNetErrTimeout:
- writer->Rewind();
- NetCliFileDownloadRequest(filename, writer, DownloadCallback, param);
- break;
-
- default:
- plString msg = plString::Format("Error getting patcher file: %S", NetErrorToString(result));
- plStatusLog::AddLineS("patcher.log", msg.c_str());
-
- if (IS_NET_SUCCESS(s_patchResult))
- s_patchResult = result;
- break;
- }
- return;
- }
-
- writer->Close();
- delete writer;
- AtomicAdd(&s_numFiles, -1);
-
- if(!s_numFiles) {
- s_downloadComplete = true;
- s_updated = true;
- }
-}
-
-//============================================================================
-static bool MD5Check (const plFileName &filename, const char *md5) {
- // Do md5 check
- plMD5Checksum existingMD5(filename);
- plMD5Checksum latestMD5;
-
- latestMD5.SetFromHexString(md5);
- return (existingMD5 == latestMD5);
-}
-
-//============================================================================
-static void ManifestCallback (
- ENetError result,
- void * param,
- const wchar_t group[],
- const NetCliFileManifestEntry manifest[],
- unsigned entryCount
-) {
- if(IS_NET_ERROR(result)) {
- switch (result) {
- case kNetErrTimeout:
- NetCliFileManifestRequest(ManifestCallback, nil, s_manifest);
- break;
-
- default:
- plString msg = plString::Format("Error getting patcher manifest: %S", NetErrorToString(result));
- plStatusLog::AddLineS("patcher.log", msg.c_str());
-
- if (IS_NET_SUCCESS(s_patchResult))
- s_patchResult = result;
- break;
- }
- return;
- }
-
-#ifndef PLASMA_EXTERNAL_RELEASE
- if (entryCount == 0) { // dataserver does not contain a patcher
- s_downloadComplete = true;
- return;
- }
-#endif
-
- // MD5 check current patcher against value in manifest
- ASSERT(entryCount == 1);
- plFileName curPatcherFile = plFileSystem::GetCurrentAppPath();
- if (!MD5Check(curPatcherFile, plString::FromWchar(manifest[0].md5, 32).c_str())) {
-// MessageBox(GetTopWindow(nil), "MD5 failed", "Msg", MB_OK);
- SelfPatcherStream::totalBytes += manifest[0].zipSize;
-
- AtomicAdd(&s_numFiles, 1);
- SetText("Downloading new patcher...");
-
- SelfPatcherStream * stream = new SelfPatcherStream;
- if (!stream->Open(s_newPatcherFile, "wb"))
- ErrorAssert(__LINE__, __FILE__, "Failed to create file: %s, errno: %u", s_newPatcherFile.AsString().c_str(), errno);
-
- NetCliFileDownloadRequest(plString::FromWchar(manifest[0].downloadName), stream, DownloadCallback, nil);
- }
- else {
- s_downloadComplete = true;
- }
-}
-
-//============================================================================
-static void FileSrvIpAddressCallback (
- ENetError result,
- void * param,
- const wchar_t addr[]
-) {
- NetCliGateKeeperDisconnect();
-
- if (IS_NET_ERROR(result)) {
- plString msg = plString::Format("FileSrvIpAddressRequest failed: %S", NetErrorToString(result));
- plStatusLog::AddLineS("patcher.log", msg.c_str());
-
- s_patchResult = result;
- s_downloadComplete = true;
- }
-
- // Start connecting to the server
- const char* caddr = hsWStringToString(addr);
- NetCliFileStartConnect(&caddr, 1, true);
- delete[] caddr;
-
- s_newPatcherFile = plFileSystem::GetCurrentAppPath().StripFileName();
- s_newPatcherFile = plFileSystem::GetTempFilename(kPatcherExeFilename.AsString().c_str(), s_newPatcherFile);
- plFileSystem::Unlink(s_newPatcherFile);
-
- NetCliFileManifestRequest(ManifestCallback, nil, s_manifest);
-}
-
-//============================================================================
-static bool SelfPatcherProc (bool * abort, plLauncherInfo *info) {
-
- bool patched = false;
- s_downloadComplete = false;
- s_patchResult = kNetSuccess;
-
- NetClientInitialize();
- NetClientSetErrorHandler(NetErrorHandler);
-
- const char** addrs;
- unsigned count;
-
- count = GetGateKeeperSrvHostnames(&addrs);
-
- // Start connecting to the server
- NetCliGateKeeperStartConnect(addrs, count);
-
- // request a file server ip address
- NetCliGateKeeperFileSrvIpAddressRequest(FileSrvIpAddressCallback, nil, true);
-
- while(!s_downloadComplete && !*abort) {
- NetClientUpdate();
- AsyncSleep(10);
- }
-
- NetCliFileDisconnect();
- NetClientUpdate();
-
- // Shutdown the client/server networking subsystem
- NetClientDestroy();
-
- if (s_downloadComplete && !*abort && s_updated && IS_NET_SUCCESS(s_patchResult)) {
-
- // launch new patcher
- STARTUPINFOW si;
- PROCESS_INFORMATION pi;
- memset(&si, 0, sizeof(si));
- memset(&pi, 0, sizeof(pi));
- si.cb = sizeof(si);
-
- wchar_t cmdline[MAX_PATH];
- StrPrintf(cmdline, arrsize(cmdline), L"%s %s",
- s_newPatcherFile.AsString().ToWchar().GetData(), info->cmdLine);
-
- // we have only successfully patched if we actually launch the new version of the patcher
- patched = CreateProcessW(
- NULL,
- cmdline,
- NULL,
- NULL,
- FALSE,
- DETACHED_PROCESS,
- NULL,
- NULL,
- &si,
- &pi
- );
- SetReturnCode(pi.dwProcessId);
- CloseHandle( pi.hThread );
- CloseHandle( pi.hProcess );
- ASSERT(patched);
- }
-
- return patched;
-}
-
-
-/*****************************************************************************
-*
-* ProgressStream Functions
-*
-***/
-
-//============================================================================
-uint32_t SelfPatcherStream::Write(uint32_t byteCount, const void* buffer) {
- progress += byteCount;
- float p = (float)progress / (float)totalBytes * 100; // progress
- SetProgress( (int)p );
- return plZlibStream::Write(byteCount, buffer);
-}
-
-
-/*****************************************************************************
-*
-* Protected Functions
-*
-***/
-
-//============================================================================
-// if return value is true, there was an update and the patcher should be shutdown, so the new patcher can take over
-bool SelfPatch (bool noSelfPatch, bool * abort, ENetError * result, plLauncherInfo *info) {
- bool patched = false;
- if (!noSelfPatch) {
- SetText("Checking for patcher update...");
- patched = SelfPatcherProc(abort, info);
- }
- *result = s_patchResult;
- return patched;
-}
-
-
-/* Enable themes in Windows XP and later */
-#pragma comment(linker,"\"/manifestdependency:type='win32' \
-name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
-processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
diff --git a/Sources/Plasma/Apps/plUruLauncher/plClientLauncher.cpp b/Sources/Plasma/Apps/plUruLauncher/plClientLauncher.cpp
new file mode 100644
index 00000000..4a8b015b
--- /dev/null
+++ b/Sources/Plasma/Apps/plUruLauncher/plClientLauncher.cpp
@@ -0,0 +1,351 @@
+/*==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 "HeadSpin.h"
+#include "plClientLauncher.h"
+#include "plFileSystem.h"
+#include "plProduct.h"
+#include "hsThread.h"
+#include "hsTimer.h"
+
+#include "pnUtils/pnUtils.h" // for CCmdParser
+#include "pnAsyncCore/pnAsyncCore.h"
+#include "plNetGameLib/plNetGameLib.h"
+#include "plStatusLog/plStatusLog.h"
+
+#include "pfPatcher/plManifests.h"
+#include "pfPatcher/pfPatcher.h"
+
+#include "pfConsoleCore/pfConsoleEngine.h"
+PF_CONSOLE_LINK_FILE(Core)
+
+#include
+
+plClientLauncher::ErrorFunc s_errorProc = nullptr; // don't even ask, cause I'm not happy about this.
+
+const int kNetTransTimeout = 5 * 60 * 1000; // 5m
+const int kShardStatusUpdateTime = 5; // 5s
+const int kAsyncCoreShutdownTime = 2 * 1000; // 2s
+const int kNetCoreUpdateSleepTime = 10; // 10ms
+
+// ===================================================
+
+class plShardStatus : public hsThread
+{
+ double fLastUpdate;
+ volatile bool fRunning;
+ hsEvent fUpdateEvent;
+ char fCurlError[CURL_ERROR_SIZE];
+
+public:
+ plClientLauncher::StatusFunc fShardFunc;
+
+ plShardStatus() :
+ fRunning(true), fLastUpdate(0)
+ { }
+
+ virtual hsError Run();
+ void Shutdown();
+ void Update();
+};
+
+static size_t ICurlCallback(void* buffer, size_t size, size_t nmemb, void* thread)
+{
+ static char status[256];
+
+ strncpy(status, (const char *)buffer, std::min(size * nmemb, arrsize(status)));
+ status[arrsize(status) - 1] = 0;
+ static_cast(thread)->fShardFunc(status);
+ return size * nmemb;
+}
+
+hsError plShardStatus::Run()
+{
+ {
+ const char* url = GetServerStatusUrl();
+
+ // initialize CURL
+ std::unique_ptr> curl(curl_easy_init(), curl_easy_cleanup);
+ curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, fCurlError);
+ curl_easy_setopt(curl.get(), CURLOPT_USERAGENT, "UruClient/1.0");
+ curl_easy_setopt(curl.get(), CURLOPT_URL, url);
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, this);
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, ICurlCallback);
+
+ // we want to go ahead and run once
+ fUpdateEvent.Signal();
+
+ // loop until we die!
+ do
+ {
+ fUpdateEvent.Wait();
+ if (!fRunning)
+ break;
+
+ if (url[0] && curl_easy_perform(curl.get()))
+ fShardFunc(fCurlError);
+ fLastUpdate = hsTimer::GetSysSeconds();
+ } while (fRunning);
+ }
+
+ return hsOK;
+}
+
+void plShardStatus::Shutdown()
+{
+ fRunning = false;
+ fUpdateEvent.Signal();
+}
+
+void plShardStatus::Update()
+{
+ double now = hsTimer::GetSysSeconds();
+ if ((now - fLastUpdate) >= kShardStatusUpdateTime)
+ fUpdateEvent.Signal();
+}
+
+// ===================================================
+
+plClientLauncher::plClientLauncher() :
+ fFlags(0),
+ fServerIni("server.ini"),
+ fPatcherFactory(nullptr),
+ fClientExecutable(plManifest::ClientExecutable()),
+ fStatusThread(new plShardStatus())
+{
+ pfPatcher::GetLog()->AddLine(plProduct::ProductString().c_str());
+}
+
+plClientLauncher::~plClientLauncher() { }
+
+// ===================================================
+
+plString plClientLauncher::GetAppArgs() const
+{
+ plStringStream ss;
+ ss << "-ServerIni=";
+ ss << fServerIni.AsString();
+ return ss.GetString();
+}
+
+void plClientLauncher::IOnPatchComplete(ENetError result, const plString& msg)
+{
+ if (IS_NET_SUCCESS(result)) {
+ // a couple of options
+ // 1. we self-patched and didn't update anything. patch the main client.
+ // 2. we self-patched and did things and stuff... re-run myself.
+ // 3. we patched the client... run it.
+ if (!hsCheckBits(fFlags, kHaveSelfPatched) && (fClientExecutable == plManifest::ClientExecutable())) {
+ // case 1
+ hsSetBits(fFlags, kHaveSelfPatched);
+ PatchClient();
+ } else
+ // cases 2 & 3
+ fLaunchClientFunc(fClientExecutable, GetAppArgs());
+ } else if (s_errorProc)
+ s_errorProc(result, msg);
+}
+
+void plClientLauncher::PatchClient()
+{
+ if (fStatusFunc)
+ fStatusFunc("Checking for updates...");
+ hsAssert(fPatcherFactory, "why is the patcher factory nil?");
+
+ pfPatcher* patcher = fPatcherFactory();
+ patcher->OnCompletion(std::bind(&plClientLauncher::IOnPatchComplete, this, std::placeholders::_1, std::placeholders::_2));
+ patcher->OnSelfPatch([&](const plFileName& file) { fClientExecutable = file; });
+
+ if (hsCheckBits(fFlags, kHaveSelfPatched))
+ patcher->RequestManifest(plManifest::ClientManifest());
+ else
+ patcher->RequestManifest(plManifest::PatcherManifest());
+ patcher->Start();
+}
+
+bool plClientLauncher::CompleteSelfPatch(std::function waitProc) const
+{
+ if (hsCheckBits(fFlags, kHaveSelfPatched))
+ return false;
+
+ plString myExe = plFileSystem::GetCurrentAppPath().GetFileName();
+ if (myExe.CompareI(plManifest::PatcherExecutable().AsString()) != 0) {
+ waitProc();
+
+ // so now we need to unlink the old patcher, and move ME into that fool's place...
+ // then we can continue on our merry way!
+ if (!plFileSystem::Unlink(plManifest::PatcherExecutable())) {
+ hsMessageBox("Failed to delete old patcher executable!", "Error", hsMessageBoxNormal, hsMessageBoxIconError);
+ return true;
+ }
+ if (!plFileSystem::Move(plFileSystem::GetCurrentAppPath(), plManifest::PatcherExecutable())) {
+ hsMessageBox("Failed to move patcher executable!", "Error", hsMessageBoxNormal, hsMessageBoxIconError);
+ return true;
+ }
+
+ // Now, execute the new patcher...
+ fLaunchClientFunc(plManifest::PatcherExecutable(), GetAppArgs() + " -NoSelfPatch");
+ return true;
+ }
+ return false;
+}
+
+// ===================================================
+
+static void IGotFileServIPs(ENetError result, void* param, const wchar_t* addr)
+{
+ plClientLauncher* launcher = static_cast(param);
+ NetCliGateKeeperDisconnect();
+
+ if (IS_NET_SUCCESS(result)) {
+ // bah... why do I even bother
+ plString eapSucks = plString::FromWchar(addr);
+ const char* eapReallySucks[] = { eapSucks.c_str() };
+ NetCliFileStartConnect(eapReallySucks, 1, true);
+
+ // Who knows if we will actually connect. So let's start updating.
+ launcher->PatchClient();
+ } else if (s_errorProc)
+ s_errorProc(result, "Failed to get FileServ addresses");
+}
+
+static void IEapSucksErrorProc(ENetProtocol protocol, ENetError error)
+{
+ if (s_errorProc) {
+ plString msg = plString::Format("Protocol: %S", NetProtocolToString(protocol));
+ s_errorProc(error, msg);
+ }
+}
+
+void plClientLauncher::InitializeNetCore()
+{
+ // initialize shard status
+ hsTimer::SetRealTime(true);
+ fStatusThread->Start();
+
+ // init eap...
+ AsyncCoreInitialize();
+
+ NetClientInitialize();
+ NetClientSetErrorHandler(IEapSucksErrorProc);
+ NetClientSetTransTimeoutMs(kNetTransTimeout);
+
+ // Gotta grab the filesrvs from the gate
+ const char** addrs;
+ uint32_t num = GetGateKeeperSrvHostnames(&addrs);
+
+ NetCliGateKeeperStartConnect(addrs, num);
+ NetCliGateKeeperFileSrvIpAddressRequest(IGotFileServIPs, this, true);
+}
+
+// ===================================================
+
+void plClientLauncher::PumpNetCore() const
+{
+ // this ain't net core, but it needs to be pumped :(
+ hsTimer::IncSysSeconds();
+
+ // pump eap
+ NetClientUpdate();
+
+ // pump shard status
+ fStatusThread->Update();
+
+ // don't nom all the CPU... kthx
+ hsSleep::Sleep(kNetCoreUpdateSleepTime);
+}
+
+void plClientLauncher::ShutdownNetCore() const
+{
+ // shutdown shard status
+ fStatusThread->Shutdown();
+
+ // unhook the neterr callback at this point because all transactions
+ // will fail when we call NetClientDestroy
+ s_errorProc = nullptr;
+
+ // shutdown eap
+ NetCliGateKeeperDisconnect();
+ NetCliFileDisconnect();
+ NetClientDestroy();
+
+ // shutdown eap (part deux)
+ AsyncCoreDestroy(kAsyncCoreShutdownTime);
+}
+
+// ===================================================
+
+bool plClientLauncher::LoadServerIni() const
+{
+ PF_CONSOLE_INITIALIZE(Core);
+
+ pfConsoleEngine console;
+ return console.ExecuteFile(fServerIni);
+}
+
+void plClientLauncher::ParseArguments()
+{
+ enum { kArgServerIni, kArgNoSelfPatch };
+ const CmdArgDef cmdLineArgs[] = {
+ { kCmdArgFlagged | kCmdTypeString, L"ServerIni", kArgServerIni },
+ { kCmdArgFlagged | kCmdTypeBool, L"NoSelfPatch", kArgNoSelfPatch },
+ };
+
+ CCmdParser cmdParser(cmdLineArgs, arrsize(cmdLineArgs));
+ cmdParser.Parse();
+
+ // cache 'em
+ if (cmdParser.GetBool(kArgNoSelfPatch))
+ hsSetBits(fFlags, kHaveSelfPatched);
+ if (cmdParser.IsSpecified(kArgServerIni))
+ fServerIni = plString::FromWchar(cmdParser.GetString(kArgServerIni));
+}
+
+void plClientLauncher::SetErrorProc(ErrorFunc proc)
+{
+ s_errorProc = proc;
+}
+
+void plClientLauncher::SetShardProc(StatusFunc proc)
+{
+ fStatusThread->fShardFunc = proc;
+}
diff --git a/Sources/Plasma/Apps/plUruLauncher/plClientLauncher.h b/Sources/Plasma/Apps/plUruLauncher/plClientLauncher.h
new file mode 100644
index 00000000..13f20a3f
--- /dev/null
+++ b/Sources/Plasma/Apps/plUruLauncher/plClientLauncher.h
@@ -0,0 +1,147 @@
+/*==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 _plClientLauncher_inc_
+#define _plClientLauncher_inc_
+
+#include "plFileSystem.h"
+#include "pnNetBase/pnNbError.h"
+
+#include
+#include
+
+class plClientLauncher
+{
+public:
+ typedef std::function CreatePatcherFunc;
+ typedef std::function ErrorFunc;
+ typedef std::function LaunchClientFunc;
+ typedef std::function StatusFunc;
+
+private:
+ enum Flags
+ {
+ kHaveSelfPatched = 1<<0,
+ };
+
+ uint32_t fFlags;
+ plFileName fServerIni;
+
+ plFileName fClientExecutable;
+ std::unique_ptr fStatusThread;
+
+ CreatePatcherFunc fPatcherFactory;
+ LaunchClientFunc fLaunchClientFunc;
+ StatusFunc fStatusFunc;
+
+ plString GetAppArgs() const;
+
+ void IOnPatchComplete(ENetError result, const plString& msg);
+
+public:
+ plClientLauncher();
+ ~plClientLauncher();
+
+ /** Begin the next logical patch operation. We are internally tracking if this is a self patch or a client patch.
+ * All you need to do is make certain the doggone callbacks are set so that your UI will update. In theory, you
+ * should never call this from your UI code since we manage this state for you.
+ */
+ void PatchClient();
+
+ /** Attempt to complete a self-patch left in progress by an older launcher. Specifically, we want to rename
+ * the launcher to something sane (UruLauncher.exe.tmp -> UruLauncher.exe). If we complete a self-patch in
+ * here, then we need to relaunch ourselves so that the game client will look like what the server expects.
+ * \returns True if a self-patch was completed. False if not.
+ */
+ bool CompleteSelfPatch(std::function waitProc) const;
+
+ /** Start eap's weird network subsystem and the shard status pinger.
+ * \remarks Please note that this will also enqueue the first patch.
+ */
+ void InitializeNetCore();
+
+ /** This pumps eap's network subsystem and runs any queued transaction completion callbacks.
+ * The thread that you call this from will be the thread that all your UI updates come from.
+ * So be certain that you've thought that through!
+ * \remarks This method will cause the thread to sleep so that we don't hog the CPU.
+ */
+ void PumpNetCore() const;
+
+ /** Shutdown eap's netcore and purge any other crap that needs to happen while the app is
+ * visible. In other words, tear down evil threaded crap.
+ */
+ void ShutdownNetCore() const;
+
+ /** Load the server configuration file. Note that you MUST parse the command
+ * arguments before calling this function!
+ */
+ bool LoadServerIni() const;
+
+ /** Parse the command line options. */
+ void ParseArguments();
+
+ /** Set a callback function that is called on a network error.
+ * \remarks This will be called from the network thread.
+ */
+ void SetErrorProc(ErrorFunc proc);
+
+ /** Set a patcher factory. */
+ void SetPatcherFactory(CreatePatcherFunc factory) { fPatcherFactory = factory; }
+
+ /** Set a callback that launches an arbitrary executable.
+ * \remarks This will be called from an arbitrary thread.
+ */
+ void SetLaunchClientProc(LaunchClientFunc proc) { fLaunchClientFunc = proc; }
+
+ /** Set a callback that displays the shard status.
+ * \remarks This will be called from a worker thread.
+ */
+ void SetShardProc(StatusFunc proc);
+
+ /** Set a callback that displays the patcher status.
+ * \remarks This will be called from the network thread. Note that any time
+ * this is called, you should consider it a state reset (so undo your progress bars).
+ */
+ void SetStatusProc(StatusFunc proc) { fStatusFunc = proc; }
+};
+
+#endif // _plClientLauncher_inc_
diff --git a/Sources/Plasma/Apps/plUruLauncher/plLauncherInfo.h b/Sources/Plasma/Apps/plUruLauncher/plLauncherInfo.h
deleted file mode 100644
index 5cc995bc..00000000
--- a/Sources/Plasma/Apps/plUruLauncher/plLauncherInfo.h
+++ /dev/null
@@ -1,102 +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/Apps/plUruLauncher/plLauncherCallback.h
-*
-***/
-
-#ifdef PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_PLLAUNCHERCALLBACK_H
-#error "Header $/Plasma20/Sources/Plasma/Apps/plUruLauncher/plLauncherCallback.h included more than once"
-#endif
-#define PLASMA20_SOURCES_PLASMA_APPS_PLURULAUNCHER_PLLAUNCHERCALLBACK_H
-
-enum EStatus {
- kStatusOk,
- kStatusError,
- kStatusPending,
-};
-
-struct PatchInfo {
- unsigned progress;
- unsigned stage;
- unsigned progressStage;
-};
-
-typedef void (*launcherCallback)(int status, void *param);
-typedef void (*setTextCallback)(const char text[]);
-typedef void (*setStatusTextCallback)(const char text[]);
-typedef void (*setTimeRemainingCallback)(unsigned seconds);
-typedef void (*setBytesRemainingCallback)(unsigned bytes);
-
-struct plLauncherInfo {
- wchar_t path[MAX_PATH];
- wchar_t cmdLine[512];
- unsigned buildId; // buildId override
- launcherCallback prepCallback;
- launcherCallback initCallback;
- launcherCallback startCallback;
- launcherCallback stopCallback;
- launcherCallback terminateCallback;
- launcherCallback progressCallback;
- launcherCallback exitCallback;
- setTextCallback SetText;
- setStatusTextCallback SetStatusText;
- setTimeRemainingCallback SetTimeRemaining;
- setBytesRemainingCallback SetBytesRemaining;
-
- PatchInfo patchInfo;
- DWORD returnCode; // used so we can pass a new process id back to gametap. That way gametap wont think uru has exited when the patcher quits.
-};
-
-
-/*****************************************************************************
-*
-* Main.cpp
-*
-***/
-
-void SetProgress (unsigned progress) ;
-void SetText (const char text[]);
-void SetStatusText (const char text[]);
-void SetTimeRemaining(unsigned seconds);
-void SetBytesRemaining(unsigned bytes);
\ No newline at end of file
diff --git a/Sources/Plasma/Apps/plUruLauncher/plUruLauncher.rc b/Sources/Plasma/Apps/plUruLauncher/plUruLauncher.rc
index e6261ee9..0a6e552a 100644
--- a/Sources/Plasma/Apps/plUruLauncher/plUruLauncher.rc
+++ b/Sources/Plasma/Apps/plUruLauncher/plUruLauncher.rc
@@ -4,7 +4,16 @@
#define WIN32_LEAN_AND_MEAN
#include
-#define IDC_STATIC (-1) // all static controls
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
@@ -32,6 +41,12 @@ BEGIN
"\0"
END
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
#endif // APSTUDIO_INVOKED
@@ -40,7 +55,7 @@ END
// Dialog
//
-IDD_DIALOG DIALOGEX 0, 0, 301, 180
+IDD_DIALOG DIALOGEX 0, 0, 301, 135
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS |
DS_CENTER | WS_POPUP | WS_VISIBLE | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
@@ -48,17 +63,16 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL 109,IDB_BITMAP,"Static",SS_BITMAP | SS_SUNKEN,7,7,288,36
CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER | 0x1,7,
- 162,234,11
- LTEXT "Static",IDC_TEXT,10,152,266,8
- PUSHBUTTON "Cancel",IDCANCEL,243,162,51,11
+ 111,234,11
+ CONTROL "", IDC_MARQUEE, "msctls_progress32", WS_BORDER | 0x8, 7,
+ 111, 234, 11
+ LTEXT "Static",IDC_TEXT,10,101,266,8
+ PUSHBUTTON "Cancel",IDCANCEL,243,111,51,11
LTEXT "Welcome to URU",IDC_STATUS_TEXT,19,57,266,17
GROUPBOX "",IDC_STATIC,7,46,287,49
- GROUPBOX "Status",IDC_STATIC,7,103,287,44
- LTEXT "Approx. Time Remaining:",IDC_STATIC,19,117,88,11
- LTEXT "Update Remaining:",IDC_STATIC,20,130,73,9
- LTEXT "...",IDC_TIMEREMAINING,111,117,165,12
- LTEXT "...",IDC_BYTESREMAINING,111,130,42,12
RTEXT "Product String",IDC_PRODUCTSTRING,19,85,272,8
+ LTEXT "6 MiB / 666 MiB",IDC_DLSIZE,11,124,110,8
+ LTEXT "128 KiB/s",IDC_DLSPEED,186,124,53,8,0,WS_EX_RIGHT
END
@@ -75,7 +89,7 @@ BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 294
TOPMARGIN, 7
- BOTTOMMARGIN, 173
+ BOTTOMMARGIN, 135
END
END
#endif // APSTUDIO_INVOKED
diff --git a/Sources/Plasma/Apps/plUruLauncher/resource.h b/Sources/Plasma/Apps/plUruLauncher/resource.h
index d54baf7a..612a5ffd 100644
--- a/Sources/Plasma/Apps/plUruLauncher/resource.h
+++ b/Sources/Plasma/Apps/plUruLauncher/resource.h
@@ -6,12 +6,15 @@
#define IDB_BITMAP 109
#define IDI_ICON1 111
#define IDC_PROGRESS 1003
+#define IDC_MARQUEE 1004
#define IDC_TEXT 1006
#define IDC_STATUS_TEXT 1009
#define IDC_TIMEREMAINING 1010
#define IDC_BYTESREMAINING 1011
#define IDC_PRODUCTSTRING 1012
-#define IDC_FILESREMAINING 1013
+#define IDC_DLSIZE 1014
+#define IDC_DLSPEED 1015
+#define IDC_STATIC -1
// Next default values for new objects
//
@@ -19,7 +22,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 112
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1014
+#define _APS_NEXT_CONTROL_VALUE 1016
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/Sources/Plasma/Apps/plUruLauncher/winmain.cpp b/Sources/Plasma/Apps/plUruLauncher/winmain.cpp
new file mode 100644
index 00000000..702018c6
--- /dev/null
+++ b/Sources/Plasma/Apps/plUruLauncher/winmain.cpp
@@ -0,0 +1,348 @@
+/*==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 "HeadSpin.h"
+#include "plFileSystem.h"
+#include "plProduct.h"
+
+#include "pfPatcher/plManifests.h"
+#include "pfPatcher/pfPatcher.h"
+
+#include "plClientLauncher.h"
+
+#include "hsWindows.h"
+#include "resource.h"
+#include
+#include
+
+// ===================================================
+
+#define PLASMA_PHAILURE 1
+#define PLASMA_OK 0
+
+static HWND s_dialog;
+static plClientLauncher s_launcher;
+static UINT s_taskbarCreated = RegisterWindowMessageW(L"TaskbarButtonCreated");
+static ITaskbarList3* s_taskbar = nullptr;
+
+// ===================================================
+
+/** Create a global patcher mutex that is backwards compatible with eap's */
+static HANDLE CreatePatcherMutex()
+{
+ return CreateMutexW(nullptr, FALSE, plManifest::PatcherExecutable().AsString().ToWchar());
+}
+
+static bool IsPatcherRunning()
+{
+ HANDLE mut = CreatePatcherMutex();
+ return WaitForSingleObject(mut, 0) != WAIT_OBJECT_0;
+}
+
+static void WaitForOldPatcher()
+{
+ HANDLE mut = CreatePatcherMutex();
+ WaitForSingleObject(mut, INFINITE);
+}
+
+// ===================================================
+
+static inline void IQuit(int exitCode=PLASMA_OK)
+{
+ // hey, guess what?
+ // PostQuitMessage doesn't work if you're not on the main thread...
+ PostMessageW(s_dialog, WM_QUIT, exitCode, 0);
+}
+
+static inline void IShowMarquee(bool marquee=true)
+{
+ // NOTE: This is a HACK to workaround a bug that causes progress bars that were ever
+ // marquees to reanimate when changing the range or position
+ ShowWindow(GetDlgItem(s_dialog, IDC_MARQUEE), marquee ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(s_dialog, IDC_PROGRESS), marquee ? SW_HIDE : SW_SHOW);
+ PostMessageW(GetDlgItem(s_dialog, IDC_MARQUEE), PBM_SETMARQUEE, static_cast(marquee), 0);
+}
+
+BOOL CALLBACK PatcherDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ // NT6 Taskbar Majick
+ if (uMsg == s_taskbarCreated) {
+ if (s_taskbar)
+ s_taskbar->Release();
+ HRESULT result = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, IID_ITaskbarList3, (void**)&s_taskbar);
+ if (FAILED(result))
+ s_taskbar = nullptr;
+ }
+
+ switch (uMsg) {
+ case WM_COMMAND:
+ // Did they press cancel?
+ if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL) {
+ EnableWindow(GetDlgItem(s_dialog, IDCANCEL), false);
+ SetWindowTextW(GetDlgItem(s_dialog, IDC_TEXT), L"Shutting Down...");
+ IQuit();
+ }
+ break;
+ case WM_DESTROY:
+ if (s_taskbar)
+ s_taskbar->Release();
+ PostQuitMessage(PLASMA_OK);
+ break;
+ case WM_NCHITTEST:
+ SetWindowLongW(hwndDlg, DWL_MSGRESULT, (LONG_PTR)HTCAPTION);
+ return TRUE;
+ case WM_QUIT:
+ s_launcher.ShutdownNetCore();
+ DestroyWindow(hwndDlg);
+ break;
+ default:
+ return DefWindowProcW(hwndDlg, uMsg, wParam, lParam);
+ }
+
+ return TRUE;
+}
+
+static void ShowPatcherDialog(HINSTANCE hInstance)
+{
+ s_dialog = ::CreateDialogW(hInstance, MAKEINTRESOURCEW(IDD_DIALOG), nullptr, PatcherDialogProc);
+ SetDlgItemTextW(s_dialog, IDC_TEXT, L"Connecting...");
+ SetDlgItemTextW(s_dialog, IDC_PRODUCTSTRING, plProduct::ProductString().ToWchar());
+ SetDlgItemTextW(s_dialog, IDC_DLSIZE, L"");
+ SetDlgItemTextW(s_dialog, IDC_DLSPEED, L"");
+ IShowMarquee();
+}
+
+static void PumpMessages()
+{
+ MSG msg;
+ do {
+ // Pump all Win32 messages
+ while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
+ if (!IsDialogMessageW(s_dialog, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ }
+
+ // Now we need to pump the netcore while we have some spare time...
+ s_launcher.PumpNetCore();
+ } while (msg.message != WM_QUIT);
+}
+
+// ===================================================
+
+static void IOnDownloadBegin(const plFileName& file)
+{
+ plString msg = plString::Format("Downloading... %s", file.AsString().c_str());
+ SetDlgItemTextW(s_dialog, IDC_TEXT, msg.ToWchar());
+}
+
+static void IOnProgressTick(uint64_t curBytes, uint64_t totalBytes, const plString& status)
+{
+ // Swap marquee/real progress
+ IShowMarquee(false);
+
+ // DL size
+ plString size = plString::Format("%s / %s", plFileSystem::ConvertFileSize(curBytes).c_str(),
+ plFileSystem::ConvertFileSize(totalBytes).c_str());
+ SetDlgItemTextW(s_dialog, IDC_DLSIZE, size.ToWchar());
+
+ // DL speed
+ SetDlgItemTextW(s_dialog, IDC_DLSPEED, status.ToWchar());
+ HWND progress = GetDlgItem(s_dialog, IDC_PROGRESS);
+
+ // hey look... ULONGLONG. that's exactly what we need >.<
+ if (s_taskbar)
+ s_taskbar->SetProgressValue(s_dialog, curBytes, totalBytes);
+
+ // Windows can only do signed 32-bit int progress bars.
+ // So, chop it into smaller chunks until we get something we can represent.
+ while (totalBytes > INT32_MAX) {
+ totalBytes /= 1024;
+ curBytes /= 1024;
+ }
+
+ PostMessageW(progress, PBM_SETRANGE32, 0, static_cast(totalBytes));
+ PostMessageW(progress, PBM_SETPOS, static_cast(curBytes), 0);
+}
+
+// ===================================================
+
+static void ILaunchClientExecutable(const plFileName& exe, const plString& args)
+{
+ // Once we start launching something, we no longer need to trumpet any taskbar status
+ if (s_taskbar)
+ s_taskbar->SetProgressState(s_dialog, TBPF_NOPROGRESS);
+
+ // Only launch a client executable if we're given one. If not, that's probably a cue that we're
+ // done with some service operation and need to go away.
+ if (!exe.AsString().IsEmpty()) {
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ memset(&si, 0, sizeof(si));
+ memset(&pi, 0, sizeof(pi));
+ si.cb = sizeof(si);
+
+ // This event will prevent the game from restarting the patcher
+ HANDLE hEvent = CreateEventW(nullptr, TRUE, FALSE, L"UruPatcherEvent");
+
+ // Fire up ye olde new process
+ plString cmd = plString::Format("%s %s", exe.AsString().c_str(), args.c_str());
+ CreateProcessW(
+ exe.AsString().ToWchar(),
+ const_cast(cmd.ToWchar().GetData()), // windows claims that it may modify this... let's hope that doesn't happen.
+ nullptr,
+ nullptr,
+ FALSE,
+ DETACHED_PROCESS,
+ nullptr,
+ plFileSystem::GetCWD().AsString().ToWchar(),
+ &si,
+ &pi
+ );
+
+ // if this is the real game client, then we need to make sure it gets this event...
+ if (plManifest::ClientExecutable().AsString().CompareI(exe.AsString()) == 0) {
+ WaitForInputIdle(pi.hProcess, 1000);
+ WaitForSingleObject(hEvent, INFINITE);
+ }
+
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ CloseHandle(hEvent);
+ }
+
+ // time to hara-kiri...
+ IQuit();
+}
+
+static void IOnNetError(ENetError result, const plString& msg)
+{
+ if (s_taskbar)
+ s_taskbar->SetProgressState(s_dialog, TBPF_ERROR);
+
+ plString text = plString::Format("Error: %S\r\n%s", NetErrorAsString(result), msg.c_str());
+ hsMessageBox(text.c_str(), "Error", hsMessageBoxNormal);
+ IQuit(PLASMA_PHAILURE);
+}
+
+static void ISetDownloadStatus(const plString& status)
+{
+ SetDlgItemTextW(s_dialog, IDC_TEXT, status.ToWchar());
+
+ // consider this a reset of the download status...
+ IShowMarquee();
+ SetDlgItemTextW(s_dialog, IDC_DLSIZE, L"");
+ SetDlgItemTextW(s_dialog, IDC_DLSPEED, L"");
+
+ if (s_taskbar)
+ s_taskbar->SetProgressState(s_dialog, TBPF_INDETERMINATE);
+}
+
+static void ISetShardStatus(const plString& status)
+{
+ SetDlgItemTextW(s_dialog, IDC_STATUS_TEXT, status.ToWchar());
+}
+
+static pfPatcher* IPatcherFactory()
+{
+ pfPatcher* patcher = new pfPatcher();
+ patcher->OnFileDownloadBegin(IOnDownloadBegin);
+ patcher->OnProgressTick(IOnProgressTick);
+
+ return patcher;
+}
+
+// ===================================================
+
+int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLink, int nCmdShow)
+{
+ // Let's initialize our plClientLauncher friend
+ s_launcher.ParseArguments();
+ s_launcher.SetErrorProc(IOnNetError);
+ s_launcher.SetLaunchClientProc(ILaunchClientExecutable);
+ s_launcher.SetPatcherFactory(IPatcherFactory);
+ s_launcher.SetShardProc(ISetShardStatus);
+ s_launcher.SetStatusProc(ISetDownloadStatus);
+
+ // If we're newly updated, then our filename will be something we don't expect!
+ // Let's go ahead and take care of that nao.
+ if (s_launcher.CompleteSelfPatch(WaitForOldPatcher))
+ return PLASMA_OK; // see you on the other side...
+
+ // Load the doggone server.ini
+ if (!s_launcher.LoadServerIni()) {
+ hsMessageBox("No server.ini file found. Please check your URU installation.", "Error", hsMessageBoxNormal);
+ return PLASMA_PHAILURE;
+ }
+
+ // Ensure there is only ever one patcher running...
+ if (IsPatcherRunning()) {
+ hsMessageBox(plString::Format("%s is already running", plProduct::LongName().c_str()).c_str(), "Error",
+ hsMessageBoxNormal, hsMessageBoxIconError);
+ return PLASMA_OK;
+ }
+ HANDLE _onePatcherMut = CreatePatcherMutex();
+
+ // Initialize the network core
+ s_launcher.InitializeNetCore();
+
+ // Welp, now that we know we're (basically) sane, let's create our client window
+ // and pump window messages until we're through.
+ ShowPatcherDialog(hInstance);
+ PumpMessages();
+
+ // Alrighty now we just need to clean up behind ourselves!
+ // NOTE: We shut down the netcore in the WM_QUIT handler so
+ // we don't have a windowless, zombie process if that takes
+ // awhile (it can... dang eap...)
+ ReleaseMutex(_onePatcherMut);
+ CloseHandle(_onePatcherMut);
+
+ // kthxbai
+ return PLASMA_OK;
+}
+
+/* Enable themes in Windows XP and later */
+#pragma comment(linker,"\"/manifestdependency:type='win32' \
+ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
+ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")