////////////////////////////////////////////////////////// // // ValidateGTAPath // // Check GTA path looks good // ////////////////////////////////////////////////////////// void ValidateGTAPath( void ) { // Get path to GTA ePathResult iResult = DiscoverGTAPath( true ); if ( iResult == GAME_PATH_MISSING ) { DisplayErrorMessageBox ( _("Registry entries are missing. Please reinstall Multi Theft Auto: San Andreas."), _E("CL12"), "reg-entries-missing" ); return ExitProcess( EXIT_ERROR ); } else if ( iResult == GAME_PATH_UNICODE_CHARS ) { DisplayErrorMessageBox ( _("The path to your installation of GTA: San Andreas contains unsupported (unicode) characters. Please move your Grand Theft Auto: San Andreas installation to a compatible path that contains only standard ASCII characters and reinstall Multi Theft Auto: San Andreas."), _E("CL13") ); return ExitProcess( EXIT_ERROR ); } else if ( iResult == GAME_PATH_STEAM ) { DisplayErrorMessageBox ( _("It appears you have a Steam version of GTA:SA, which is currently incompatible with MTASA. You are now being redirected to a page where you can find information to resolve this issue."), _E("CL14") ); BrowseToSolution ( "downgrade-steam" ); return ExitProcess( EXIT_ERROR ); } SString strGTAPath = GetGTAPath(); // We can now set this SetCurrentDirectory ( strGTAPath ); const SString strMTASAPath = GetMTASAPath (); if ( strGTAPath.Contains ( ";" ) || strMTASAPath.Contains ( ";" ) ) { DisplayErrorMessageBox (_( "The path to your installation of 'MTA:SA' or 'GTA: San Andreas'\n" "contains a ';' (semicolon).\n\n" " If you experience problems when running MTA:SA,\n" " move your installation(s) to a path that does not contain a semicolon." ), _E("CL15"), "path-semicolon" ); } }
////////////////////////////////////////////////////////// // // HandleTrouble // // // ////////////////////////////////////////////////////////// void HandleTrouble ( void ) { if ( CheckAndShowFileOpenFailureMessage () ) return; int iResponse = MessageBoxUTF8 ( NULL, _("Are you having problems running MTA:SA?.\n\nDo you want to revert to an earlier version?"), "MTA: San Andreas"+_E("CL07"), MB_YESNO | MB_ICONQUESTION | MB_TOPMOST ); if ( iResponse == IDYES ) { BrowseToSolution ( "crashing-before-gtagame", TERMINATE_PROCESS ); } }
//////////////////////////////////////////////// // // CSettingsSA::FindVideoMode // // Find best matching video mode // //////////////////////////////////////////////// uint CSettingsSA::FindVideoMode( int iResX, int iResY, int iColorBits ) { int iBestMode, iBestScore = -1; uint numVidModes = GetNumVideoModes(); for ( uint vidMode = 0; vidMode < numVidModes; vidMode++ ) { VideoMode vidModeInfo; GetVideoModeInfo( &vidModeInfo, vidMode ); // Remove resolutions that will make the gui unusable if ( vidModeInfo.width < 640 || vidModeInfo.height < 480 ) continue; if ( vidModeInfo.flags & rwVIDEOMODEEXCLUSIVE ) { // Rate my res int iScore = abs( iResX - vidModeInfo.width ) + abs( iResY - vidModeInfo.height ); // Penalize matches with wrong bit depth if ( vidModeInfo.depth != iColorBits ) { iScore += 100000; } // Penalize matches with higher than requested resolution if ( vidModeInfo.width > iResX || vidModeInfo.height > iResY ) { iScore += 200000; } if ( iScore < iBestScore || iBestScore == -1 ) { // Found a better match iBestScore = iScore; iBestMode = vidMode; } } } if ( iBestScore != -1 ) return iBestMode; BrowseToSolution ( "no-find-res", EXIT_GAME_FIRST | ASK_GO_ONLINE, _( "Can't find valid screen resolution." ) ); return 1; }
////////////////////////////////////////////////////////// // // HandleResetSettings // // // ////////////////////////////////////////////////////////// void HandleResetSettings ( void ) { if ( CheckAndShowFileOpenFailureMessage () ) return; CheckAndShowMissingFileMessage(); SString strSaveFilePath = PathJoin ( GetSystemPersonalPath(), "GTA San Andreas User Files" ); SString strSettingsFilename = PathJoin ( strSaveFilePath, "gta_sa.set" ); SString strSettingsFilenameBak = PathJoin ( strSaveFilePath, "gta_sa_old.set" ); if ( FileExists ( strSettingsFilename ) ) { int iResponse = MessageBoxUTF8 ( NULL, _("There seems to be a problem launching MTA:SA.\nResetting GTA settings can sometimes fix this problem.\n\nDo you want to reset GTA settings now?"), "MTA: San Andreas"+_E("CL08"), MB_YESNO | MB_ICONQUESTION | MB_TOPMOST ); if ( iResponse == IDYES ) { FileDelete ( strSettingsFilenameBak ); FileRename ( strSettingsFilename, strSettingsFilenameBak ); FileDelete ( strSettingsFilename ); if ( !FileExists ( strSettingsFilename ) ) { AddReportLog ( 4053, "Deleted gta_sa.set" ); MessageBoxUTF8 ( NULL, _("GTA settings have been reset.\n\nPress OK to continue."), "MTA: San Andreas", MB_OK | MB_ICONINFORMATION | MB_TOPMOST ); } else { AddReportLog ( 5054, SString ( "Delete gta_sa.set failed with '%s'", *strSettingsFilename ) ); MessageBoxUTF8 ( NULL, SString ( _("File could not be deleted: '%s'"), *strSettingsFilename ), "Error"+_E("CL09"), MB_OK | MB_ICONWARNING | MB_TOPMOST ); } } } else { // No settings to delete, or can't find them int iResponse = MessageBoxUTF8 ( NULL, _("Are you having problems running MTA:SA?.\n\nDo you want to see some online help?"), "MTA: San Andreas", MB_YESNO | MB_ICONQUESTION | MB_TOPMOST ); if ( iResponse == IDYES ) { BrowseToSolution ( "crashing-before-gtalaunch", TERMINATE_PROCESS ); } } }
/////////////////////////////////////////////////////////////// // // WinMain // // // /////////////////////////////////////////////////////////////// int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // Load the loader.dll and continue the load #ifdef MTA_DEBUG SString strLoaderDllFilename = "loader_d.dll"; #else SString strLoaderDllFilename = "loader.dll"; #endif SString strMTASAPath = PathJoin ( GetLaunchPath (), "mta" ); SString strLoaderDllPathFilename = PathJoin ( strMTASAPath, strLoaderDllFilename ); // Load loader dll HMODULE hModule = LoadLibrary ( strLoaderDllPathFilename ); int iReturnCode = 0; if ( hModule ) { // Find and call DoWinMain typedef int (*PFNDOWINMAIN) ( HINSTANCE, HINSTANCE, LPSTR, int ); PFNDOWINMAIN pfnDoWinMain = static_cast < PFNDOWINMAIN > ( static_cast < PVOID > ( GetProcAddress ( hModule, "DoWinMain" ) ) ); if ( pfnDoWinMain ) iReturnCode = pfnDoWinMain ( hInstance, hPrevInstance, lpCmdLine, nCmdShow ); FreeLibrary ( hModule ); } else { SString strError = GetSystemErrorMessage ( GetLastError () ); SString strMessage ( "Failed to load: '%s'\n\n%s", *strLoaderDllPathFilename, *strError ); AddReportLog ( 5711, strMessage ); BrowseToSolution ( "loader-dll-missing", true, false, false, strMessage ); iReturnCode = 1; } return iReturnCode; }
//////////////////////////////////////////////// // // Hook CCore::OnPostCreateDevice // // Wrap device or log failure // //////////////////////////////////////////////// HRESULT CCore::OnPostCreateDevice(HRESULT hResult, IDirect3D9* pDirect3D, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) { if (!UsingAltD3DSetup()) return D3D_OK; // // - Allow create device with no changes // - Check caps and report diff with GTA caps // - Release device // WriteDebugEvent("CCore::OnPostCreateDevice - Alt startup used"); if (hResult != D3D_OK) WriteDebugEvent(SString("Initial CreateDevice failed: %08x", hResult)); else WriteDebugEvent("Initial CreateDevice succeeded"); AddCapsReport(Adapter, pDirect3D, *ppReturnedDeviceInterface, false); SAFE_RELEASE(*ppReturnedDeviceInterface); // // - Create device with required changes // - Check caps and report diff with GTA caps // - Fix GTA caps if needed // // Save original values for later BehaviorFlagsOrig = BehaviorFlags; presentationParametersOrig = *pPresentationParameters; WriteDebugEvent(" Original paramters:"); WriteDebugEvent(ToString(Adapter, DeviceType, hFocusWindow, BehaviorFlags, *pPresentationParameters)); // Make sure DirectX Get...() calls will work BehaviorFlags &= ~D3DCREATE_PUREDEVICE; // Enable the auto depth stencil parameter pPresentationParameters->EnableAutoDepthStencil = true; GetVideoModeManager()->PreCreateDevice(pPresentationParameters); WriteDebugEvent(" Modified paramters:"); WriteDebugEvent(ToString(Adapter, DeviceType, hFocusWindow, BehaviorFlags, *pPresentationParameters)); hResult = CreateDeviceInsist(2, 1000, pDirect3D, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface); if (hResult != D3D_OK) WriteDebugEvent(SString("MTA CreateDevice failed: %08x", hResult)); else WriteDebugEvent("MTA CreateDevice succeeded"); AddCapsReport(Adapter, pDirect3D, *ppReturnedDeviceInterface, true); // Change the window title to MTA: San Andreas #ifdef MTA_DEBUG SetWindowTextW(hFocusWindow, MbUTF8ToUTF16("MTA: San Andreas [DEBUG]").c_str()); #else SetWindowTextW(hFocusWindow, MbUTF8ToUTF16("MTA: San Andreas").c_str()); #endif // Log graphic card name D3DADAPTER_IDENTIFIER9 AdapterIdent; pDirect3D->GetAdapterIdentifier(Adapter, 0, &AdapterIdent); WriteDebugEvent(ToString(AdapterIdent)); // Store the rendering window in the direct 3d data CDirect3DData::GetSingleton().StoreDeviceWindow(pPresentationParameters->hDeviceWindow); // Apply input hook CMessageLoopHook::GetSingleton().ApplyHook(hFocusWindow); // Make sure the object was created successfully. if (hResult == D3D_OK) { WriteDebugEvent("CreateDevice succeeded"); GetVideoModeManager()->PostCreateDevice(*ppReturnedDeviceInterface, pPresentationParameters); // We must first store the presentation values. CDirect3DData::GetSingleton().StoreViewport(0, 0, pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight); // Calc and store readable depth format for shader use ERenderFormat ReadableDepthFormat = CDirect3DEvents9::DiscoverReadableDepthFormat(*ppReturnedDeviceInterface, pPresentationParameters->MultiSampleType, pPresentationParameters->Windowed != 0); CGraphics::GetSingleton().GetRenderItemManager()->SetDepthBufferFormat(ReadableDepthFormat); // Now create the proxy device. *ppReturnedDeviceInterface = new CProxyDirect3DDevice9(*ppReturnedDeviceInterface); // Debug output D3DDEVICE_CREATION_PARAMETERS parameters; (*ppReturnedDeviceInterface)->GetCreationParameters(¶meters); WriteDebugEvent(" Used creation parameters:"); WriteDebugEvent(SString(" Adapter:%d DeviceType:%d BehaviorFlags:0x%x ReadableDepth:%s", parameters.AdapterOrdinal, parameters.DeviceType, parameters.BehaviorFlags, ReadableDepthFormat ? std::string((char*)&ReadableDepthFormat, 4).c_str() : "None")); } bool bDetectOptimus = (GetModuleHandle("nvd3d9wrap.dll") != NULL); // Calc log level to use uint uiDiagnosticLogLevel = 0; if (GetApplicationSettingInt("nvhacks", "optimus") || bDetectOptimus) uiDiagnosticLogLevel = 1; // Log and continue if (hResult != D3D_OK) uiDiagnosticLogLevel = 2; // Log and wait - If fail status // Do diagnostic log now if needed if (uiDiagnosticLogLevel) { // Prevent statup warning in loader WatchDogCompletedSection("L3"); // Run diagnostic CCore::GetSingleton().GetNetwork()->ResetStub('dia3', *ms_strExtraLogBuffer, uiDiagnosticLogLevel); } ms_strExtraLogBuffer.clear(); // Handle fatal error if (hResult != D3D_OK) { // Inform user SString strMessage; strMessage += "There was a problem starting MTA:SA\n\n"; strMessage += SString("Direct3D CreateDevice error: %08x", hResult); BrowseToSolution("d3dcreatedevice-fail", EXIT_GAME_FIRST | ASK_GO_ONLINE, strMessage); } return hResult; }
//////////////////////////////////////////////// // // HandleCreateDeviceResult // // Log result and possibly fix everything // //////////////////////////////////////////////// HRESULT HandleCreateDeviceResult(HRESULT hResult, IDirect3D9* pDirect3D, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) { // Log graphic card name D3DADAPTER_IDENTIFIER9 AdapterIdent; pDirect3D->GetAdapterIdentifier(Adapter, 0, &AdapterIdent); WriteDebugEvent(ToString(AdapterIdent)); uint uiCurrentStatus = 0; // 0-unknown 1-fail 2-success after retry 3-success if (hResult == D3D_OK) { // Log success and creation parameters WriteDebugEvent("CreateDevice success"); uiCurrentStatus = CREATE_DEVICE_SUCCESS; WriteDebugEvent(ToString(Adapter, DeviceType, hFocusWindow, BehaviorFlags, *pPresentationParameters)); } if (hResult != D3D_OK) { // Handle failure of initial create device call WriteDebugEvent(SString("CreateDevice failed #0: %08x", hResult)); // Try create device again hResult = DoCreateDevice(pDirect3D, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface); // Handle retry result if (hResult != D3D_OK) { WriteDebugEvent("--CreateDevice failed after retry"); uiCurrentStatus = CREATE_DEVICE_FAIL; } else { WriteDebugEvent("++CreateDevice succeeded after retry"); uiCurrentStatus = CREATE_DEVICE_RETRY_SUCCESS; // Apply input hook CMessageLoopHook::GetSingleton().ApplyHook(hFocusWindow); GetVideoModeManager()->PostCreateDevice(*ppReturnedDeviceInterface, pPresentationParameters); // We must first store the presentation values. CDirect3DData::GetSingleton().StoreViewport(0, 0, pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight); // Calc and store readable depth format for shader use ERenderFormat ReadableDepthFormat = CDirect3DEvents9::DiscoverReadableDepthFormat( *ppReturnedDeviceInterface, pPresentationParameters->MultiSampleType, pPresentationParameters->Windowed != 0); CGraphics::GetSingleton().GetRenderItemManager()->SetDepthBufferFormat(ReadableDepthFormat); // Now create the proxy device. *ppReturnedDeviceInterface = new CProxyDirect3DDevice9(*ppReturnedDeviceInterface); // Debug output D3DDEVICE_CREATION_PARAMETERS parameters; (*ppReturnedDeviceInterface)->GetCreationParameters(¶meters); WriteDebugEvent(SString(" Adapter:%d DeviceType:%d BehaviorFlags:0x%x ReadableDepth:%s", parameters.AdapterOrdinal, parameters.DeviceType, parameters.BehaviorFlags, ReadableDepthFormat ? std::string((char*)&ReadableDepthFormat, 4).c_str() : "None")); } } uint uiLastStatus = GetApplicationSettingInt("diagnostics", "createdevice-last-status"); SetApplicationSettingInt("diagnostics", "createdevice-last-status", uiCurrentStatus); // Calc log level to use uint uiDiagnosticLogLevel = 0; if (uiLastStatus == CREATE_DEVICE_FAIL && uiCurrentStatus != CREATE_DEVICE_FAIL) uiDiagnosticLogLevel = 1; // Log and continue - If changing from fail status if (uiCurrentStatus == CREATE_DEVICE_FAIL) uiDiagnosticLogLevel = 2; // Log and wait - If fail status bool bDetectOptimus = (GetModuleHandle("nvd3d9wrap.dll") != NULL); bool bFixCaps = false; if (GetApplicationSettingInt("nvhacks", "optimus") || bDetectOptimus) { bFixCaps = true; if (uiDiagnosticLogLevel == 0) uiDiagnosticLogLevel = 1; } AddCapsReport(Adapter, pDirect3D, *ppReturnedDeviceInterface, bFixCaps); if (uiDiagnosticLogLevel) { // Prevent statup warning in loader WatchDogCompletedSection("L3"); CCore::GetSingleton().GetNetwork()->ResetStub('dia3', *ms_strExtraLogBuffer, uiDiagnosticLogLevel); } ms_strExtraLogBuffer.clear(); if (hResult != D3D_OK) { // Handle fatal error SString strMessage; strMessage += "There was a problem starting MTA:SA\n\n"; strMessage += SString("Direct3D CreateDevice error: %08x", hResult); BrowseToSolution("d3dcreatedevice-fail", EXIT_GAME_FIRST | ASK_GO_ONLINE, strMessage); } return hResult; }