////////////////////////////////////////////////////////// // // NvOptimusDetect // // Try detecting optimus via NvAPI // ////////////////////////////////////////////////////////// bool NvOptimusDetect( void ) { if( NvAPI_Initialize() != NVAPI_OK ) { return false; } // Get and log driver info NvAPI_ShortString szDesc = "-"; NvU32 uiDriverVersion = -1; NvAPI_ShortString szBuildBranchString = "-"; NvAPI_GetInterfaceVersionString( szDesc ); NvAPI_SYS_GetDriverAndBranchVersion( &uiDriverVersion, szBuildBranchString ); WriteDebugEventAndReport( 7460, SString( "NvAPI - InterfaceVersion:'%s' DriverVersion:%d.%d Branch:'%s'", szDesc, uiDriverVersion / 100, uiDriverVersion % 100, szBuildBranchString ) ); // Get all the Physical GPU Handles NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS] = {0}; NvU32 uiGpuCount = 0; if( NvAPI_EnumPhysicalGPUs( nvGPUHandle, &uiGpuCount ) != NVAPI_OK ) { return false; } bool bFoundOptimus = false; for( NvU32 i = 0; i < uiGpuCount; i++ ) { NV_SYSTEM_TYPE SystemType = (NV_SYSTEM_TYPE)-1; // 1-Laptop 2-Desktop NV_GPU_TYPE GpuType = (NV_GPU_TYPE)-1; // 1-Integrated 2-Discrete NvAPI_ShortString szName = "-"; NvAPI_GPU_GetSystemType( nvGPUHandle[i], &SystemType ); NvAPI_GPU_GetGPUType( nvGPUHandle[i], &GpuType ); NvAPI_GPU_GetFullName( nvGPUHandle[i], szName ); SString strStatus( "NvAPI - GPU %d/%d - SystemType:%d GpuType:%d (%s)", i, uiGpuCount, SystemType, GpuType, szName ); if ( SystemType == NV_SYSTEM_TYPE_LAPTOP && GpuType == NV_SYSTEM_TYPE_DGPU ) { bFoundOptimus = true; strStatus += " FoundOptimus"; } WriteDebugEventAndReport( 7461, strStatus ); } return bFoundOptimus; }
////////////////////////////////////////////////////////// // // ShouldUseExeCopy // // Returns true if patches should be applied to exe copy // ////////////////////////////////////////////////////////// bool ShouldUseExeCopy( void ) { SString strUseCopyReason; if ( GetApplicationSettingInt( "nvhacks", "optimus" ) ) strUseCopyReason = GetApplicationSettingInt( "nvhacks", "optimus-rename-exe" ) == 0 ? "" : "optimus-rename-exe"; else strUseCopyReason = GetApplicationSettingInt( "driver-overrides-disabled" ) == 0 ? "" : "driver-overrides-disabled"; if ( GetPatchRequirementAltModules() ) strUseCopyReason += " AltModules"; if ( RequiresAltTabFix() ) strUseCopyReason += " AltTabFix"; // Log reason for using proxy_sa static SString strUseCopyReasonPrevious; if ( strUseCopyReasonPrevious != strUseCopyReason ) { WriteDebugEventAndReport( 3500, SString( "Using proxy_sa because: %s", *strUseCopyReason ) ); strUseCopyReasonPrevious = strUseCopyReason; } return !strUseCopyReason.empty(); }
EPatchResult UpdatePatchStatusAltModules( const SString& strGTAEXEPath, EPatchMode mode ) { // List of names to check/change SSearchInfo searchList[] = { { 0x4a0000, 0x3000, "vorbisfile.dll", "vvof.dll", 0, }, { 0x4a0000, 0x3000, "eax.dll", "vea.dll", 0, }, { 0xD96000, 0x7000, "vorbisfile.dll", "vvof.dll", 0, }, { 0xD96000, 0x7000, "eax.dll", "vea.dll", 0, }, }; uint uiNumOldNames = 0; uint uiNumNewNames = 0; FILE* fh = fopen ( strGTAEXEPath, "rb" ); if ( fh ) { for ( uint i = 0 ; i < NUMELMS( searchList ) ; i++ ) { SSearchInfo& item = searchList[i]; if ( !fseek ( fh, item.uiOffsetStart, SEEK_SET ) ) { std::vector < char > buffer; buffer.resize( item.uiSearchSize ); if ( fread ( &buffer[0], item.uiSearchSize, 1, fh ) == 1 ) { std::vector < char >::iterator it; it = std::search( buffer.begin(), buffer.end(), item.szOldName, item.szOldName + strlen( item.szOldName ), SearchPredicate ); if ( it != buffer.end() ) { uiNumOldNames++; } else { it = std::search( buffer.begin(), buffer.end(), item.szNewName, item.szNewName + strlen( item.szNewName ), SearchPredicate ); if ( it != buffer.end() ) { uiNumNewNames++; } } if ( it != buffer.end() ) { char* p0 = &buffer[0]; char* p1 = &(*it); item.uiFileOffset = item.uiOffsetStart + (uint)p1 - (uint)p0; } } } } fclose ( fh ); } // Return status if just checking if ( mode == PATCH_CHECK ) { if ( uiNumNewNames > 0 ) return PATCH_CHECK_RESULT_ON; return PATCH_CHECK_RESULT_OFF; } if ( uiNumOldNames + uiNumNewNames != 4 ) { WriteDebugEventAndReport( 9804, SString ( "UpdatePatchStatusAltModules: Can't find module names (%d,%d)", uiNumOldNames, uiNumNewNames ) ); } if ( ( mode == PATCH_SET_ON && uiNumOldNames > 0 ) || ( mode == PATCH_SET_OFF && uiNumNewNames > 0 ) ) { // Change needed! // Can't do this to gta_sa.exe 4 sure assert( !strGTAEXEPath.EndsWithI( "gta_sa.exe" ) ); SetFileAttributes ( strGTAEXEPath, FILE_ATTRIBUTE_NORMAL ); FILE* fh = fopen ( strGTAEXEPath, "r+b" ); if ( !fh ) { return PATCH_SET_RESULT_REQ_ADMIN; } for ( uint i = 0 ; i < NUMELMS( searchList ) ; i++ ) { SSearchInfo& item = searchList[i]; const char* szName = ( mode == PATCH_SET_ON ) ? item.szNewName : item.szOldName; if ( item.uiFileOffset ) { if ( !fseek ( fh, item.uiFileOffset, SEEK_SET ) ) { fwrite( szName, strlen( szName ) + 1, 1, fh ); } } } fclose ( fh ); if ( mode == PATCH_SET_ON ) WriteDebugEvent( SString ( "UpdatePatchStatusAltModules: Now using alt modules (%d,%d)", uiNumOldNames, uiNumNewNames ) ); } return PATCH_SET_RESULT_OK; }
EPatchResult UpdatePatchStatusNvightmare( const SString& strGTAEXEPath, EPatchMode mode ) { char bIsEUVersion = false; bool bHasExportTable = true; uint uiExportValue = 0; bool bUnknownBytes = false; FILE* fh = fopen( strGTAEXEPath, "rb" ); bool bFileError = ( fh == NULL ); if( !bFileError ) { // Determine version bFileError |= ( fseek( fh, EU_VERSION_BYTE, SEEK_SET ) != 0 ); bFileError |= ( fread( &bIsEUVersion, 1, 1, fh ) != 1 ); // Determine patched status for ( uint i = 0 ; i < NUMELMS( datumList ) ; i++ ) { const SDataumRow& row = datumList[ i ]; uint uiFileOffset = bIsEUVersion ? row.uiFileOffsetEU : row.uiFileOffsetUS; bFileError |= ( fseek( fh, uiFileOffset, SEEK_SET ) != 0 ); std::vector < char > buffer( row.uiDataSize ); bFileError |= ( fread( &buffer[0], row.uiDataSize, 1, fh ) != 1 ); if ( memcmp( &buffer[0], row.pOldData, row.uiDataSize ) == 0 ) bHasExportTable = false; else if ( memcmp( &buffer[0], row.pNewData, row.uiDataSize ) != 0 ) bUnknownBytes = true; } // Determine export value { uint uiFileOffset = bIsEUVersion ? valueItem.uiFileOffsetEU : valueItem.uiFileOffsetUS; bFileError |= ( fseek( fh, uiFileOffset, SEEK_SET ) != 0 ); bFileError |= ( fread( &uiExportValue, sizeof( uiExportValue ), 1, fh ) != 1 ); } fclose ( fh ); } // Return status if just checking if ( mode == PATCH_CHECK ) { if ( bHasExportTable && uiExportValue == 1 ) return PATCH_CHECK_RESULT_ON; return PATCH_CHECK_RESULT_OFF; } if ( bFileError ) WriteDebugEventAndReport( 9801, "Nvightmare patch: Can not apply due to unknown file error" ); else if ( bUnknownBytes ) WriteDebugEventAndReport( 9802, "Nvightmare patch: Can not apply due to unknown file bytes" ); else { // Determine if change required bool bReqExportTable = ( mode == PATCH_SET_ON ); uint uiReqExportValue = 1; if ( bReqExportTable == bHasExportTable && uiReqExportValue == uiExportValue ) { if ( bReqExportTable ) WriteDebugEvent( SString( "Nvightmare patch: Already applied ExportValue of %d", uiReqExportValue ) ); } else { // Change needed! SetFileAttributes( strGTAEXEPath, FILE_ATTRIBUTE_NORMAL ); FILE* fh = fopen( strGTAEXEPath, "r+b" ); if ( !fh ) { return PATCH_SET_RESULT_REQ_ADMIN; } bool bFileError = false; // Write patches if ( bReqExportTable != bHasExportTable ) { WriteDebugEvent( SString( "Nvightmare patch: Changing HasExportTable to %d", bReqExportTable ) ); for ( uint i = 0 ; i < NUMELMS( datumList ) ; i++ ) { const SDataumRow& row = datumList[ i ]; uint uiFileOffset = bIsEUVersion ? row.uiFileOffsetEU : row.uiFileOffsetUS; bFileError |= ( fseek( fh, uiFileOffset, SEEK_SET ) != 0 ); if ( bReqExportTable ) bFileError |= ( fwrite( row.pNewData, row.uiDataSize, 1, fh ) != 1 ); else bFileError |= ( fwrite( row.pOldData, row.uiDataSize, 1, fh ) != 1 ); } } // Write value if ( uiReqExportValue != uiExportValue ) { WriteDebugEvent( SString( "Nvightmare patch: Changing ExportValue to %d", uiReqExportValue ) ); uint uiFileOffset = bIsEUVersion ? valueItem.uiFileOffsetEU : valueItem.uiFileOffsetUS; bFileError |= ( fseek( fh, uiFileOffset, SEEK_SET ) != 0 ); bFileError |= ( fwrite( &uiReqExportValue, sizeof( uiReqExportValue ), 1, fh ) != 1 ); } fclose ( fh ); if ( bFileError ) WriteDebugEventAndReport( 9803, "Nvightmare patch: File update completed with file errors" ); else WriteDebugEvent( "Nvightmare patch: File update completed" ); } } return PATCH_SET_RESULT_OK; }