From 4d5c10f77528a840818511b33bc0fdfdb667de75 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Fri, 31 Jul 2015 14:28:06 -0400 Subject: [PATCH] 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" --- Sources/Plasma/Apps/plClient/CMakeLists.txt | 6 +- Sources/Plasma/Apps/plClient/plClient.cpp | 62 +--- Sources/Plasma/Apps/plClient/plClient.h | 3 +- .../Plasma/Apps/plClient/plClientLoader.cpp | 145 ++++++++ Sources/Plasma/Apps/plClient/plClientLoader.h | 110 ++++++ Sources/Plasma/Apps/plClient/winmain.cpp | 351 +++++------------- Sources/Plasma/CoreLib/hsThread_Win.cpp | 2 +- 7 files changed, 362 insertions(+), 317 deletions(-) create mode 100644 Sources/Plasma/Apps/plClient/plClientLoader.cpp create mode 100644 Sources/Plasma/Apps/plClient/plClientLoader.h diff --git a/Sources/Plasma/Apps/plClient/CMakeLists.txt b/Sources/Plasma/Apps/plClient/CMakeLists.txt index 9c0f7e65..a23b1c99 100644 --- a/Sources/Plasma/Apps/plClient/CMakeLists.txt +++ b/Sources/Plasma/Apps/plClient/CMakeLists.txt @@ -39,17 +39,15 @@ endif(PYTHONINTERP_FOUND) set(plClient_HEADERS plClient.h plClientCreatable.h - #plClientKey.h + plClientLoader.h plClientUpdateFormat.h - #plPluginClient.h ) set(plClient_SOURCES pfAllCreatables.cpp plAllCreatables.cpp plClient.cpp - #plClientKey.cpp - #plPluginClient.cpp + plClientLoader.cpp pnAllCreatables.cpp winmain.cpp ) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index c07695f5..49cc921b 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -799,14 +799,6 @@ bool plClient::MsgReceive(plMessage* msg) return true; } - //============================================================================ - // plNetCommAuthMsg - //============================================================================ - if (plNetCommAuthMsg * authCommMsg = plNetCommAuthMsg::ConvertNoRef(msg)) { - IHandleNetCommAuthMsg(authCommMsg); - return true; - } - //============================================================================ // plResPatcherMsg //============================================================================ @@ -1379,10 +1371,6 @@ bool plClient::StartInit() // local data of course). ((plResManager *)hsgResMgr::ResMgr())->VerifyPages(); - // the dx8 audio system MUST be initialized - // before the database is loaded - SetForegroundWindow(fWindowHndl); - plgAudioSys::Init(); gAudio = plgAudioSys::Sys(); @@ -1439,7 +1427,6 @@ bool plClient::StartInit() // // Init Net before loading things // - plgDispatch::Dispatch()->RegisterForExactType(plNetCommAuthMsg::Index(), GetKey()); plNetClientMgr::GetInstance()->Init(); plAgeLoader::GetInstance()->Init(); @@ -1460,8 +1447,6 @@ bool plClient::StartInit() plMouseDevice::Instance()->SetDisplayResolution((float)fPipeline->Width(), (float)fPipeline->Height()); 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()); // create the listener for the audio system: @@ -1472,22 +1457,15 @@ bool plClient::StartInit() plgDispatch::Dispatch()->RegisterForExactType(plAudioSysMsg::Index(), pLMod->GetKey()); plSynchedObject::PushSynchDisabled(false); // enable dirty tracking + return true; +} - if (NetCommGetStartupAge()->ageDatasetName.CompareI("StartUp") == 0) - { - plNetCommAuthMsg * msg = new plNetCommAuthMsg(); - msg->result = kNetSuccess; - msg->param = nil; - msg->Send(); - } - - // 2nd half of plClient initialization occurs after - // all network events have completed. Async events: - // - // 1) Download secure files - // - // Continue plClient init via IOnAsyncInitComplete(). - +//============================================================================ +bool plClient::BeginGame() +{ + IPlayIntroMovie("avi/CyanWorlds.webm", 0.f, 0.f, 0.f, 1.f, 1.f, 0.75); + if (GetDone()) return false; + IPatchGlobalAgeFiles(); return true; } @@ -2290,27 +2268,3 @@ void plClient::IHandlePatcherMsg (plResPatcherMsg * msg) { 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(); -} diff --git a/Sources/Plasma/Apps/plClient/plClient.h b/Sources/Plasma/Apps/plClient/plClient.h index c81fa37b..485d5045 100644 --- a/Sources/Plasma/Apps/plClient/plClient.h +++ b/Sources/Plasma/Apps/plClient/plClient.h @@ -177,7 +177,6 @@ protected: void ICompleteInit (); void IOnAsyncInitComplete (); void IHandlePatcherMsg (plResPatcherMsg * msg); - void IHandleNetCommAuthMsg (plNetCommAuthMsg * msg); bool IHandleAgeLoaded2Msg (plAgeLoaded2Msg * msg); bool IFlushRenderRequests(); @@ -286,6 +285,8 @@ public: virtual void WindowActivate(bool active); virtual bool WindowActive() const { return fWindowActive; } + bool BeginGame(); + void FlashWindow(); void SetMessagePumpProc( plMessagePumpProc proc ) { fMessagePumpProc = proc; } void ResetDisplayDevice(int Width, int Height, int ColorDepth, bool Windowed, int NumAASamples, int MaxAnisotropicSamples, bool VSync = false); diff --git a/Sources/Plasma/Apps/plClient/plClientLoader.cpp b/Sources/Plasma/Apps/plClient/plClientLoader.cpp new file mode 100644 index 00000000..3be92717 --- /dev/null +++ b/Sources/Plasma/Apps/plClient/plClientLoader.cpp @@ -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 . + +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 + +#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(); +} diff --git a/Sources/Plasma/Apps/plClient/plClientLoader.h b/Sources/Plasma/Apps/plClient/plClientLoader.h new file mode 100644 index 00000000..e0a5bf73 --- /dev/null +++ b/Sources/Plasma/Apps/plClient/plClientLoader.h @@ -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 . + +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; } +}; + diff --git a/Sources/Plasma/Apps/plClient/winmain.cpp b/Sources/Plasma/Apps/plClient/winmain.cpp index af179d9a..00c03dcf 100644 --- a/Sources/Plasma/Apps/plClient/winmain.cpp +++ b/Sources/Plasma/Apps/plClient/winmain.cpp @@ -52,7 +52,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsStream.h" #include "plCmdParser.h" #include "plClient.h" -#include "plClientResMgr/plClientResMgr.h" +#include "plClientLoader.h" #include "pfCrashHandler/plCrashCli.h" #include "plNetClient/plNetClientMgr.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 "plProduct.h" #include "plNetGameLib/plNetGameLib.h" -#include "plPhysX/plSimulationMgr.h" #include "res/resource.h" @@ -114,7 +113,7 @@ int gWinBorderDX = GetSystemMetrics( SM_CXSIZEFRAME ); int gWinBorderDY = GetSystemMetrics( SM_CYSIZEFRAME ); int gWinMenuDY = GetSystemMetrics( SM_CYCAPTION ); -plClient *gClient; +plClientLoader gClient; bool gPendingActivate = false; bool gPendingActivateFlag = false; @@ -143,11 +142,6 @@ static wchar_t s_patcherExeName[] = L"UruLauncher.exe"; #endif // PLASMA_EXTERNAL_RELEASE -//============================================================================ -// PhysX installer -//============================================================================ -static wchar_t s_physXSetupExeName[] = L"PhysX_Setup.exe"; - //============================================================================ // LoginDialogParam //============================================================================ @@ -355,15 +349,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_CLOSE: - gClient->SetDone(TRUE); - if (plNetClientMgr * mgr = plNetClientMgr::GetInstance()) - mgr->QueueDisableNet(false, nil); + gClient.ShutdownStart(); DestroyWindow(gClient->GetWindowHandle()); break; case WM_DESTROY: - gClient->SetDone(TRUE); - if (plNetClientMgr * mgr = plNetClientMgr::GetInstance()) - mgr->QueueDisableNet(false, nil); + gClient.ShutdownStart(); PostQuitMessage(0); break; } @@ -456,156 +446,6 @@ void DeInitNetClientComm() 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 // @@ -1065,34 +905,34 @@ BOOL CALLBACK UruLoginDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM 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: - switch (plLocalization::GetLanguage()) - { - case plLocalization::kFrench: - ::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Démarrage d'URU. Veuillez patienter..."); - break; - case plLocalization::kGerman: - ::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Starte URU, bitte warten ..."); - break; - case plLocalization::kSpanish: - ::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Iniciando URU, por favor espera..."); - break; - case plLocalization::kItalian: - ::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Avvio di URU, attendere..."); - break; - // default is English - case plLocalization::kJapanese: - ::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "..."); - break; - default: - ::SetDlgItemText( hwndDlg, IDC_STARTING_TEXT, "Starting URU. Please wait..."); - break; - } - return true; + case WM_INITDIALOG: + switch (plLocalization::GetLanguage()) + { + case plLocalization::kFrench: + ::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Démarrage d'URU. Veuillez patienter..."); + break; + case plLocalization::kGerman: + ::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Starte URU, bitte warten ..."); + break; + case plLocalization::kSpanish: + ::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Iniciando URU, por favor espera..."); + break; + case plLocalization::kItalian: + ::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Avvio di URU, attendere..."); + break; + // default is English + case plLocalization::kJapanese: + ::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "..."); + break; + default: + ::SetDlgItemText(hwndDlg, IDC_STARTING_TEXT, "Starting URU. Please wait..."); + break; + } + return true; } 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. s_crash.WaitForHandle(); - HWND parentHwnd = (gClient == nil) ? GetActiveWindow() : gClient->GetWindowHandle(); + HWND parentHwnd = gClient ? gClient->GetWindowHandle() : GetActiveWindow(); DialogBoxParam(gHInst, MAKEINTRESOURCE(IDD_EXCEPTION), parentHwnd, ExceptionDialogProc, NULL); // Trickle up the handlers @@ -1129,6 +969,40 @@ LONG WINAPI plCustomUnhandledExceptionFilter( struct _EXCEPTION_POINTERS *Except #include "pfConsoleCore/pfConsoleEngine.h" 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" 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 + // 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"); if (serverIniFile) { @@ -1254,6 +1132,12 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC 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); InitNetClientComm(); @@ -1299,96 +1183,49 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC curl_global_cleanup(); if (needExit) { + gClient.ShutdownStart(); + gClient.ShutdownEnd(); DeInitNetClientComm(); return PARABLE_NORMAL_EXIT; } 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 #ifndef HS_DEBUGGING LPTOP_LEVEL_EXCEPTION_FILTER oldFilter; oldFilter = SetUnhandledExceptionFilter( plCustomUnhandledExceptionFilter ); #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()); - - for (;;) { - // Create Window - if (!WinInit(hInst, nCmdShow) || gClient->GetDone()) - break; - - // 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()); + // We should quite frankly be done initing the client by now. But, if not, spawn the good old + // "Starting URU, please wait..." dialog (not so yay) + if (!gClient.IsInited()) { + HWND splashDialog = ::CreateDialog(hInst, MAKEINTRESOURCE(IDD_LOADING), NULL, SplashDialogProc); + gClient.Wait(); + ::DestroyWindow(splashDialog); + } - // - // Init Application here - // - if( !gClient->StartInit() ) - break; - - // I want it on top! I mean it! - BringWindowToTop( gClient->GetWindowHandle() ); + // Main loop + if (gClient && !gClient->GetDone()) { + gClient->SetMessagePumpProc(PumpMessageQueueProc); + gClient.Start(); - // initialize dinput here: - if (gClient && gClient->GetInputManager()) - gClient->GetInputManager()->InitDInput(hInst, (HWND)gClient->GetWindowHandle()); - - // Seriously! - BringWindowToTop( gClient->GetWindowHandle() ); - - // - // Main loop - // MSG msg; - do - { + do { gClient->MainLoop(); - - if( gClient->GetDone() ) + if (gClient->GetDone()) break; // Look for a message - while (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) - { + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // Handle the message - TranslateMessage( &msg ); - DispatchMessage( &msg ); + TranslateMessage(&msg); + DispatchMessage(&msg); } } while (WM_QUIT != msg.message); - - break; } - // - // 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 + gClient.ShutdownEnd(); DeInitNetClientComm(); // Uninstall our unhandled exception filter, if we installed one diff --git a/Sources/Plasma/CoreLib/hsThread_Win.cpp b/Sources/Plasma/CoreLib/hsThread_Win.cpp index 014aa9f9..3be66009 100644 --- a/Sources/Plasma/CoreLib/hsThread_Win.cpp +++ b/Sources/Plasma/CoreLib/hsThread_Win.cpp @@ -67,8 +67,8 @@ static unsigned int __stdcall gEntryPointBT(void* param) WinThreadParam* wtp = (WinThreadParam*)param; unsigned int result = wtp->fThread->Run(); - ::ReleaseSemaphore(wtp->fQuitSemaH, 1, nil); // signal that we've quit wtp->fThread->OnQuit(); + ::ReleaseSemaphore(wtp->fQuitSemaH, 1, nil); // signal that we've quit delete wtp; return result; }