2
3
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:
rarified
2021-05-15 12:49:46 -06:00
parent c3f4a640a3
commit 96903e8dca
4002 changed files with 159 additions and 644 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

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

File diff suppressed because it is too large Load Diff

View 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"

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

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

View 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

View 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