void CCrashDumpWriter::DumpMiniDump ( _EXCEPTION_POINTERS* pException, CExceptionInformation* pExceptionInformation )
{
    WriteDebugEvent ( "CCrashDumpWriter::DumpMiniDump" );

    // Try to load the DLL in our directory
    HMODULE hDll = NULL;
    char szDbgHelpPath [MAX_PATH];
    if ( GetModuleFileNameA ( NULL, szDbgHelpPath, MAX_PATH ) )
    {
        char* pSlash = _tcsrchr ( szDbgHelpPath, '\\' );
        if ( pSlash )
        {
            _tcscpy ( pSlash + 1, "DBGHELP.DLL" );
            hDll = LoadLibrary ( szDbgHelpPath );
        }
    }

    // If we couldn't load the one in our dir, load any version available
    if ( !hDll )
    {
        hDll = LoadLibrary( "DBGHELP.DLL" );
    }

    if ( !hDll )
        AddReportLog( 9201, "CCrashDumpWriter::DumpMiniDump - Could not load DBGHELP.DLL" );

    // We could load a dll?
    if ( hDll )
    {
        // Grab the MiniDumpWriteDump proc address
        MINIDUMPWRITEDUMP pDump = reinterpret_cast < MINIDUMPWRITEDUMP > ( GetProcAddress( hDll, "MiniDumpWriteDump" ) );
        if ( !pDump )
            AddReportLog( 9202, "CCrashDumpWriter::DumpMiniDump - Could not find MiniDumpWriteDump" );

        if ( pDump )
        {
            // Create the file
            HANDLE hFile = CreateFile ( CalcMTASAPath ( "mta\\core.dmp" ), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
            if ( hFile == INVALID_HANDLE_VALUE )
                AddReportLog( 9203, SString( "CCrashDumpWriter::DumpMiniDump - Could not create '%s'", *CalcMTASAPath ( "mta\\core.dmp" ) ) );

            if ( hFile != INVALID_HANDLE_VALUE )
            {
                // Create an exception information struct
                _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
                ExInfo.ThreadId = GetCurrentThreadId ();
                ExInfo.ExceptionPointers = pException;
                ExInfo.ClientPointers = FALSE;

                // Write the dump
                BOOL bResult = pDump ( GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)( MiniDumpNormal | MiniDumpWithIndirectlyReferencedMemory ), &ExInfo, NULL, NULL );

                if ( !bResult )
                    AddReportLog( 9204, SString( "CCrashDumpWriter::DumpMiniDump - MiniDumpWriteDump failed (%08x)", GetLastError() ) );
                else
                    WriteDebugEvent ( "CCrashDumpWriter::DumpMiniDump - MiniDumpWriteDump succeeded" );

                // Close the dumpfile
                CloseHandle ( hFile );

                // Grab the current time
                // Ask windows for the system time.
                SYSTEMTIME SystemTime;
                GetLocalTime ( &SystemTime );

                // Create the dump directory
                CreateDirectory ( CalcMTASAPath ( "mta\\dumps" ), 0 );
                CreateDirectory ( CalcMTASAPath ( "mta\\dumps\\private" ), 0 );

                SString strModuleName = pExceptionInformation->GetModuleBaseName ();
                strModuleName = strModuleName.ReplaceI ( ".dll", "" ).Replace ( ".exe", "" ).Replace ( "_", "" ).Replace ( ".", "" ).Replace ( "-", "" );
                if ( strModuleName.length () == 0 )
                    strModuleName = "unknown";

                SString strMTAVersionFull = SString ( "%s.%s", MTA_DM_BUILDTAG_LONG, *GetApplicationSetting ( "mta-version-ext" ).SplitRight ( ".", NULL, -2 ) );
                SString strSerialPart = GetApplicationSetting ( "serial" ).substr ( 0, 5 );
                uint uiServerIP = GetApplicationSettingInt ( "last-server-ip" );
                uint uiServerPort = GetApplicationSettingInt ( "last-server-port" );
                int uiServerTime = GetApplicationSettingInt ( "last-server-time" );
                int uiServerDuration = _time32 ( NULL ) - uiServerTime;
                uiServerDuration = Clamp ( 0, uiServerDuration + 1, 0xfff );

                // Get path to mta dir
                SString strPathCode;
                {
                    std::vector < SString > parts;
                    PathConform ( CalcMTASAPath ( "" ) ).Split ( PATH_SEPERATOR, parts );
                    for ( uint i = 0 ; i < parts.size () ; i++ )
                    {
                        if ( parts[i].CompareI ( "Program Files" ) )
                            strPathCode += "Pr";
                        else
                        if ( parts[i].CompareI ( "Program Files (x86)" ) )
                            strPathCode += "Px";
                        else
                        if ( parts[i].CompareI ( "MTA San Andreas" ) )
                            strPathCode += "Mt";
                        else
                        if ( parts[i].BeginsWithI ( "MTA San Andreas" ) )
                            strPathCode += "Mb";
                        else
                            strPathCode += parts[i].Left ( 1 ).ToUpper ();
                    }
                }

                // Ensure filename parts match up with EDumpFileNameParts
                SString strFilename ( "mta\\dumps\\private\\client_%s_%s_%08x_%x_%s_%08X_%04X_%03X_%s_%04d%02d%02d_%02d%02d.dmp",
                                             strMTAVersionFull.c_str (),
                                             strModuleName.c_str (),
                                             pExceptionInformation->GetAddressModuleOffset (),
                                             pExceptionInformation->GetCode () & 0xffff,
                                             strPathCode.c_str (),
                                             uiServerIP,
                                             uiServerPort,
                                             uiServerDuration,
                                             strSerialPart.c_str (),
                                             SystemTime.wYear,
                                             SystemTime.wMonth,
                                             SystemTime.wDay,
                                             SystemTime.wHour,
                                             SystemTime.wMinute
                                           );

                SString strPathFilename = CalcMTASAPath ( strFilename );

                // Copy the file
                CopyFile ( CalcMTASAPath ( "mta\\core.dmp" ), strPathFilename, false );

                // For the dump uploader
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "none" );
                SetApplicationSetting ( "diagnostics", "last-dump-save", strPathFilename );

                // Try to append pool sizes info to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-pools" );
                CBuffer poolInfo;
                GetPoolInfo ( poolInfo );
                AppendToDumpFile ( strPathFilename, poolInfo, 'POLs', 'POLe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-pools" );

                // Try to append d3d state info to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-d3d" );
                CBuffer d3dInfo;
                GetD3DInfo ( d3dInfo );
                AppendToDumpFile ( strPathFilename, d3dInfo, 'D3Ds', 'D3De' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-d3d" );

                // Try to append crash averted stats to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-crash-averted" );
                CBuffer crashAvertedStats;
                GetCrashAvertedStats ( crashAvertedStats );
                AppendToDumpFile ( strPathFilename, crashAvertedStats, 'CASs', 'CASe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-crash-averted" );

                // Try to append log info to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-log" );
                CBuffer logInfo;
                GetLogInfo ( logInfo );
                AppendToDumpFile ( strPathFilename, logInfo, 'LOGs', 'LOGe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-log" );

                // Try to append dx info to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-misc" );
                CBuffer dxInfo;
                GetDxInfo ( dxInfo );
                AppendToDumpFile ( strPathFilename, dxInfo, 'DXIs', 'DXIe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-misc" );

                // Try to append misc info to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-misc" );
                CBuffer miscInfo;
                GetMiscInfo ( miscInfo );
                AppendToDumpFile ( strPathFilename, miscInfo, 'MSCs', 'MSCe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-misc" );

                // Try to append memory info to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-mem" );
                CBuffer memInfo;
                GetMemoryInfo ( memInfo );
                AppendToDumpFile ( strPathFilename, memInfo, 'MEMs', 'MEMe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-mem" );

                // Try to logfile.txt to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-logfile" );
                CBuffer logfileContent;
                logfileContent.LoadFromFile( CalcMTASAPath( PathJoin( "mta", "logs", "logfile.txt" ) ) );
                AppendToDumpFile ( strPathFilename, logfileContent, 'LOGs', 'LOGe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-logfile" );

                // Try to report.log to dump file
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "try-report" );
                CBuffer reportLogContent;
                reportLogContent.LoadFromFile( PathJoin( GetMTADataPath(), "report.log" ) );
                AppendToDumpFile ( strPathFilename, reportLogContent, 'REPs', 'REPe' );
                SetApplicationSetting ( "diagnostics", "last-dump-extra", "added-report" );
            }
        }

        // Free the DLL again
        FreeLibrary ( hDll );
    }

    // Auto-fixes

    // Check if crash was in volumetric shadow code
    if ( ms_uiInCrashZone == 1 || ms_uiInCrashZone == 2 )
    {
        CVARS_SET( "volumetric_shadows", false );
        CCore::GetSingleton().SaveConfig();
        AddReportLog( 9205, "Disabled volumetric shadows" );
    }

    CNet* pNet = CCore::GetSingleton().GetNetwork();
    if ( pNet )
        pNet->PostCrash();    
}
//Get the system information and print everything on screen (and in the log file)
void GameDebugger::GetSystemSpecs(ALLEGRO_DISPLAY* mydisplay)
{
    GetSystemInfo(&SystemInfo);
    struct tm* mytime = GetDateAndTime();

        fprintf(OutputFile, "-- START OF LOG FILE --\nTIMESTAMP: %02i/%02i/%02i - %02i:%02i:%02i\n\n",1+mytime->tm_mday, 1+mytime->tm_mon,
            1900+mytime->tm_year, mytime->tm_hour, mytime->tm_min, mytime->tm_sec);

    GetPhysicallyInstalledSystemMemory(&pMemory);
    myMemory.dwLength = sizeof(myMemory);
    GlobalMemoryStatus(&myMemory);

    fprintf(OutputFile, "-- SYSTEM SPECS --\n\n");
    fprintf(OutputFile, "CPU: %s\n", cpuInstInfo.cpusignature);
    fprintf(OutputFile, "Cores: %i\n", SystemInfo.dwNumberOfProcessors);

#ifdef _DEBUG
	printf("-- SYSTEM SPECS --\n\n");
	printf("CPU: %s\n", cpuInstInfo.cpusignature);
	printf("Cores: %i\n", SystemInfo.dwNumberOfProcessors);
#endif

    if(cpuInstInfo.PFLAGS.PYSICAL_ADDRESS_E)
    {
        fprintf(OutputFile, "Physical Address Extension (PAE) Available (x86_64)\n");
#ifdef _DEBUG
        printf("Physical Address Extension (PAE) Available (x86_64)\n");
#endif
    }

    fprintf(OutputFile, "Other processor extensions: ");
    printf("Other processor extensions: ");

    if(cpuInstInfo.PFLAGS.LONGMODE)
    {
        fprintf(OutputFile, "lm ");
#ifdef _DEBUG
        printf("lm ");
#endif
    }

    if(cpuInstInfo.PFLAGS.MMX_INSTRUCTIONS)
    {
        fprintf(OutputFile, "mmx ");
#ifdef _DEBUG
        printf("mmx ");
#endif
    }

    if(cpuInstInfo.PFLAGS.EXT_MMX)
    {
        fprintf(OutputFile, "mmxext ");
#ifdef _DEBUG
        printf("mmxext ");
#endif
    }

    if(cpuInstInfo.PFLAGS.B3DNOW)
    {
        fprintf(OutputFile, "3dnow ");
#ifdef _DEBUG
        printf("3dnow ");
#endif
    }

    if(cpuInstInfo.PFLAGS.EXT_3DNOW)
    {
        fprintf(OutputFile, "3dnowext ");
#ifdef _DEBUG
        printf("3dnowext ");
#endif
    }

    if(cpuInstInfo.PFLAGS.MULTIPROCESSOR_CAPABLE)
    {
        fprintf(OutputFile, "mp ");
#ifdef _DEBUG
        printf("mp ");
#endif
    }

    fprintf(OutputFile, "\n\n -- RAM INFORMATION -- \n\n");
    fprintf(OutputFile, "Physical RAM: %I64u Mb\n",pMemory/1024);
    fprintf(OutputFile, "Available RAM: %i Mb\n",myMemory.dwAvailPhys / 1024 / 1024);
    fprintf(OutputFile, "Total PageFile: %i Mb\n",myMemory.dwTotalPageFile / 1024 / 1024);
    fprintf(OutputFile, "Available PageFile: %i Mb\n",myMemory.dwAvailPageFile / 1024 / 1024);
    fprintf(OutputFile, "Total Virtual Memory: %i Mb\n",myMemory.dwTotalVirtual / 1024 / 1024);
    fprintf(OutputFile, "Available Virtual Memory: %i Mb\n",myMemory.dwAvailVirtual / 1024 / 1024);

#ifdef _DEBUG
	printf("\n\n -- RAM INFORMATION -- \n\n");
	printf("Physical RAM: %I64u Mb\n",pMemory/1024);
    printf("Available RAM: %i Mb\n",myMemory.dwAvailPhys / 1024 / 1024);
    printf("Total PageFile: %i Mb\n",myMemory.dwTotalPageFile / 1024 / 1024);
	printf("Available PageFile: %i Mb\n",myMemory.dwAvailPageFile / 1024 / 1024);
    printf("Total Virtual Memory: %i Mb\n",myMemory.dwTotalVirtual / 1024 / 1024);
    printf("Available Virtual Memory: %i Mb\n",myMemory.dwAvailVirtual / 1024 / 1024);
#endif

	if(IsD3D(mydisplay))
	{
#ifdef _DEBUG
		printf("Using Direct 3D\n");
#endif
		fprintf(OutputFile, "Using Direct 3D\n");
		GetD3DInfo(mydisplay);
		
	}else{
#ifdef _DEBUG
		printf("Using OpenGL 3D\n");
#endif
		fprintf(OutputFile, "Using OpenGL\n");
		GetGLInfo(mydisplay);
	}

    return;
}