mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-17 10:52:46 +00:00
Move plClient init to a thread
This means that most users should see the game window pop up immediately after pressing login instead of seeing "Starting URU... Please wait"
This commit is contained in:
@ -39,17 +39,15 @@ endif(PYTHONINTERP_FOUND)
|
|||||||
set(plClient_HEADERS
|
set(plClient_HEADERS
|
||||||
plClient.h
|
plClient.h
|
||||||
plClientCreatable.h
|
plClientCreatable.h
|
||||||
#plClientKey.h
|
plClientLoader.h
|
||||||
plClientUpdateFormat.h
|
plClientUpdateFormat.h
|
||||||
#plPluginClient.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(plClient_SOURCES
|
set(plClient_SOURCES
|
||||||
pfAllCreatables.cpp
|
pfAllCreatables.cpp
|
||||||
plAllCreatables.cpp
|
plAllCreatables.cpp
|
||||||
plClient.cpp
|
plClient.cpp
|
||||||
#plClientKey.cpp
|
plClientLoader.cpp
|
||||||
#plPluginClient.cpp
|
|
||||||
pnAllCreatables.cpp
|
pnAllCreatables.cpp
|
||||||
winmain.cpp
|
winmain.cpp
|
||||||
)
|
)
|
||||||
|
@ -799,14 +799,6 @@ bool plClient::MsgReceive(plMessage* msg)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
// plNetCommAuthMsg
|
|
||||||
//============================================================================
|
|
||||||
if (plNetCommAuthMsg * authCommMsg = plNetCommAuthMsg::ConvertNoRef(msg)) {
|
|
||||||
IHandleNetCommAuthMsg(authCommMsg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// plResPatcherMsg
|
// plResPatcherMsg
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@ -1379,10 +1371,6 @@ bool plClient::StartInit()
|
|||||||
// local data of course).
|
// local data of course).
|
||||||
((plResManager *)hsgResMgr::ResMgr())->VerifyPages();
|
((plResManager *)hsgResMgr::ResMgr())->VerifyPages();
|
||||||
|
|
||||||
// the dx8 audio system MUST be initialized
|
|
||||||
// before the database is loaded
|
|
||||||
SetForegroundWindow(fWindowHndl);
|
|
||||||
|
|
||||||
plgAudioSys::Init();
|
plgAudioSys::Init();
|
||||||
gAudio = plgAudioSys::Sys();
|
gAudio = plgAudioSys::Sys();
|
||||||
|
|
||||||
@ -1439,7 +1427,6 @@ bool plClient::StartInit()
|
|||||||
//
|
//
|
||||||
// Init Net before loading things
|
// Init Net before loading things
|
||||||
//
|
//
|
||||||
plgDispatch::Dispatch()->RegisterForExactType(plNetCommAuthMsg::Index(), GetKey());
|
|
||||||
plNetClientMgr::GetInstance()->Init();
|
plNetClientMgr::GetInstance()->Init();
|
||||||
plAgeLoader::GetInstance()->Init();
|
plAgeLoader::GetInstance()->Init();
|
||||||
|
|
||||||
@ -1460,8 +1447,6 @@ bool plClient::StartInit()
|
|||||||
plMouseDevice::Instance()->SetDisplayResolution((float)fPipeline->Width(), (float)fPipeline->Height());
|
plMouseDevice::Instance()->SetDisplayResolution((float)fPipeline->Width(), (float)fPipeline->Height());
|
||||||
plInputManager::SetRecenterMouse(false);
|
plInputManager::SetRecenterMouse(false);
|
||||||
|
|
||||||
IPlayIntroMovie("avi/CyanWorlds.webm", 0.f, 0.f, 0.f, 1.f, 1.f, 0.75);
|
|
||||||
if(GetDone()) return false;
|
|
||||||
plgDispatch::Dispatch()->RegisterForExactType(plMovieMsg::Index(), GetKey());
|
plgDispatch::Dispatch()->RegisterForExactType(plMovieMsg::Index(), GetKey());
|
||||||
|
|
||||||
// create the listener for the audio system:
|
// create the listener for the audio system:
|
||||||
@ -1472,22 +1457,15 @@ bool plClient::StartInit()
|
|||||||
plgDispatch::Dispatch()->RegisterForExactType(plAudioSysMsg::Index(), pLMod->GetKey());
|
plgDispatch::Dispatch()->RegisterForExactType(plAudioSysMsg::Index(), pLMod->GetKey());
|
||||||
|
|
||||||
plSynchedObject::PushSynchDisabled(false); // enable dirty tracking
|
plSynchedObject::PushSynchDisabled(false); // enable dirty tracking
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (NetCommGetStartupAge()->ageDatasetName.CompareI("StartUp") == 0)
|
//============================================================================
|
||||||
{
|
bool plClient::BeginGame()
|
||||||
plNetCommAuthMsg * msg = new plNetCommAuthMsg();
|
{
|
||||||
msg->result = kNetSuccess;
|
IPlayIntroMovie("avi/CyanWorlds.webm", 0.f, 0.f, 0.f, 1.f, 1.f, 0.75);
|
||||||
msg->param = nil;
|
if (GetDone()) return false;
|
||||||
msg->Send();
|
IPatchGlobalAgeFiles();
|
||||||
}
|
|
||||||
|
|
||||||
// 2nd half of plClient initialization occurs after
|
|
||||||
// all network events have completed. Async events:
|
|
||||||
//
|
|
||||||
// 1) Download secure files
|
|
||||||
//
|
|
||||||
// Continue plClient init via IOnAsyncInitComplete().
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2290,27 +2268,3 @@ void plClient::IHandlePatcherMsg (plResPatcherMsg * msg) {
|
|||||||
|
|
||||||
IOnAsyncInitComplete();
|
IOnAsyncInitComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void plClient::IHandleNetCommAuthMsg (plNetCommAuthMsg * msg) {
|
|
||||||
|
|
||||||
plgDispatch::Dispatch()->UnRegisterForExactType(plNetCommAuthMsg::Index(), GetKey());
|
|
||||||
|
|
||||||
if (IS_NET_ERROR(msg->result)) {
|
|
||||||
char str[1024];
|
|
||||||
StrPrintf(
|
|
||||||
str,
|
|
||||||
arrsize(str),
|
|
||||||
// fmt
|
|
||||||
"Authentication failed: NetError %u, %S.\n"
|
|
||||||
,// values
|
|
||||||
msg->result,
|
|
||||||
NetErrorToString(msg->result)
|
|
||||||
);
|
|
||||||
plNetClientApp::GetInstance()->QueueDisableNet(true, str);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patch them global files!
|
|
||||||
IPatchGlobalAgeFiles();
|
|
||||||
}
|
|
||||||
|
@ -177,7 +177,6 @@ protected:
|
|||||||
void ICompleteInit ();
|
void ICompleteInit ();
|
||||||
void IOnAsyncInitComplete ();
|
void IOnAsyncInitComplete ();
|
||||||
void IHandlePatcherMsg (plResPatcherMsg * msg);
|
void IHandlePatcherMsg (plResPatcherMsg * msg);
|
||||||
void IHandleNetCommAuthMsg (plNetCommAuthMsg * msg);
|
|
||||||
bool IHandleAgeLoaded2Msg (plAgeLoaded2Msg * msg);
|
bool IHandleAgeLoaded2Msg (plAgeLoaded2Msg * msg);
|
||||||
|
|
||||||
bool IFlushRenderRequests();
|
bool IFlushRenderRequests();
|
||||||
@ -286,6 +285,8 @@ public:
|
|||||||
virtual void WindowActivate(bool active);
|
virtual void WindowActivate(bool active);
|
||||||
virtual bool WindowActive() const { return fWindowActive; }
|
virtual bool WindowActive() const { return fWindowActive; }
|
||||||
|
|
||||||
|
bool BeginGame();
|
||||||
|
|
||||||
void FlashWindow();
|
void FlashWindow();
|
||||||
void SetMessagePumpProc( plMessagePumpProc proc ) { fMessagePumpProc = proc; }
|
void SetMessagePumpProc( plMessagePumpProc proc ) { fMessagePumpProc = proc; }
|
||||||
void ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Windowed, int NumAASamples, int MaxAnisotropicSamples, bool VSync = false);
|
void ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Windowed, int NumAASamples, int MaxAnisotropicSamples, bool VSync = false);
|
||||||
|
145
Sources/Plasma/Apps/plClient/plClientLoader.cpp
Normal file
145
Sources/Plasma/Apps/plClient/plClientLoader.cpp
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||||||
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7
|
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or
|
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||||
|
(or a modified version of those libraries),
|
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||||
|
licensors of this Program grant you additional
|
||||||
|
permission to convey the resulting work. Corresponding Source for a
|
||||||
|
non-source form of such a combination shall include the source code for
|
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||||
|
work.
|
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||||
|
or by snail mail at:
|
||||||
|
Cyan Worlds, Inc.
|
||||||
|
14617 N Newport Hwy
|
||||||
|
Mead, WA 99021
|
||||||
|
|
||||||
|
*==LICENSE==*/
|
||||||
|
|
||||||
|
#include "plClientLoader.h"
|
||||||
|
#include "plClient.h"
|
||||||
|
#include "plFileSystem.h"
|
||||||
|
#include "plPipeline.h"
|
||||||
|
|
||||||
|
#include "hsWindows.h"
|
||||||
|
#include <shellapi.h>
|
||||||
|
|
||||||
|
#include "plClientResMgr/plClientResMgr.h"
|
||||||
|
#include "plNetClient/plNetClientMgr.h"
|
||||||
|
#include "plPhysX/plSimulationMgr.h"
|
||||||
|
#include "plResMgr/plResManager.h"
|
||||||
|
|
||||||
|
static plFileName s_physXSetupExe = "PhysX_Setup.exe";
|
||||||
|
|
||||||
|
static bool InitPhysX()
|
||||||
|
{
|
||||||
|
#ifdef HS_BUILD_FOR_WIN32
|
||||||
|
plSimulationMgr::Init();
|
||||||
|
if (!plSimulationMgr::GetInstance()) {
|
||||||
|
if (plFileInfo(s_physXSetupExe).Exists()) {
|
||||||
|
// launch the PhysX installer
|
||||||
|
SHELLEXECUTEINFOW info;
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.cbSize = sizeof(info);
|
||||||
|
info.lpFile = s_physXSetupExe.AsString().ToWchar();
|
||||||
|
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC;
|
||||||
|
ShellExecuteExW(&info);
|
||||||
|
|
||||||
|
// wait for completion
|
||||||
|
WaitForSingleObject(info.hProcess, INFINITE);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
CloseHandle(info.hProcess);
|
||||||
|
} else {
|
||||||
|
hsMessageBox("You must install PhysX before you can play URU.", "Error", hsMessageBoxNormal, hsMessageBoxIconError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (plSimulationMgr::GetInstance()) {
|
||||||
|
plSimulationMgr::GetInstance()->Suspend();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
hsMessageBox("PhysX install failed. You will not be able to play URU.", "Error", hsMessageBoxNormal, hsMessageBoxIconError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif // HS_BUILD_FOR_WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
hsError plClientLoader::Run()
|
||||||
|
{
|
||||||
|
plResManager *resMgr = new plResManager;
|
||||||
|
resMgr->SetDataPath("dat");
|
||||||
|
hsgResMgr::Init(resMgr);
|
||||||
|
|
||||||
|
if (!plFileInfo("resource.dat").Exists()) {
|
||||||
|
hsMessageBox("Required file 'resource.dat' not found.", "Error", hsMessageBoxNormal);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
plClientResMgr::Instance().ILoadResources("resource.dat");
|
||||||
|
|
||||||
|
fClient = new plClient;
|
||||||
|
fClient->SetWindowHandle(fWindow);
|
||||||
|
if (!InitPhysX() || fClient->InitPipeline() || !fClient->StartInit()) {
|
||||||
|
fClient->SetDone(true);
|
||||||
|
return hsFail;
|
||||||
|
}
|
||||||
|
return hsOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plClientLoader::Start()
|
||||||
|
{
|
||||||
|
fClient->ResizeDisplayDevice(fClient->GetPipeline()->Width(), fClient->GetPipeline()->Height(), !fClient->GetPipeline()->IsFullScreen());
|
||||||
|
|
||||||
|
// Show the client window
|
||||||
|
ShowWindow(fWindow, SW_SHOW);
|
||||||
|
BringWindowToTop(fWindow);
|
||||||
|
|
||||||
|
// Now, show the intro video, patch the global ages, etc...
|
||||||
|
fClient->BeginGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================
|
||||||
|
void plClientLoader::ShutdownStart()
|
||||||
|
{
|
||||||
|
// Ensure that the client actually inited
|
||||||
|
hsThread::Stop();
|
||||||
|
|
||||||
|
// Now request the sane exit
|
||||||
|
fClient->SetDone(true);
|
||||||
|
if (plNetClientMgr* mgr = plNetClientMgr::GetInstance())
|
||||||
|
mgr->QueueDisableNet(false, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void plClientLoader::ShutdownEnd()
|
||||||
|
{
|
||||||
|
if (fClient)
|
||||||
|
fClient->Shutdown();
|
||||||
|
hsAssert(hsgResMgr::ResMgr()->RefCnt() == 1, "resMgr has too many refs, expect mem leaks");
|
||||||
|
hsgResMgr::Shutdown();
|
||||||
|
}
|
110
Sources/Plasma/Apps/plClient/plClientLoader.h
Normal file
110
Sources/Plasma/Apps/plClient/plClientLoader.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*==LICENSE==*
|
||||||
|
|
||||||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||||||
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Additional permissions under GNU GPL version 3 section 7
|
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or
|
||||||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||||
|
(or a modified version of those libraries),
|
||||||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||||
|
licensors of this Program grant you additional
|
||||||
|
permission to convey the resulting work. Corresponding Source for a
|
||||||
|
non-source form of such a combination shall include the source code for
|
||||||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||||
|
work.
|
||||||
|
|
||||||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||||
|
or by snail mail at:
|
||||||
|
Cyan Worlds, Inc.
|
||||||
|
14617 N Newport Hwy
|
||||||
|
Mead, WA 99021
|
||||||
|
|
||||||
|
*==LICENSE==*/
|
||||||
|
|
||||||
|
#include "HeadSpin.h"
|
||||||
|
#include "hsThread.h"
|
||||||
|
#include "hsWindows.h"
|
||||||
|
|
||||||
|
class plClientLoader : private hsThread
|
||||||
|
{
|
||||||
|
class plClient* fClient;
|
||||||
|
HWND fWindow;
|
||||||
|
|
||||||
|
virtual void OnQuit()
|
||||||
|
{
|
||||||
|
SetQuit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Does the heavy lifting of client init */
|
||||||
|
virtual hsError Run();
|
||||||
|
|
||||||
|
public:
|
||||||
|
plClientLoader() : fClient(nullptr) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the client asyncrhonouslynn including: loading the localization,
|
||||||
|
* registry, dispatcher, etc.
|
||||||
|
*/
|
||||||
|
void Init()
|
||||||
|
{
|
||||||
|
hsAssert(fClient == nullptr, "trying to init the client more than once?");
|
||||||
|
hsThread::Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not the client init is done
|
||||||
|
*/
|
||||||
|
bool IsInited() const { return hsThread::GetQuit(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the client HWND
|
||||||
|
*/
|
||||||
|
void SetClientWindow(HWND hWnd) { fWindow = hWnd; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial shutdown request received from Windows (or something)... start tear down
|
||||||
|
*/
|
||||||
|
void ShutdownStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window mess cleaned up, time to commit hara-kiri
|
||||||
|
*/
|
||||||
|
void ShutdownEnd();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launches the client window and starts the game.
|
||||||
|
* This will block if the client is not initialized.
|
||||||
|
*/
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the client to finish initing
|
||||||
|
*/
|
||||||
|
void Wait() { hsThread::Stop(); }
|
||||||
|
|
||||||
|
/** Returns the current plClient instance */
|
||||||
|
plClient* operator ->() const { return fClient; }
|
||||||
|
|
||||||
|
/** Returns whether or not the client is non-null */
|
||||||
|
operator bool() const { return fClient != nullptr; }
|
||||||
|
};
|
||||||
|
|
@ -52,7 +52,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|||||||
#include "hsStream.h"
|
#include "hsStream.h"
|
||||||
#include "plCmdParser.h"
|
#include "plCmdParser.h"
|
||||||
#include "plClient.h"
|
#include "plClient.h"
|
||||||
#include "plClientResMgr/plClientResMgr.h"
|
#include "plClientLoader.h"
|
||||||
#include "pfCrashHandler/plCrashCli.h"
|
#include "pfCrashHandler/plCrashCli.h"
|
||||||
#include "plNetClient/plNetClientMgr.h"
|
#include "plNetClient/plNetClientMgr.h"
|
||||||
#include "plInputCore/plInputDevice.h"
|
#include "plInputCore/plInputDevice.h"
|
||||||
@ -66,7 +66,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|||||||
#include "plStatusLog/plStatusLog.h"
|
#include "plStatusLog/plStatusLog.h"
|
||||||
#include "plProduct.h"
|
#include "plProduct.h"
|
||||||
#include "plNetGameLib/plNetGameLib.h"
|
#include "plNetGameLib/plNetGameLib.h"
|
||||||
#include "plPhysX/plSimulationMgr.h"
|
|
||||||
|
|
||||||
#include "res/resource.h"
|
#include "res/resource.h"
|
||||||
|
|
||||||
@ -114,7 +113,7 @@ int gWinBorderDX = GetSystemMetrics( SM_CXSIZEFRAME );
|
|||||||
int gWinBorderDY = GetSystemMetrics( SM_CYSIZEFRAME );
|
int gWinBorderDY = GetSystemMetrics( SM_CYSIZEFRAME );
|
||||||
int gWinMenuDY = GetSystemMetrics( SM_CYCAPTION );
|
int gWinMenuDY = GetSystemMetrics( SM_CYCAPTION );
|
||||||
|
|
||||||
plClient *gClient;
|
plClientLoader gClient;
|
||||||
bool gPendingActivate = false;
|
bool gPendingActivate = false;
|
||||||
bool gPendingActivateFlag = false;
|
bool gPendingActivateFlag = false;
|
||||||
|
|
||||||
@ -143,11 +142,6 @@ static wchar_t s_patcherExeName[] = L"UruLauncher.exe";
|
|||||||
|
|
||||||
#endif // PLASMA_EXTERNAL_RELEASE
|
#endif // PLASMA_EXTERNAL_RELEASE
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
// PhysX installer
|
|
||||||
//============================================================================
|
|
||||||
static wchar_t s_physXSetupExeName[] = L"PhysX_Setup.exe";
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// LoginDialogParam
|
// LoginDialogParam
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@ -355,15 +349,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
gClient->SetDone(TRUE);
|
gClient.ShutdownStart();
|
||||||
if (plNetClientMgr * mgr = plNetClientMgr::GetInstance())
|
|
||||||
mgr->QueueDisableNet(false, nil);
|
|
||||||
DestroyWindow(gClient->GetWindowHandle());
|
DestroyWindow(gClient->GetWindowHandle());
|
||||||
break;
|
break;
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
gClient->SetDone(TRUE);
|
gClient.ShutdownStart();
|
||||||
if (plNetClientMgr * mgr = plNetClientMgr::GetInstance())
|
|
||||||
mgr->QueueDisableNet(false, nil);
|
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -456,156 +446,6 @@ void DeInitNetClientComm()
|
|||||||
NetCommShutdown();
|
NetCommShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK WaitingForPhysXDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
||||||
{
|
|
||||||
switch( uMsg )
|
|
||||||
{
|
|
||||||
case WM_INITDIALOG:
|
|
||||||
::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Waiting for PhysX install...");
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InitPhysX()
|
|
||||||
{
|
|
||||||
bool physXInstalled = false;
|
|
||||||
while (!physXInstalled)
|
|
||||||
{
|
|
||||||
plSimulationMgr::Init();
|
|
||||||
if (!plSimulationMgr::GetInstance())
|
|
||||||
{
|
|
||||||
int ret = hsMessageBox("PhysX is not installed, or an older version is installed.\nInstall new version? (Game will exit if you click \"No\")",
|
|
||||||
"Missing PhysX", hsMessageBoxYesNo);
|
|
||||||
if (ret == hsMBoxNo) // exit if no
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// launch the PhysX installer
|
|
||||||
SHELLEXECUTEINFOW info;
|
|
||||||
memset(&info, 0, sizeof(info));
|
|
||||||
info.cbSize = sizeof(info);
|
|
||||||
info.lpFile = s_physXSetupExeName;
|
|
||||||
info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC;
|
|
||||||
ShellExecuteExW(&info);
|
|
||||||
|
|
||||||
// let the user know what's going on
|
|
||||||
HWND waitingDialog = ::CreateDialog(gHInst, MAKEINTRESOURCE(IDD_LOADING), NULL, WaitingForPhysXDialogProc);
|
|
||||||
|
|
||||||
// run a loop to wait for it to quit, pumping the windows message queue intermittently
|
|
||||||
DWORD waitRet = WaitForSingleObject(info.hProcess, 100);
|
|
||||||
MSG msg;
|
|
||||||
while (waitRet == WAIT_TIMEOUT)
|
|
||||||
{
|
|
||||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
||||||
{
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
waitRet = WaitForSingleObject(info.hProcess, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanup
|
|
||||||
CloseHandle(info.hProcess);
|
|
||||||
::DestroyWindow(waitingDialog);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
plSimulationMgr::GetInstance()->Suspend();
|
|
||||||
physXInstalled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InitClient( HWND hWnd )
|
|
||||||
{
|
|
||||||
plResManager *resMgr = new plResManager;
|
|
||||||
resMgr->SetDataPath("dat");
|
|
||||||
hsgResMgr::Init(resMgr);
|
|
||||||
|
|
||||||
if (!plFileInfo("resource.dat").Exists())
|
|
||||||
{
|
|
||||||
hsMessageBox("Required file 'resource.dat' not found.", "Error", hsMessageBoxNormal);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
plClientResMgr::Instance().ILoadResources("resource.dat");
|
|
||||||
|
|
||||||
gClient = new plClient;
|
|
||||||
if( gClient == nil )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!InitPhysX())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
gClient->SetWindowHandle( hWnd );
|
|
||||||
|
|
||||||
if( gClient->InitPipeline() )
|
|
||||||
gClient->SetDone(true);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gClient->ResizeDisplayDevice(gClient->GetPipeline()->Width(), gClient->GetPipeline()->Height(), !gClient->GetPipeline()->IsFullScreen());
|
|
||||||
}
|
|
||||||
|
|
||||||
if( gPendingActivate )
|
|
||||||
{
|
|
||||||
// We need this because the window gets a WM_ACTIVATE before we get to this function, so
|
|
||||||
// the above flag lets us know that we need to fake a late activate msg to the client
|
|
||||||
gClient->WindowActivate( gPendingActivateFlag );
|
|
||||||
}
|
|
||||||
|
|
||||||
gClient->SetMessagePumpProc( PumpMessageQueueProc );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes all that windows junk, creates class then shows main window
|
|
||||||
BOOL WinInit(HINSTANCE hInst, int nCmdShow)
|
|
||||||
{
|
|
||||||
// Fill out WNDCLASS info
|
|
||||||
WNDCLASS wndClass;
|
|
||||||
wndClass.style = CS_DBLCLKS; // CS_HREDRAW | CS_VREDRAW;
|
|
||||||
wndClass.lpfnWndProc = WndProc;
|
|
||||||
wndClass.cbClsExtra = 0;
|
|
||||||
wndClass.cbWndExtra = 0;
|
|
||||||
wndClass.hInstance = hInst;
|
|
||||||
wndClass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_DIRT));
|
|
||||||
|
|
||||||
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
||||||
wndClass.hbrBackground = (struct HBRUSH__*) (GetStockObject(BLACK_BRUSH));
|
|
||||||
wndClass.lpszMenuName = CLASSNAME;
|
|
||||||
wndClass.lpszClassName = CLASSNAME;
|
|
||||||
|
|
||||||
// can only run one at a time anyway, so just quit if another is running
|
|
||||||
if (!RegisterClass(&wndClass))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
// Create a window
|
|
||||||
HWND hWnd = CreateWindow(
|
|
||||||
CLASSNAME, plProduct::LongName().c_str(),
|
|
||||||
WS_OVERLAPPEDWINDOW,
|
|
||||||
0, 0,
|
|
||||||
800 + gWinBorderDX * 2,
|
|
||||||
600 + gWinBorderDY * 2 + gWinMenuDY,
|
|
||||||
NULL, NULL, hInst, NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
if( !InitClient( hWnd ) )
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
// Return false if window creation failed
|
|
||||||
if (!gClient->GetWindowHandle())
|
|
||||||
{
|
|
||||||
OutputDebugString("Create window failed\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OutputDebugString("Create window OK\n");
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// For error logging
|
// For error logging
|
||||||
//
|
//
|
||||||
@ -1065,34 +905,34 @@ BOOL CALLBACK UruLoginDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK SplashDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
BOOL CALLBACK SplashDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch( uMsg )
|
switch (uMsg)
|
||||||
{
|
{
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
switch (plLocalization::GetLanguage())
|
switch (plLocalization::GetLanguage())
|
||||||
{
|
{
|
||||||
case plLocalization::kFrench:
|
case plLocalization::kFrench:
|
||||||
::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "D<EFBFBD>marrage d'URU. Veuillez patienter...");
|
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "D<EFBFBD>marrage d'URU. Veuillez patienter...");
|
||||||
break;
|
break;
|
||||||
case plLocalization::kGerman:
|
case plLocalization::kGerman:
|
||||||
::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Starte URU, bitte warten ...");
|
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Starte URU, bitte warten ...");
|
||||||
break;
|
break;
|
||||||
case plLocalization::kSpanish:
|
case plLocalization::kSpanish:
|
||||||
::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Iniciando URU, por favor espera...");
|
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Iniciando URU, por favor espera...");
|
||||||
break;
|
break;
|
||||||
case plLocalization::kItalian:
|
case plLocalization::kItalian:
|
||||||
::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Avvio di URU, attendere...");
|
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Avvio di URU, attendere...");
|
||||||
break;
|
break;
|
||||||
// default is English
|
// default is English
|
||||||
case plLocalization::kJapanese:
|
case plLocalization::kJapanese:
|
||||||
::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "...");
|
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "...");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Starting URU. Please wait...");
|
::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Starting URU. Please wait...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1118,7 +958,7 @@ LONG WINAPI plCustomUnhandledExceptionFilter( struct _EXCEPTION_POINTERS *Except
|
|||||||
|
|
||||||
// Now, try to create a nice exception dialog after plCrashHandler is done.
|
// Now, try to create a nice exception dialog after plCrashHandler is done.
|
||||||
s_crash.WaitForHandle();
|
s_crash.WaitForHandle();
|
||||||
HWND parentHwnd = (gClient == nil) ? GetActiveWindow() : gClient->GetWindowHandle();
|
HWND parentHwnd = gClient ? gClient->GetWindowHandle() : GetActiveWindow();
|
||||||
DialogBoxParam(gHInst, MAKEINTRESOURCE(IDD_EXCEPTION), parentHwnd, ExceptionDialogProc, NULL);
|
DialogBoxParam(gHInst, MAKEINTRESOURCE(IDD_EXCEPTION), parentHwnd, ExceptionDialogProc, NULL);
|
||||||
|
|
||||||
// Trickle up the handlers
|
// Trickle up the handlers
|
||||||
@ -1129,6 +969,40 @@ LONG WINAPI plCustomUnhandledExceptionFilter( struct _EXCEPTION_POINTERS *Except
|
|||||||
#include "pfConsoleCore/pfConsoleEngine.h"
|
#include "pfConsoleCore/pfConsoleEngine.h"
|
||||||
PF_CONSOLE_LINK_ALL()
|
PF_CONSOLE_LINK_ALL()
|
||||||
|
|
||||||
|
bool WinInit(HINSTANCE hInst)
|
||||||
|
{
|
||||||
|
// Fill out WNDCLASS info
|
||||||
|
WNDCLASS wndClass;
|
||||||
|
wndClass.style = CS_DBLCLKS; // CS_HREDRAW | CS_VREDRAW;
|
||||||
|
wndClass.lpfnWndProc = WndProc;
|
||||||
|
wndClass.cbClsExtra = 0;
|
||||||
|
wndClass.cbWndExtra = 0;
|
||||||
|
wndClass.hInstance = hInst;
|
||||||
|
wndClass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON_DIRT));
|
||||||
|
|
||||||
|
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
wndClass.hbrBackground = (struct HBRUSH__*) (GetStockObject(BLACK_BRUSH));
|
||||||
|
wndClass.lpszMenuName = CLASSNAME;
|
||||||
|
wndClass.lpszClassName = CLASSNAME;
|
||||||
|
|
||||||
|
// can only run one at a time anyway, so just quit if another is running
|
||||||
|
if (!RegisterClass(&wndClass))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Create a window
|
||||||
|
HWND hWnd = CreateWindow(
|
||||||
|
CLASSNAME, plProduct::LongName().c_str(),
|
||||||
|
WS_OVERLAPPEDWINDOW,
|
||||||
|
0, 0,
|
||||||
|
800 + gWinBorderDX * 2,
|
||||||
|
600 + gWinBorderDY * 2 + gWinMenuDY,
|
||||||
|
NULL, NULL, hInst, NULL
|
||||||
|
);
|
||||||
|
gClient.SetClientWindow(hWnd);
|
||||||
|
gClient.Init();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#include "plResMgr/plVersion.h"
|
#include "plResMgr/plVersion.h"
|
||||||
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
|
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
@ -1241,6 +1115,10 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Set up to log errors by using hsDebugMessage
|
||||||
|
DebugInit();
|
||||||
|
DebugMsgF("Plasma 2.0.%i.%i - %s", PLASMA2_MAJOR_VERSION, PLASMA2_MINOR_VERSION, plProduct::ProductString().c_str());
|
||||||
|
|
||||||
FILE *serverIniFile = plFileSystem::Open(serverIni, "rb");
|
FILE *serverIniFile = plFileSystem::Open(serverIni, "rb");
|
||||||
if (serverIniFile)
|
if (serverIniFile)
|
||||||
{
|
{
|
||||||
@ -1254,6 +1132,12 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||||||
return PARABLE_NORMAL_EXIT;
|
return PARABLE_NORMAL_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin initializing the client in the background
|
||||||
|
if (!WinInit(hInst)) {
|
||||||
|
hsMessageBox("Failed to initialize plClient", "Error", hsMessageBoxNormal);
|
||||||
|
return PARABLE_NORMAL_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
NetCliAuthAutoReconnectEnable(false);
|
NetCliAuthAutoReconnectEnable(false);
|
||||||
InitNetClientComm();
|
InitNetClientComm();
|
||||||
|
|
||||||
@ -1299,96 +1183,49 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
|
|
||||||
if (needExit) {
|
if (needExit) {
|
||||||
|
gClient.ShutdownStart();
|
||||||
|
gClient.ShutdownEnd();
|
||||||
DeInitNetClientComm();
|
DeInitNetClientComm();
|
||||||
return PARABLE_NORMAL_EXIT;
|
return PARABLE_NORMAL_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetCliAuthAutoReconnectEnable(true);
|
NetCliAuthAutoReconnectEnable(true);
|
||||||
|
|
||||||
// VERY VERY FIRST--throw up our splash screen
|
|
||||||
HWND splashDialog = ::CreateDialog( hInst, MAKEINTRESOURCE( IDD_LOADING ), NULL, SplashDialogProc );
|
|
||||||
|
|
||||||
// Install our unhandled exception filter for trapping all those nasty crashes in release build
|
// Install our unhandled exception filter for trapping all those nasty crashes in release build
|
||||||
#ifndef HS_DEBUGGING
|
#ifndef HS_DEBUGGING
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
||||||
oldFilter = SetUnhandledExceptionFilter( plCustomUnhandledExceptionFilter );
|
oldFilter = SetUnhandledExceptionFilter( plCustomUnhandledExceptionFilter );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
// We should quite frankly be done initing the client by now. But, if not, spawn the good old
|
||||||
// Set up to log errors by using hsDebugMessage
|
// "Starting URU, please wait..." dialog (not so yay)
|
||||||
//
|
if (!gClient.IsInited()) {
|
||||||
DebugInit();
|
HWND splashDialog = ::CreateDialog(hInst, MAKEINTRESOURCE(IDD_LOADING), NULL, SplashDialogProc);
|
||||||
DebugMsgF("Plasma 2.0.%i.%i - %s", PLASMA2_MAJOR_VERSION, PLASMA2_MINOR_VERSION, plProduct::ProductString().c_str());
|
gClient.Wait();
|
||||||
|
::DestroyWindow(splashDialog);
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
// Main loop
|
||||||
// Create Window
|
if (gClient && !gClient->GetDone()) {
|
||||||
if (!WinInit(hInst, nCmdShow) || gClient->GetDone())
|
gClient->SetMessagePumpProc(PumpMessageQueueProc);
|
||||||
break;
|
gClient.Start();
|
||||||
|
|
||||||
// Done with our splash now
|
|
||||||
::DestroyWindow( splashDialog );
|
|
||||||
|
|
||||||
if (!gClient)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Show the main window
|
|
||||||
ShowWindow(gClient->GetWindowHandle(), SW_SHOW);
|
|
||||||
|
|
||||||
// Be really REALLY forceful about being in the front
|
|
||||||
BringWindowToTop( gClient->GetWindowHandle() );
|
|
||||||
|
|
||||||
// Update the window
|
|
||||||
UpdateWindow(gClient->GetWindowHandle());
|
|
||||||
|
|
||||||
//
|
|
||||||
// Init Application here
|
|
||||||
//
|
|
||||||
if( !gClient->StartInit() )
|
|
||||||
break;
|
|
||||||
|
|
||||||
// I want it on top! I mean it!
|
|
||||||
BringWindowToTop( gClient->GetWindowHandle() );
|
|
||||||
|
|
||||||
// initialize dinput here:
|
|
||||||
if (gClient && gClient->GetInputManager())
|
|
||||||
gClient->GetInputManager()->InitDInput(hInst, (HWND)gClient->GetWindowHandle());
|
|
||||||
|
|
||||||
// Seriously!
|
|
||||||
BringWindowToTop( gClient->GetWindowHandle() );
|
|
||||||
|
|
||||||
//
|
|
||||||
// Main loop
|
|
||||||
//
|
|
||||||
MSG msg;
|
MSG msg;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
gClient->MainLoop();
|
gClient->MainLoop();
|
||||||
|
if (gClient->GetDone())
|
||||||
if( gClient->GetDone() )
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Look for a message
|
// Look for a message
|
||||||
while (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
{
|
|
||||||
// Handle the message
|
// Handle the message
|
||||||
TranslateMessage( &msg );
|
TranslateMessage(&msg);
|
||||||
DispatchMessage( &msg );
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
} while (WM_QUIT != msg.message);
|
} while (WM_QUIT != msg.message);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
gClient.ShutdownEnd();
|
||||||
// Cleanup
|
|
||||||
//
|
|
||||||
if (gClient)
|
|
||||||
{
|
|
||||||
gClient->Shutdown(); // shuts down PhysX for us
|
|
||||||
gClient = nil;
|
|
||||||
}
|
|
||||||
hsAssert(hsgResMgr::ResMgr()->RefCnt()==1, "resMgr has too many refs, expect mem leaks");
|
|
||||||
hsgResMgr::Shutdown(); // deletes fResMgr
|
|
||||||
DeInitNetClientComm();
|
DeInitNetClientComm();
|
||||||
|
|
||||||
// Uninstall our unhandled exception filter, if we installed one
|
// Uninstall our unhandled exception filter, if we installed one
|
||||||
|
@ -67,8 +67,8 @@ static unsigned int __stdcall gEntryPointBT(void* param)
|
|||||||
|
|
||||||
WinThreadParam* wtp = (WinThreadParam*)param;
|
WinThreadParam* wtp = (WinThreadParam*)param;
|
||||||
unsigned int result = wtp->fThread->Run();
|
unsigned int result = wtp->fThread->Run();
|
||||||
::ReleaseSemaphore(wtp->fQuitSemaH, 1, nil); // signal that we've quit
|
|
||||||
wtp->fThread->OnQuit();
|
wtp->fThread->OnQuit();
|
||||||
|
::ReleaseSemaphore(wtp->fQuitSemaH, 1, nil); // signal that we've quit
|
||||||
delete wtp;
|
delete wtp;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user