mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-14 02:27:40 -04:00
CWE Directory Reorganization
Rearrange directory structure of CWE to be loosely equivalent to the H'uru Plasma repository. Part 1: Movement of directories and files.
This commit is contained in:
BIN
Sources/Plasma/Apps/plUruLauncher/Dirt.ICO
Normal file
BIN
Sources/Plasma/Apps/plUruLauncher/Dirt.ICO
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
61
Sources/Plasma/Apps/plUruLauncher/Intern.h
Normal file
61
Sources/Plasma/Apps/plUruLauncher/Intern.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $/Plasma20/Sources/Plasma/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);
|
1136
Sources/Plasma/Apps/plUruLauncher/Main.cpp
Normal file
1136
Sources/Plasma/Apps/plUruLauncher/Main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
70
Sources/Plasma/Apps/plUruLauncher/Pch.h
Normal file
70
Sources/Plasma/Apps/plUruLauncher/Pch.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $/Plasma20/Sources/Plasma/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 <process.h>
|
||||
#include <time.h>
|
||||
#include "hsThread.h"
|
||||
#include "pnUtils/pnUtils.h"
|
||||
#include "pnNetBase/pnNetBase.h"
|
||||
#include "pnAsyncCore/pnAsyncCore.h"
|
||||
#include "pnProduct/pnProduct.h"
|
||||
#include "pnNetCli/pnNetCli.h"
|
||||
#include "plNetGameLib/plNetGameLib.h"
|
||||
#include "plEncryption/plChecksum.h"
|
||||
|
||||
#include "plCompression/plZlibStream.h"
|
||||
#include "../plClientPatcher/UruPlayer.h"
|
||||
|
||||
#include "plLauncherInfo.h"
|
||||
#include "Intern.h"
|
||||
#include "WinHttp.h"
|
||||
|
925
Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp
Normal file
925
Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp
Normal file
@ -0,0 +1,925 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $/Plasma20/Sources/Plasma/Apps/plUruLauncher/SelfPatcher.cpp
|
||||
*
|
||||
***/
|
||||
|
||||
#include "Pch.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#ifndef SEE_MASK_NOASYNC
|
||||
#define SEE_MASK_NOASYNC 0x00000100
|
||||
#endif
|
||||
|
||||
#define PATCHER_FLAG_INSTALLER 0x10
|
||||
|
||||
typedef bool(*FVerifyReturnCode)(DWORD);
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private Data
|
||||
*
|
||||
***/
|
||||
|
||||
#ifndef PLASMA_EXTERNAL_RELEASE
|
||||
static const wchar s_manifest[] = L"InternalPatcher";
|
||||
#else
|
||||
static const wchar s_manifest[] = L"ExternalPatcher";
|
||||
#endif
|
||||
|
||||
static const wchar s_depManifest[] = L"DependencyPatcher";
|
||||
|
||||
class SelfPatcherStream : public plZlibStream {
|
||||
public:
|
||||
SelfPatcherStream();
|
||||
virtual UInt32 Write(UInt32 byteCount, const void* buffer);
|
||||
static unsigned totalBytes;
|
||||
static unsigned progress;
|
||||
static DWORD startTime;
|
||||
};
|
||||
|
||||
unsigned SelfPatcherStream::totalBytes = 0;
|
||||
unsigned SelfPatcherStream::progress = 0;
|
||||
DWORD SelfPatcherStream::startTime = 0;
|
||||
|
||||
//============================================================================
|
||||
class plSelfPatcher : public hsThread
|
||||
{
|
||||
enum RequestType
|
||||
{
|
||||
kUndefined = -1,
|
||||
kQuit,
|
||||
|
||||
kRequestManifest,
|
||||
kHash,
|
||||
kDownload,
|
||||
kVerify,
|
||||
kInstall,
|
||||
};
|
||||
|
||||
enum RequestFlags
|
||||
{
|
||||
kRequestBlocked = (1<<0),
|
||||
kRequestOptionalManifest = (1<<1),
|
||||
kRequestNewPatcher = (1<<2),
|
||||
};
|
||||
|
||||
class PatcherWork
|
||||
{
|
||||
public:
|
||||
LINK(PatcherWork) link;
|
||||
|
||||
RequestType fType;
|
||||
UInt32 fFlags;
|
||||
union
|
||||
{
|
||||
NetCliFileManifestEntry fEntry;
|
||||
wchar fFileName[MAX_PATH];
|
||||
};
|
||||
|
||||
PatcherWork() : fType(kUndefined), fFlags(0) { }
|
||||
PatcherWork(RequestType type, const PatcherWork* cpy)
|
||||
: fType(type), fFlags(0)
|
||||
{
|
||||
memcpy(&fEntry, &cpy->fEntry, sizeof(fEntry));
|
||||
}
|
||||
};
|
||||
|
||||
LISTDECL(PatcherWork, link) fReqs;
|
||||
CEvent fQueueEvent;
|
||||
CCritSect fMutex;
|
||||
ENetError fResult;
|
||||
wchar fNewPatcherFileName[MAX_PATH];
|
||||
UInt32 fInstallerCount;
|
||||
UInt32 fInstallersExecuted;
|
||||
|
||||
// Any thread
|
||||
void IEnqueueFile(const NetCliFileManifestEntry& file);
|
||||
void IEnqueueWork(PatcherWork*& wk, bool priority=false);
|
||||
void IDequeueWork(PatcherWork*& wk);
|
||||
void IFatalError(const wchar* msg);
|
||||
void IReportServerBusy();
|
||||
|
||||
// This worker thread
|
||||
void ICheckAndRequest(PatcherWork*& wk);
|
||||
void IDownloadFile(PatcherWork*& wk);
|
||||
void IVerifyFile(PatcherWork*& wk);
|
||||
void IIssueManifestRequest(PatcherWork*& wk);
|
||||
|
||||
HANDLE ICreateProcess(const wchar* path, const wchar* args, bool forceShell=false) const;
|
||||
void IInstallDep(PatcherWork*& wk);
|
||||
bool IWaitProcess(HANDLE hProcess, FVerifyReturnCode verify);
|
||||
static bool IValidateExeReturnCode(DWORD returncode);
|
||||
static bool IValidateMsiReturnCode(DWORD returncode);
|
||||
|
||||
void IRun();
|
||||
void IQuit();
|
||||
|
||||
public:
|
||||
plSelfPatcher();
|
||||
|
||||
bool Active() const { return GetQuit() == 0; }
|
||||
const wchar* GetNewPatcherFileName() const { return fNewPatcherFileName; }
|
||||
ENetError GetResult() const { return fResult; }
|
||||
|
||||
void IssueManifestRequests();
|
||||
|
||||
void Start(); // override;
|
||||
hsError Run(); // override;
|
||||
void Stop(); // override;
|
||||
|
||||
public:
|
||||
plLauncherInfo* fLauncherInfo;
|
||||
|
||||
public:
|
||||
// NetCli callbacks
|
||||
static void NetErrorHandler(ENetProtocol protocol, ENetError error);
|
||||
static void OnFileSrvIP(ENetError result, void* param, const wchar addr[]);
|
||||
static void OnFileSrvManifest(ENetError result, void* param, const wchar group[], const NetCliFileManifestEntry manifest[], unsigned entryCount);
|
||||
static void OnFileSrvDownload(ENetError result, void* param, const wchar filename[], hsStream* writer);
|
||||
|
||||
} s_selfPatcher;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Private Functions
|
||||
*
|
||||
***/
|
||||
|
||||
//============================================================================
|
||||
static bool CheckMD5(const wchar* path, const wchar* hash)
|
||||
{
|
||||
plMD5Checksum localMD5;
|
||||
plMD5Checksum remoteMD5;
|
||||
|
||||
hsUNIXStream s;
|
||||
s.Open(path);
|
||||
localMD5.CalcFromStream(&s);
|
||||
s.Close();
|
||||
|
||||
// Some silly goose decided to send an md5 hash as UCS-2 instead of ASCII
|
||||
char ansi[33];
|
||||
StrToAnsi(ansi, hash, arrsize(ansi));
|
||||
remoteMD5.SetFromHexString(ansi);
|
||||
|
||||
return localMD5 == remoteMD5;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
static wchar* FormatSystemError()
|
||||
{
|
||||
wchar* error;
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPWSTR)& error,
|
||||
0,
|
||||
NULL);
|
||||
return error;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
static bool IsPatcherFile(const wchar* filename)
|
||||
{
|
||||
wchar progPath[MAX_PATH];
|
||||
PathGetProgramName(progPath, arrsize(progPath));
|
||||
wchar* progFilename = PathFindFilename(progPath);
|
||||
return StrCmpI(filename, progFilename) == 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
static bool SelfPatcherProc (bool * abort, plLauncherInfo *info) {
|
||||
|
||||
bool patched = false;
|
||||
|
||||
s_selfPatcher.fLauncherInfo = info;
|
||||
s_selfPatcher.Start();
|
||||
while(s_selfPatcher.Active() && !*abort) {
|
||||
NetClientUpdate();
|
||||
AsyncSleep(10);
|
||||
}
|
||||
s_selfPatcher.Stop();
|
||||
|
||||
if (s_selfPatcher.GetResult() == kNetPending)
|
||||
*abort = true;
|
||||
|
||||
if (!*abort && *s_selfPatcher.GetNewPatcherFileName() && IS_NET_SUCCESS(s_selfPatcher.GetResult())) {
|
||||
|
||||
// launch new patcher
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
ZERO(si);
|
||||
ZERO(pi);
|
||||
si.cb = sizeof(si);
|
||||
|
||||
wchar cmdline[MAX_PATH];
|
||||
StrPrintf(cmdline, arrsize(cmdline), L"%s %s", s_selfPatcher.GetNewPatcherFileName(), 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
|
||||
*
|
||||
***/
|
||||
|
||||
//============================================================================
|
||||
SelfPatcherStream::SelfPatcherStream()
|
||||
: plZlibStream()
|
||||
{
|
||||
if (startTime == 0)
|
||||
startTime = TimeGetSecondsSince2001Utc();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
UInt32 SelfPatcherStream::Write(UInt32 byteCount, const void* buffer) {
|
||||
progress += byteCount;
|
||||
float p = (float)progress / (float)totalBytes * 1000; // progress
|
||||
SetProgress( (int)p );
|
||||
|
||||
if (progress >= totalBytes) {
|
||||
SetBytesRemaining(0);
|
||||
SetTimeRemaining(0);
|
||||
} else {
|
||||
SetBytesRemaining(totalBytes - progress);
|
||||
DWORD bytesPerSec = (progress) / max(TimeGetSecondsSince2001Utc() - startTime, 1);
|
||||
SetTimeRemaining((totalBytes - progress) / max(bytesPerSec, 1));
|
||||
}
|
||||
|
||||
return plZlibStream::Write(byteCount, buffer);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* SelfPatcher Methods
|
||||
*
|
||||
***/
|
||||
|
||||
//============================================================================
|
||||
plSelfPatcher::plSelfPatcher()
|
||||
: fQueueEvent(kEventAutoReset), fResult(kNetPending), fLauncherInfo(nil),
|
||||
fInstallerCount(0), fInstallersExecuted(0)
|
||||
{
|
||||
memset(fNewPatcherFileName, 0, sizeof(fNewPatcherFileName));
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IEnqueueFile(const NetCliFileManifestEntry& file)
|
||||
{
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::IEnqueueFile: Enqueueing hash check of '%s'", file.downloadName);
|
||||
|
||||
PatcherWork* wk = NEW(PatcherWork);
|
||||
wk->fType = kHash;
|
||||
memcpy(&wk->fEntry, &file, sizeof(NetCliFileManifestEntry));
|
||||
|
||||
// Are we the patcher? If not, any other exe or msi should be installed.
|
||||
if (IsPatcherFile(wk->fEntry.clientName)) {
|
||||
wk->fFlags |= kRequestNewPatcher;
|
||||
} else {
|
||||
const wchar* extension = PathFindExtension(file.clientName);
|
||||
if (extension && (StrCmpI(extension, L".exe") == 0 || StrCmpI(extension, L".msi") == 0))
|
||||
wk->fEntry.flags |= PATCHER_FLAG_INSTALLER;
|
||||
}
|
||||
|
||||
IEnqueueWork(wk);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IEnqueueWork(PatcherWork*& wk, bool priority)
|
||||
{
|
||||
fMutex.Enter();
|
||||
wk->fFlags &= ~kRequestBlocked;
|
||||
fReqs.Link(wk, priority ? kListHead : kListTail);
|
||||
fMutex.Leave();
|
||||
fQueueEvent.Signal();
|
||||
|
||||
// WHY?! You ask?
|
||||
// If we don't, IRun() will reblock any reused requests. Also, from an ownership standpoint,
|
||||
// the worker queue now owns the work, not whoever enqueued it.
|
||||
wk = NULL;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IDequeueWork(PatcherWork*& wk)
|
||||
{
|
||||
ASSERT(wk->link.IsLinked());
|
||||
|
||||
fMutex.Enter();
|
||||
fReqs.Unlink(wk);
|
||||
fMutex.Leave();
|
||||
fQueueEvent.Signal();
|
||||
|
||||
DEL(wk);
|
||||
wk = NULL;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IFatalError(const wchar* msg)
|
||||
{
|
||||
#ifdef PLASMA_EXTERNAL_RELEASE
|
||||
MessageBoxW(NULL, msg, L"URU Launcher", MB_OK | MB_ICONERROR);
|
||||
IQuit();
|
||||
#else
|
||||
wchar finalmsg[1024];
|
||||
StrPrintf(finalmsg, arrsize(finalmsg), L"%s Continue?", msg);
|
||||
if (MessageBoxW(NULL, finalmsg, L"URU Launcher", MB_YESNO | MB_ICONERROR) == IDNO) {
|
||||
IQuit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IReportServerBusy()
|
||||
{
|
||||
MessageBoxA(NULL,
|
||||
"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/",
|
||||
"URU Launcher",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
fResult = kNetPending; // Don't show the unhandled error box.
|
||||
IQuit();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IssueManifestRequests()
|
||||
{
|
||||
{
|
||||
PatcherWork* wk = NEW(PatcherWork);
|
||||
wk->fType = kRequestManifest;
|
||||
StrCopy(wk->fFileName, s_manifest, arrsize(wk->fFileName));
|
||||
IEnqueueWork(wk);
|
||||
}
|
||||
|
||||
{
|
||||
PatcherWork* wk = NEW(PatcherWork);
|
||||
wk->fType = kRequestManifest;
|
||||
wk->fFlags |= kRequestOptionalManifest;
|
||||
StrCopy(wk->fFileName, s_depManifest, arrsize(wk->fFileName));
|
||||
IEnqueueWork(wk);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::ICheckAndRequest(PatcherWork*& wk)
|
||||
{
|
||||
// Patcher thread, can be as slow as molasses.
|
||||
if (PathDoesFileExist(wk->fEntry.clientName)) {
|
||||
if (CheckMD5(wk->fEntry.clientName, wk->fEntry.md5)) {
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::ICheckAndRequest: File '%s' appears to be up-to-date.", wk->fEntry.clientName);
|
||||
IDequeueWork(wk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::ICheckAndRequest: File '%s' needs to be downloaded.", wk->fEntry.clientName);
|
||||
SelfPatcherStream::totalBytes += (wk->fEntry.zipSize != 0) ? wk->fEntry.zipSize : wk->fEntry.fileSize;
|
||||
wk->fType = kDownload;
|
||||
IEnqueueWork(wk);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IDownloadFile(PatcherWork*& wk)
|
||||
{
|
||||
// The patcher downloads to a temporary file.
|
||||
if (wk->fFlags & kRequestNewPatcher) {
|
||||
PathGetProgramDirectory(fNewPatcherFileName, arrsize(fNewPatcherFileName));
|
||||
GetTempFileNameW(fNewPatcherFileName, kPatcherExeFilename, 0, fNewPatcherFileName);
|
||||
PathDeleteFile(fNewPatcherFileName);
|
||||
StrCopy(wk->fEntry.clientName, fNewPatcherFileName, arrsize(wk->fEntry.clientName));
|
||||
|
||||
SetText("Downloading new patcher...");
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::IDownloadFile: New patcher will be downloaded as '%s'", fNewPatcherFileName);
|
||||
} else {
|
||||
if (wk->fEntry.flags & PATCHER_FLAG_INSTALLER)
|
||||
SetText("Downloading update installer...");
|
||||
else
|
||||
SetText("Downloading update...");
|
||||
}
|
||||
|
||||
SelfPatcherStream* s = NEWZERO(SelfPatcherStream);
|
||||
if (!s->Open(wk->fEntry.clientName, L"wb")) {
|
||||
LogMsg(kLogError, L"plSelfPatcher::IDownloadFile: Failed to create file: %s, errno: %u", wk->fEntry.clientName, errno);
|
||||
IFatalError(L"Failed to create file.");
|
||||
} else {
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::IDownloadFile: Downloading file '%s'.", wk->fEntry.downloadName);
|
||||
NetCliFileDownloadRequest(wk->fEntry.downloadName, s, OnFileSrvDownload, wk);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IVerifyFile(PatcherWork*& wk)
|
||||
{
|
||||
if (!CheckMD5(wk->fEntry.clientName, wk->fEntry.md5)) {
|
||||
LogMsg(kLogError, L"plSelfPatcher::IVerifyFile: Hash mismatch on file '%s'. Expected: %s",
|
||||
wk->fEntry.clientName, wk->fEntry.md5);
|
||||
IFatalError(L"File download verification failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a redistributable dependency, it needs to be installed.
|
||||
if (wk->fEntry.flags & PATCHER_FLAG_INSTALLER) {
|
||||
LogMsg(kLogPerf, L"plSelfPatcher::IVerifyFile: Downloaded valid dependency installer '%s'", wk->fEntry.clientName);
|
||||
s_selfPatcher.fInstallerCount++;
|
||||
|
||||
wk->fType = kInstall;
|
||||
s_selfPatcher.IEnqueueWork(wk);
|
||||
} else {
|
||||
LogMsg(kLogPerf, L"plSelfPatcher::IVerifyFile: Downloaded valid standard file '%s'", wk->fEntry.clientName);
|
||||
s_selfPatcher.IDequeueWork(wk);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IIssueManifestRequest(PatcherWork*& wk)
|
||||
{
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::IIssueManifestRequest: Issuing manifest request '%s'.", wk->fFileName);
|
||||
NetCliFileManifestRequest(OnFileSrvManifest, wk, wk->fFileName);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
HANDLE plSelfPatcher::ICreateProcess(const wchar* path, const wchar* args, bool forceShell) const
|
||||
{
|
||||
// Generally speaking, we would *like* to use CreateProcessW. Unfortunately, we cannot do that
|
||||
// becuase on Windows Vista and above (read: what the world SHOULD be using...) CreateProcessW
|
||||
// will not handle UAC split tokens and can fail with ERROR_ELEVATION_REQUIRED. For bonus fun,
|
||||
// that error isn't even defined in the Platform SDK we're using here. The "official" solution
|
||||
// is to use ShellExecuteEx with the verb "runas" so there you go. (See also: "runas.exe")
|
||||
// Bonus chatter: on Windows XP, there is no "runas" feature because there are no split tokens
|
||||
// or UAC. Also, Windows XP does not have the SEE_MASK_NOASYNC flag (it does have the DDEWAIT flag
|
||||
// whose value is the same but functions slightly differently), which causes any dialogs
|
||||
// launched by Windows (such as errors) to deadlock the UI quite horribly. Further,
|
||||
// ShellExecuteExW pops up that weird "do you want to run this file you downloaded from the internet?"
|
||||
// box, which we can't actually interact with due to the above.
|
||||
if (!forceShell) {
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&si, 0, sizeof(si));
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
si.cb = sizeof(si);
|
||||
|
||||
wchar cmdline[MAX_PATH];
|
||||
StrPrintf(cmdline, arrsize(cmdline), L"\"%s\" %s", path, args);
|
||||
BOOL result = CreateProcessW(path,
|
||||
cmdline,
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE,
|
||||
DETACHED_PROCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
&si,
|
||||
&pi);
|
||||
CloseHandle(pi.hThread);
|
||||
if (result != FALSE) {
|
||||
return pi.hProcess;
|
||||
} else {
|
||||
wchar* error = FormatSystemError();
|
||||
LogMsg(kLogError, L"plSelfPatcher::ICreateProcess: CreateProcessW failed for '%s': %u %s",
|
||||
path, GetLastError(), error);
|
||||
LocalFree(error);
|
||||
// Purposefully falling through to ShellExecuteExW
|
||||
}
|
||||
}
|
||||
|
||||
SHELLEXECUTEINFOW info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.cbSize = sizeof(info);
|
||||
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI;
|
||||
info.hwnd = fLauncherInfo->dialog;
|
||||
// Not explicitly setting lpVerb to L"runas" because this seemingly breaks msiexec.
|
||||
info.lpFile = path;
|
||||
info.lpParameters = args;
|
||||
|
||||
if (ShellExecuteExW(&info) == FALSE) {
|
||||
wchar* error = FormatSystemError();
|
||||
LogMsg(kLogError, L"plSelfPatcher::ICreateProcess: ShellExecuteExW failed for '%s': %u %s",
|
||||
path, GetLastError(), error);
|
||||
LocalFree(error);
|
||||
}
|
||||
return info.hProcess;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IInstallDep(PatcherWork*& wk)
|
||||
{
|
||||
// Due to our dependence on Visual Studio .NET 2003, we cannot use the indeterminate/marquee
|
||||
// progress bar from there. So, we'll have to dome some skullduggery to guesstimate a really
|
||||
// crummy progress meter.
|
||||
fInstallersExecuted++;
|
||||
float progress = (float)fInstallersExecuted / ((float)fInstallerCount + 1.f) * 1000.f;
|
||||
SetProgress((unsigned)progress);
|
||||
|
||||
// Best I can do for indeterminant progress.
|
||||
SetTimeRemaining(-1);
|
||||
SetBytesRemaining(-1);
|
||||
|
||||
// We are about to do something that MAY cause a UAC dialog to appear.
|
||||
// So, let's at least pretend to be a good citizen and write something in the UI about that...
|
||||
SetText("Installing updates...");
|
||||
AsyncSleep(100);
|
||||
|
||||
wchar process[MAX_PATH];
|
||||
PathGetCurrentDirectory(process, arrsize(process));
|
||||
PathAddFilename(process, process, wk->fFileName, arrsize(process));
|
||||
wchar* extension = PathFindExtension(wk->fFileName);
|
||||
wchar args[MAX_PATH];
|
||||
args[0] = 0;
|
||||
|
||||
bool forceShell = false;
|
||||
FVerifyReturnCode validateptr = NULL;
|
||||
|
||||
// Apply arguments to the process to ensure it doesn't do weird stuff like start a big UI
|
||||
// Creative OpenAL (oalinst.exe) uses '/s' for silent.
|
||||
// The small DirectX 9.0c web installer (dxwebsetup.exe) uses "/q" and pops up an error on invalid args.
|
||||
// The full monty DirectX 9.0c isntaller (dxsetup.exe) uses "/silent" and pops up an error on invalid args.
|
||||
// The Visual C++ redist (vcredist_x86.exe and vcredist_x64.exe) may optionally restart the
|
||||
// computer WITHOUT prompting when in quiet mode.
|
||||
if (extension && StrCmpI(extension, L".exe") == 0) {
|
||||
wchar* filename = PathFindFilename(wk->fFileName);
|
||||
if (StrCmpI(filename, L"oalinst.exe") == 0)
|
||||
StrPack(args, L"/s", arrsize(args));
|
||||
else if (StrCmpI(filename, L"dxsetup.exe") == 0)
|
||||
StrPack(args, L"/silent", arrsize(args));
|
||||
else
|
||||
StrPack(args, L"/q", arrsize(args));
|
||||
|
||||
if (StrStrI(filename, L"vcredist") || StrStrI(filename, L"vc_redist"))
|
||||
StrPack(args, L" /norestart", arrsize(args));
|
||||
validateptr = IValidateExeReturnCode;
|
||||
} else if (extension && StrCmpI(extension, L".msi") == 0) {
|
||||
StrPrintf(args, arrsize(args), L"/i \"%s\" /qr /norestart", process);
|
||||
StrCopy(process, L"msiexec", arrsize(process));
|
||||
validateptr = IValidateMsiReturnCode;
|
||||
forceShell = true;
|
||||
} else {
|
||||
LogMsg(kLogError, L"plSelfPatcher::IInstallDep: Invalid extension '%s' for installer '%s'",
|
||||
extension ? extension : L"(NULL)", wk->fFileName);
|
||||
IDequeueWork(wk);
|
||||
return;
|
||||
}
|
||||
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::IInstallDep: Installing '%s %s'.", process, args);
|
||||
HANDLE hProcess = ICreateProcess(process, args, forceShell);
|
||||
if (hProcess) {
|
||||
if (IWaitProcess(hProcess, validateptr)) {
|
||||
IDequeueWork(wk);
|
||||
} else {
|
||||
PathDeleteFile(wk->fFileName);
|
||||
IFatalError(L"Failed to install update.");
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
} else {
|
||||
IFatalError(L"Failed to run installer.");
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
bool plSelfPatcher::IWaitProcess(HANDLE hProcess, FVerifyReturnCode verify)
|
||||
{
|
||||
// Since we have taken over the worker thread, we need to listen for any very very important
|
||||
// requests added to the queue. The only one we care about is quit, the rest can just go to
|
||||
// HEY HEY! and we're safe to just swallow the notifies. We delete our own request to resume
|
||||
// the main proc.
|
||||
enum { kWaitQueue, kWaitProcess };
|
||||
HANDLE waitH[] = { fQueueEvent.Handle(), hProcess };
|
||||
do {
|
||||
DWORD waitStatus = WaitForMultipleObjects(arrsize(waitH), waitH, FALSE, INFINITE);
|
||||
ASSERT(waitStatus != WAIT_FAILED);
|
||||
|
||||
if (waitStatus >= WAIT_OBJECT_0 && waitStatus <= (WAIT_OBJECT_0 + arrsize(waitH))) {
|
||||
DWORD idx = waitStatus - WAIT_OBJECT_0;
|
||||
if (idx == kWaitQueue) {
|
||||
fMutex.Enter();
|
||||
PatcherWork* quitWk = fReqs.Head();
|
||||
fMutex.Leave();
|
||||
if (quitWk->fType == kQuit) {
|
||||
LogMsg(kLogPerf, "plSelfPatcher::IWaitProcess: Got shutdown during wait, attempting to terminate process.");
|
||||
TerminateProcess(hProcess, 1);
|
||||
return false;
|
||||
}
|
||||
} else if (idx == kWaitProcess) {
|
||||
if (verify) {
|
||||
DWORD returncode = 0;
|
||||
GetExitCodeProcess(hProcess, &returncode);
|
||||
return verify(returncode);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
FATAL("Invalid wait index");
|
||||
return false;
|
||||
}
|
||||
} else if (waitStatus == WAIT_FAILED) {
|
||||
wchar* error = FormatSystemError();
|
||||
LogMsg(kLogError, L"plSelfPatcher::IWaitProcess: WaitForMultipleObjects failed! %s", error);
|
||||
LocalFree(error);
|
||||
IFatalError(L"Internal Error.");
|
||||
return false;
|
||||
} else {
|
||||
LogMsg(kLogError, "plSelfPatcher::IWaitProcess: Unhandled WaitForMultipleObjects result 0x%x", waitStatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncSleep(10);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
bool plSelfPatcher::IValidateExeReturnCode(DWORD returncode)
|
||||
{
|
||||
if (returncode != 1) {
|
||||
LogMsg(kLogDebug, "plSelfPatcher::IValidateExeReturnCode: Process finished successfully! Returncode: %u", returncode);
|
||||
return true;
|
||||
} else {
|
||||
LogMsg(kLogError, "plSelfPatcher::IValidateExeReturnCode: Process failed! Returncode: %u", returncode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
bool plSelfPatcher::IValidateMsiReturnCode(DWORD returncode)
|
||||
{
|
||||
switch (returncode) {
|
||||
case ERROR_SUCCESS:
|
||||
case ERROR_PRODUCT_VERSION:
|
||||
case ERROR_SUCCESS_REBOOT_INITIATED:
|
||||
case ERROR_SUCCESS_REBOOT_REQUIRED:
|
||||
LogMsg(kLogDebug, "plSelfPatcher::IValidateMsiReturnCode: Process finished successfully!");
|
||||
return true;
|
||||
default:
|
||||
LogMsg(kLogError, "plSelfPatcher::IValidateMsiReturnCode: Process failed! Returncode: %u", returncode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
hsError plSelfPatcher::Run()
|
||||
{
|
||||
do {
|
||||
fQueueEvent.Wait(-1);
|
||||
IRun();
|
||||
} while (Active());
|
||||
return hsOK;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IRun()
|
||||
{
|
||||
do {
|
||||
fMutex.Enter();
|
||||
PatcherWork* wk = fReqs.Head();
|
||||
fMutex.Leave();
|
||||
|
||||
if (!wk) {
|
||||
LogMsg(kLogDebug, "plSelfPatcher::IRun: No work in queue, exiting.");
|
||||
if (!IS_NET_ERROR(fResult))
|
||||
fResult = kNetSuccess;
|
||||
SetQuit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wk->fFlags & kRequestBlocked)
|
||||
return;
|
||||
|
||||
switch (wk->fType) {
|
||||
case kQuit:
|
||||
LogMsg(kLogDebug, "plSelfPatcher::IRun: Explicit quit request.");
|
||||
// An explicit quit should manage its own result code.
|
||||
SetQuit(1);
|
||||
return;
|
||||
|
||||
case kRequestManifest:
|
||||
IIssueManifestRequest(wk);
|
||||
break;
|
||||
case kHash:
|
||||
ICheckAndRequest(wk);
|
||||
break;
|
||||
case kDownload:
|
||||
IDownloadFile(wk);
|
||||
break;
|
||||
case kInstall:
|
||||
IInstallDep(wk);
|
||||
break;
|
||||
case kVerify:
|
||||
IVerifyFile(wk);
|
||||
break;
|
||||
|
||||
DEFAULT_FATAL(wk.fType);
|
||||
}
|
||||
|
||||
if (wk) {
|
||||
// this "blocks" the worker thread on a dependent task like a file download that is
|
||||
// completing asyncrhonously, do not remove this request... The block is removed
|
||||
// by some callback calling IDequeueWork() or, worse case, DEL(wk).
|
||||
LogMsg(kLogDebug, L"plSelfPatcher::IRun: Worker thread is now blocked on '%s'.", wk->fFileName);
|
||||
wk->fFlags |= kRequestBlocked;
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::IQuit()
|
||||
{
|
||||
PatcherWork* wk = NEW(PatcherWork);
|
||||
wk->fType = kQuit;
|
||||
IEnqueueWork(wk, true);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::Start()
|
||||
{
|
||||
NetClientInitialize();
|
||||
NetClientSetErrorHandler(NetErrorHandler);
|
||||
|
||||
const wchar** addrs;
|
||||
unsigned count;
|
||||
count = GetGateKeeperSrvHostnames(&addrs);
|
||||
NetCliGateKeeperStartConnect(addrs, count);
|
||||
|
||||
// request a file server ip address
|
||||
NetCliGateKeeperFileSrvIpAddressRequest(OnFileSrvIP, NULL, true);
|
||||
|
||||
hsThread::Start();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::Stop()
|
||||
{
|
||||
// Post a quit message and wait for the thread to stop.
|
||||
if (Active())
|
||||
IQuit();
|
||||
hsThread::Stop();
|
||||
|
||||
NetCliFileDisconnect();
|
||||
NetClientUpdate();
|
||||
|
||||
// Shutdown the client/server networking subsystem
|
||||
NetClientDestroy();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::NetErrorHandler(ENetProtocol protocol, ENetError error)
|
||||
{
|
||||
REF(protocol);
|
||||
|
||||
LogMsg(kLogError, L"plSelfPatcher::NetErrorHandler: %s", NetErrorToString(error));
|
||||
if (IS_NET_SUCCESS(s_selfPatcher.fResult))
|
||||
s_selfPatcher.fResult = error;
|
||||
if (error == kNetErrServerBusy)
|
||||
s_selfPatcher.IReportServerBusy();
|
||||
else
|
||||
s_selfPatcher.IQuit();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::OnFileSrvIP(ENetError error, void* param, const wchar addr[])
|
||||
{
|
||||
NetCliGateKeeperDisconnect();
|
||||
if (IS_NET_ERROR(error)) {
|
||||
LogMsg(kLogError, L"plSelfPatcher::OnFileSrvIP: %s", NetErrorToString(error));
|
||||
s_selfPatcher.fResult = error;
|
||||
s_selfPatcher.IQuit();
|
||||
return;
|
||||
}
|
||||
|
||||
NetCliFileStartConnect(&addr, 1, true);
|
||||
s_selfPatcher.IssueManifestRequests();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::OnFileSrvManifest(ENetError result, void* param, const wchar group[],
|
||||
const NetCliFileManifestEntry manifest[], unsigned entryCount)
|
||||
{
|
||||
PatcherWork* wk = (PatcherWork*)param;
|
||||
|
||||
switch (result) {
|
||||
case kNetErrTimeout:
|
||||
NetCliFileManifestRequest(OnFileSrvManifest, param, group);
|
||||
return;
|
||||
case kNetErrServerBusy:
|
||||
s_selfPatcher.IReportServerBusy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_NET_ERROR(result) && !(wk->fFlags & kRequestOptionalManifest)) {
|
||||
s_selfPatcher.fResult = result;
|
||||
s_selfPatcher.IQuit();
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < entryCount; ++i)
|
||||
s_selfPatcher.IEnqueueFile(manifest[i]);
|
||||
s_selfPatcher.IDequeueWork(wk);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void plSelfPatcher::OnFileSrvDownload(ENetError result, void* param,
|
||||
const wchar filename[], hsStream* writer)
|
||||
{
|
||||
switch (result) {
|
||||
case kNetErrTimeout:
|
||||
writer->Rewind();
|
||||
NetCliFileDownloadRequest(filename, writer, OnFileSrvDownload, param);
|
||||
return;
|
||||
case kNetErrServerBusy:
|
||||
s_selfPatcher.IReportServerBusy();
|
||||
writer->Close();
|
||||
DEL(writer);
|
||||
return;
|
||||
}
|
||||
|
||||
writer->Close();
|
||||
DEL(writer);
|
||||
|
||||
if (IS_NET_ERROR(result)) {
|
||||
LogMsg(kLogError, L"plSelfPatcher::OnFileSrvDownload: Error downloading '%s': %s", filename, NetErrorToString(result));
|
||||
s_selfPatcher.fResult = result;
|
||||
s_selfPatcher.IQuit();
|
||||
} else {
|
||||
PatcherWork* wk = (PatcherWork*)param;
|
||||
wk->fType = kVerify;
|
||||
s_selfPatcher.IEnqueueWork(wk);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* 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_selfPatcher.GetResult();
|
||||
return patched;
|
||||
}
|
||||
|
BIN
Sources/Plasma/Apps/plUruLauncher/banner.bmp
Normal file
BIN
Sources/Plasma/Apps/plUruLauncher/banner.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
104
Sources/Plasma/Apps/plUruLauncher/plLauncherInfo.h
Normal file
104
Sources/Plasma/Apps/plUruLauncher/plLauncherInfo.h
Normal file
@ -0,0 +1,104 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
/*****************************************************************************
|
||||
*
|
||||
* $/Plasma20/Sources/Plasma/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 path[MAX_PATH];
|
||||
wchar 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;
|
||||
bool IsTGCider;
|
||||
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.
|
||||
HWND dialog;
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Main.cpp
|
||||
*
|
||||
***/
|
||||
|
||||
void SetProgress (unsigned progress) ;
|
||||
void SetText (const char text[]);
|
||||
void SetStatusText (const char text[]);
|
||||
void SetTimeRemaining(unsigned seconds);
|
||||
void SetBytesRemaining(unsigned bytes);
|
125
Sources/Plasma/Apps/plUruLauncher/plUruLauncher.rc
Normal file
125
Sources/Plasma/Apps/plUruLauncher/plUruLauncher.rc
Normal file
@ -0,0 +1,125 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_DIALOG DIALOGEX 0, 0, 301, 180
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS |
|
||||
DS_CENTER | WS_POPUP | WS_VISIBLE | WS_SYSMENU
|
||||
EXSTYLE WS_EX_APPWINDOW
|
||||
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
|
||||
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
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_DIALOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 294
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 173
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bitmap
|
||||
//
|
||||
|
||||
IDB_BITMAP BITMAP "banner.bmp"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON "Dirt.ICO"
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
25
Sources/Plasma/Apps/plUruLauncher/resource.h
Normal file
25
Sources/Plasma/Apps/plUruLauncher/resource.h
Normal file
@ -0,0 +1,25 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by plUruLauncher.rc
|
||||
//
|
||||
#define IDD_DIALOG 106
|
||||
#define IDB_BITMAP 109
|
||||
#define IDI_ICON1 111
|
||||
#define IDC_PROGRESS 1003
|
||||
#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
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#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_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
Reference in New Issue
Block a user