diff --git a/Sources/Plasma/Apps/plClient/CMakeLists.txt b/Sources/Plasma/Apps/plClient/CMakeLists.txt index a23b1c99..9c0f7e65 100644 --- a/Sources/Plasma/Apps/plClient/CMakeLists.txt +++ b/Sources/Plasma/Apps/plClient/CMakeLists.txt @@ -39,15 +39,17 @@ endif(PYTHONINTERP_FOUND) set(plClient_HEADERS plClient.h plClientCreatable.h - plClientLoader.h + #plClientKey.h plClientUpdateFormat.h + #plPluginClient.h ) set(plClient_SOURCES pfAllCreatables.cpp plAllCreatables.cpp plClient.cpp - plClientLoader.cpp + #plClientKey.cpp + #plPluginClient.cpp pnAllCreatables.cpp winmain.cpp ) diff --git a/Sources/Plasma/Apps/plClient/plClient.cpp b/Sources/Plasma/Apps/plClient/plClient.cpp index 069a0ff9..c07695f5 100644 --- a/Sources/Plasma/Apps/plClient/plClient.cpp +++ b/Sources/Plasma/Apps/plClient/plClient.cpp @@ -800,20 +800,18 @@ bool plClient::MsgReceive(plMessage* msg) } //============================================================================ - // plResPatcherMsg + // plNetCommAuthMsg //============================================================================ - if (plResPatcherMsg * resMsg = plResPatcherMsg::ConvertNoRef(msg)) { - IHandlePatcherMsg(resMsg); + if (plNetCommAuthMsg * authCommMsg = plNetCommAuthMsg::ConvertNoRef(msg)) { + IHandleNetCommAuthMsg(authCommMsg); return true; } //============================================================================ - // plNetCommAuthMsg + // plResPatcherMsg //============================================================================ - if (plNetCommAuthMsg* authMsg = plNetCommAuthMsg::ConvertNoRef(msg)) { - plgDispatch::Dispatch()->UnRegisterForExactType(plNetCommAuthMsg::Index(), GetKey()); - if (IS_NET_SUCCESS(authMsg->result)) - IPatchGlobalAgeFiles(); + if (plResPatcherMsg * resMsg = plResPatcherMsg::ConvertNoRef(msg)) { + IHandlePatcherMsg(resMsg); return true; } @@ -1381,6 +1379,10 @@ 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(); @@ -1438,7 +1440,7 @@ bool plClient::StartInit() // Init Net before loading things // plgDispatch::Dispatch()->RegisterForExactType(plNetCommAuthMsg::Index(), GetKey()); - plNetClientMgr::GetInstance()->RegisterAs(kNetClientMgr_KEY); + plNetClientMgr::GetInstance()->Init(); plAgeLoader::GetInstance()->Init(); plCmdIfaceModMsg* pModMsg2 = new plCmdIfaceModMsg; @@ -1458,6 +1460,8 @@ 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: @@ -1468,22 +1472,22 @@ bool plClient::StartInit() plgDispatch::Dispatch()->RegisterForExactType(plAudioSysMsg::Index(), pLMod->GetKey()); plSynchedObject::PushSynchDisabled(false); // enable dirty tracking - return true; -} -//============================================================================ -bool plClient::BeginGame() -{ - plNetClientMgr::GetInstance()->Init(); - IPlayIntroMovie("avi/CyanWorlds.webm", 0.f, 0.f, 0.f, 1.f, 1.f, 0.75); - if (GetDone()) return false; - if (NetCommGetStartupAge()->ageDatasetName.CompareI("StartUp") == 0) { - // This is needed because there is no auth step in this case - plNetCommAuthMsg* msg = new plNetCommAuthMsg(); - msg->result = kNetSuccess; - msg->param = nullptr; + 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(). + return true; } @@ -2286,3 +2290,27 @@ 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 485d5045..c81fa37b 100644 --- a/Sources/Plasma/Apps/plClient/plClient.h +++ b/Sources/Plasma/Apps/plClient/plClient.h @@ -177,6 +177,7 @@ protected: void ICompleteInit (); void IOnAsyncInitComplete (); void IHandlePatcherMsg (plResPatcherMsg * msg); + void IHandleNetCommAuthMsg (plNetCommAuthMsg * msg); bool IHandleAgeLoaded2Msg (plAgeLoaded2Msg * msg); bool IFlushRenderRequests(); @@ -285,8 +286,6 @@ 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 deleted file mode 100644 index 43937471..00000000 --- a/Sources/Plasma/Apps/plClient/plClientLoader.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ - -#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 deleted file mode 100644 index 159f8456..00000000 --- a/Sources/Plasma/Apps/plClient/plClientLoader.h +++ /dev/null @@ -1,110 +0,0 @@ -/*==LICENSE==* - -CyanWorlds.com Engine - MMOG client, server and tools -Copyright (C) 2011 Cyan Worlds, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Additional permissions under GNU GPL version 3 section 7 - -If you modify this Program, or any covered work, by linking or -combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, -NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent -JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK -(or a modified version of those libraries), -containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, -PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG -JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the -licensors of this Program grant you additional -permission to convey the resulting work. Corresponding Source for a -non-source form of such a combination shall include the source code for -the parts of OpenSSL and IJG JPEG Library used as well as that of the covered -work. - -You can contact Cyan Worlds, Inc. by email legal@cyan.com - or by snail mail at: - Cyan Worlds, Inc. - 14617 N Newport Hwy - Mead, WA 99021 - -*==LICENSE==*/ - -#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 57e9877c..af179d9a 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 "plClientLoader.h" +#include "plClientResMgr/plClientResMgr.h" #include "pfCrashHandler/plCrashCli.h" #include "plNetClient/plNetClientMgr.h" #include "plInputCore/plInputDevice.h" @@ -66,6 +66,7 @@ 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" @@ -78,7 +79,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #define TIMER_UNITS_PER_SEC (float)1e3 #define UPDATE_STATUSMSG_SECONDS 30 -#define WM_APP_SETSTATUSMSG WM_APP+1 +#define WM_USER_SETSTATUSMSG WM_USER+1 // // Globals @@ -113,7 +114,7 @@ int gWinBorderDX = GetSystemMetrics( SM_CXSIZEFRAME ); int gWinBorderDY = GetSystemMetrics( SM_CYSIZEFRAME ); int gWinMenuDY = GetSystemMetrics( SM_CYCAPTION ); -plClientLoader gClient; +plClient *gClient; bool gPendingActivate = false; bool gPendingActivateFlag = false; @@ -142,6 +143,11 @@ static wchar_t s_patcherExeName[] = L"UruLauncher.exe"; #endif // PLASMA_EXTERNAL_RELEASE +//============================================================================ +// PhysX installer +//============================================================================ +static wchar_t s_physXSetupExeName[] = L"PhysX_Setup.exe"; + //============================================================================ // LoginDialogParam //============================================================================ @@ -349,11 +355,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_CLOSE: - gClient.ShutdownStart(); + gClient->SetDone(TRUE); + if (plNetClientMgr * mgr = plNetClientMgr::GetInstance()) + mgr->QueueDisableNet(false, nil); DestroyWindow(gClient->GetWindowHandle()); break; case WM_DESTROY: - gClient.ShutdownStart(); + gClient->SetDone(TRUE); + if (plNetClientMgr * mgr = plNetClientMgr::GetInstance()) + mgr->QueueDisableNet(false, nil); PostQuitMessage(0); break; } @@ -446,6 +456,156 @@ 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 // @@ -704,7 +864,7 @@ static size_t CurlCallback(void *buffer, size_t size, size_t nmemb, void *param) strncpy(status, (const char *)buffer, std::min(size * nmemb, 256)); status[255] = 0; - PostMessage(hwnd, WM_APP_SETSTATUSMSG, 0, (LPARAM) status); + PostMessage(hwnd, WM_USER_SETSTATUSMSG, 0, (LPARAM) status); return size * nmemb; } @@ -731,7 +891,7 @@ void StatusCallback(void *param) curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, param); if (!statusUrl.IsEmpty() && curl_easy_perform(hCurl) != 0) // only perform request if there's actually a URL set - PostMessage(hwnd, WM_APP_SETSTATUSMSG, 0, (LPARAM) curlError); + PostMessage(hwnd, WM_USER_SETSTATUSMSG, 0, (LPARAM) curlError); for(unsigned i = 0; i < UPDATE_STATUSMSG_SECONDS && s_loginDlgRunning; ++i) { @@ -787,7 +947,7 @@ BOOL CALLBACK UruLoginDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM return FALSE; } - case WM_APP_SETSTATUSMSG: + case WM_USER_SETSTATUSMSG: SendMessage(GetDlgItem(hwndDlg, IDC_STATUS_TEXT), WM_SETTEXT, 0, lParam); return TRUE; @@ -905,34 +1065,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; @@ -958,7 +1118,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 ? gClient->GetWindowHandle() : GetActiveWindow(); + HWND parentHwnd = (gClient == nil) ? GetActiveWindow() : gClient->GetWindowHandle(); DialogBoxParam(gHInst, MAKEINTRESOURCE(IDD_EXCEPTION), parentHwnd, ExceptionDialogProc, NULL); // Trickle up the handlers @@ -969,40 +1129,6 @@ 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) { @@ -1115,10 +1241,6 @@ 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) { @@ -1132,12 +1254,6 @@ 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(); @@ -1183,51 +1299,96 @@ 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 - // 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); - } + // + // 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()); - // Main loop - if (gClient && !gClient->GetDone()) { - if (gPendingActivate) - gClient->WindowActivate(gPendingActivateFlag); - gClient->SetMessagePumpProc(PumpMessageQueueProc); - gClient.Start(); + 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()); + + // + // 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; - 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; } - 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(); // 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 3be66009..014aa9f9 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(); - wtp->fThread->OnQuit(); ::ReleaseSemaphore(wtp->fQuitSemaH, 1, nil); // signal that we've quit + wtp->fThread->OnQuit(); delete wtp; return result; } diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetClientCommInterface.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientCommInterface.cpp index cd7396b7..45aa2327 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetClientCommInterface.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientCommInterface.cpp @@ -65,7 +65,6 @@ int plNetClientCommMsgHandler::HandleMessage( plNetMessage* msg ) int plNetClientMgr::IInitNetClientComm() { NetCommActivatePostInitErrorHandler(); - NetCommActivateMsgDispatchers(); ASSERT(!GetFlagsBit(kNetClientCommInited)); fNetClientComm.SetDefaultHandler(&fNetClientCommMsgHandler); diff --git a/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp index 16e22721..63509817 100644 --- a/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClient/plNetClientMgr.cpp @@ -341,6 +341,7 @@ int plNetClientMgr::Init() VaultInitialize(); + RegisterAs( kNetClientMgr_KEY ); IAddCloneRoom(); fNetGroups.Reset(); diff --git a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp index 043086bc..0ea74390 100644 --- a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp +++ b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp @@ -741,6 +741,10 @@ void NetCommStartup () { NetClientInitialize(); NetClientSetErrorHandler(IPreInitNetErrorCallback); + NetCliGameSetRecvBufferHandler(INetBufferCallback); +// NetCliAuthSetRecvBufferHandler(INetBufferCallback); + NetCliAuthSetNotifyNewBuildHandler(INotifyNewBuildCallback); + NetCliAuthSetConnectCallback(INotifyAuthConnectedCallback); // Set startup age info memset(&s_startupAge, 0, sizeof(s_startupAge)); @@ -776,10 +780,15 @@ void NetCommEnableNet ( bool enabled, bool wait ) { - if (enabled) + if (enabled) { NetClientInitialize(); - else + NetClientSetErrorHandler(INetErrorCallback); + NetCliGameSetRecvBufferHandler(INetBufferCallback); +// NetCliAuthSetRecvBufferHandler(INetBufferCallback); + } + else { NetClientDestroy(wait); + } } //============================================================================ @@ -787,15 +796,6 @@ void NetCommActivatePostInitErrorHandler () { NetClientSetErrorHandler(INetErrorCallback); } -//============================================================================ -void NetCommActivateMsgDispatchers() { - NetClientSetErrorHandler(INetErrorCallback); - NetCliGameSetRecvBufferHandler(INetBufferCallback); -// NetCliAuthSetRecvBufferHandler(INetBufferCallback); - NetCliAuthSetNotifyNewBuildHandler(INotifyNewBuildCallback); - NetCliAuthSetConnectCallback(INotifyAuthConnectedCallback); -} - //============================================================================ void NetCommUpdate () { // plClient likes to recursively call us on occasion; debounce that crap. diff --git a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.h b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.h index 2116ec87..45aeb75d 100644 --- a/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.h +++ b/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.h @@ -136,7 +136,6 @@ void NetCommEnableNet ( bool wait ); void NetCommActivatePostInitErrorHandler(); -void NetCommActivateMsgDispatchers(); /***************************************************************************** diff --git a/Sources/Plasma/PubUtilLib/plPipeline/DX/plDXPipeline.cpp b/Sources/Plasma/PubUtilLib/plPipeline/DX/plDXPipeline.cpp index 779e19b5..301ceb4f 100644 --- a/Sources/Plasma/PubUtilLib/plPipeline/DX/plDXPipeline.cpp +++ b/Sources/Plasma/PubUtilLib/plPipeline/DX/plDXPipeline.cpp @@ -2239,23 +2239,25 @@ bool plDXPipeline::IResetDevice() IFindDepthFormat(fSettings.fPresentParams); } HRESULT hr = fD3DDevice->Reset(&fSettings.fPresentParams); - // The device is inited the first time on the client loader thread, but this is the main thread - // we expect to get one failure... So let's try recreating the device on the main thread. - if (FAILED(hr)) { - IReleaseDeviceObjects(); - for (int i = 0; true; ++i) { - if (!ICreateDeviceObjects()) - break; - ::Sleep(250); - // Old magic number from reset land - if (i == 25) { - IPrintDeviceInitError(); - IResetToDefaults(&fSettings.fPresentParams); - } + int count = 0; + while( FAILED(hr) ) + { + if(count++ == 25) + { + IPrintDeviceInitError(); + IResetToDefaults(&fSettings.fPresentParams); } + // Still not ready? This is bad. + // Until we called Reset(), we could make any D3D call we wanted, + // and it would turn into a no-op. But once we call Reset(), until + // the device really is reset, anything but TestCoop/Reset/Release + // has just become illegal. We've already released everything, Reset + // just failed, not much to do but wait and try again. + ::Sleep(250); + hr = fD3DDevice->Reset(&fSettings.fPresentParams); } fSettings.fCurrFVFFormat = 0; - fSettings.fCurrVertexShader = nullptr; + fSettings.fCurrVertexShader = NULL; fManagedAlloced = false; ICreateDynDeviceObjects(); IInitDeviceState();