Grand Theft Auto V

Grand Theft Auto V

Not enough ratings
Script for making GTAV backups (for mods) (batch)
By Urik
NOTE: I've updated the scripts to work with new launcher.

A pair of batch scripts I made for backing up game files so that it can be downgraded when an update comes out and breaks ScriptHookV / mods functionality.
   
Award
Favorite
Favorited
Unfavorite
opening words
These are batch scripts I wrote and use myself to backup, check and downgrade / re-update my game when needed.
changelog
  • MAR-31-2020 - added GTAVLanguageSelect.exe & PlayGTAV.exe to all scripts
  • DEC-11-2019 - tweaked input handler in "Downgrade" script
  • SEP-20-2019 - updated some mechanics of the scripts due Rockstar Game Launcher update.
    • scripts now detect game version not from log, but directly from gta5.exe, which is more reliable
    • added "downgrade" script
  • JUN-24-2019 - tweaks to "Check backups" script: during backup-to-backup comparison, it now prints = and != symbols with file names on both sides.
TL;DR summary
A short breakdown / how-to:
  • create a text file anywhere, open with text editor, paste the code, save, rename .txt to .bat
  • run backup.bat to backup files. If the game is installed in C:\Program Files\ and the script can't copy files, run it as administrator ( right-click > "run as administrator" )
  • when the game eventually updates, run backup.bat to make a new backup
  • you can then downgrade / re-upgrade (manually) using files from backupfolder ( <gamefolder>/_backup by default )
  • use check_backups.bat to check differences between installed and backed up files, or to determine which files have been updated between backups
  • use downgrade.bat to downgrade to previous backed up version / re-update to latest backup version
Introduction
As you know, every now and then an update comes out and is followed by a week long wait for a new build of Alex Blade's ScriptHookV and inability to use single player mods.
I initially wrote these scripts for myself, over time they became sophisticated enough (in my eyes) for a public release. While I'm not any sort of programmer - not even in the slightest - I've made the effort to keep the code comprehensible and maintain simplicity, user-friendliness and error proofing.

Both scripts quoted here might ( and likely will ) receive corrections / fixes / changes without it being mentioned in the changelog.
Files that are backed up
It all centers around these files:
  • GTA5.exe
  • GTAVLauncher.exe
  • GTAVLanguageSelect.exe
  • PlayGTAV.exe
  • steam_api64.dll
  • update\update.rpf

If you're new to this, there's a very good detailed thread on gta5-mods called "Quick start guide to modding Grand Theft Auto V"[forums.gta5-mods.com], which includes a lot of basic how-to and info on handling game files and mods, and touches on this topic as well.

It's worth mentioning though that most of the time, usually, when the game updates, only two of these four files are updated: the main executable (GTA5.exe) and update\update.rpf
It is less common for GTAVLauncher.exe to get updated; whereas steam_api64.dll , apparently, hasn't been updated since 2017. Nevertheless, my script includes all four files, just for a good measure, and because there's always a chance eventually even steam_api64.dll gets updated.
On another note, SC / Non-Steam version of the game does not have steam_api64.dll (duh), but my script takes that into account.

Where to place the scripts and how to run them
Since scripts are not directory-dependent, they can be placed anywhere on your pc.

Common Functions: auto-detect
Both scripts scan log file generated by the launcher/game to figure out the installation folder and platform. The game version is determined with wmic command output for gta5.exe. The log file is:
%userprofile%\Documents\Rockstar Games\Launcher\launcher.log
Log file is auto-generated each time the game is run. Hence, the info it contains is always from the last run.
If the script reads from log file that it isn't a Steam version of the game, it will exclude steam_api64.dll from its operations.
Common Settings: %backupfolder%
Backupfolder is a variable set in the beginning of the script(s) that can be changed by user.
By default, it's set to
set backupfolder=gamefolder\_backup
The script is programmed to replace gamefolder with the actual detected gamefolder.
However, you can set a fully custom path, like
set backupfolder=E:\gta5_backups
or
set backupfolder="E:\my backups\gta5"
Note how in the second example I added " " marks because there are spaces in the path

BOTH SCRIPTS should have backupfolder set to the same path, as the second script that checks the backed-up files relies on files and folder structure that has been set by the first script.
Script #1 "backup.bat"
@echo off setLocal EnableDelayedExpansion :: ------------------------ SET VARIABLES (don't touch) ---------------------------- set LauncherFolder="%userprofile%\Documents\Rockstar Games\Launcher" :: ------------------------ USER OPTIONS ---------------------------------------------- :: gamefolder will be replaced by actual game folder. BUT, you can put a completely custom path here, like "F:\my backups\gta_backup" , BUT please use " marks if your path has spaces! set backupfolder=gamefolder\_backup :: open backup folder in explorer once finished set open_explorer_window=true :: ---------------------------------------------------------------------------------------- :Start :GetGameFolder if exist %LauncherFolder% ( cd /d %LauncherFolder% if exist launcher.log ( for /f tokens^=2^ delims^=^" %%i in ('type launcher.log ^|find "GTA5.exe"') do set "exepath=%%i" if "!exepath!"=="" ( for /f "tokens=1 delims=" %%i in ('type launcher.log ^|find "Grand Theft Auto V"') do ( set "_p=%%i" set "_p=!_p:*Location: =!" set gamepath="!_p!" set "exepath=!_p!\gta5.exe" ) if "!gamepath!"=="" echo ERROR: COULD NOT DETECT GAMEFOLDER & pause & goto :eof ) else ( set gamepath="!exepath:\GTA5.exe=!" ) if exist !gamepath! ( set "gamefolder=!gamepath!" & echo Detected Game Folder !gamepath! & echo. ) else ( echo ERROR: COULD NOT DETECT GAMEFOLDER & pause & goto :eof ) ) ) else ( echo Warning: CAN'T FIND LAUNCHER FOLDER %LauncherFolder% & pause & goto :eof ) :GetVersion set exepath2=!exepath:\=\\! for /f "tokens=*" %%V in ( ' wmic datafile where "name='!exepath2!'" get version ' ) do ( for /F "delims=" %%A IN ("%%V") do ( if not "%%V"=="" ( if not "%%V"=="Version" set "version=%%V" ) ) ) set "version=%version: =%" if '!version!'=='' ( echo ERROR: COULD NOT DETECT VERSION & pause & goto :eof ) else ( echo Game Version: %version% ) :GetPlatform cd /d %LauncherFolder% if exist launcher.log ( for /f "tokens=*" %%i in ('type launcher.log ^|find "Running in Steam mode"') do set "Is_Steam=true" ) else ( echo ERROR: CAN'T FIND %cd%\launcher.log ) :SetFileList if defined is_steam ( set files_tocopy=GTA5.exe,GTAVLauncher.exe,GTAVLanguageSelect.exe,PlayGTAV.exe,steam_api64.dll,update\update.rpf ) else ( set files_tocopy=GTA5.exe,GTAVLauncher.exe,GTAVLanguageSelect.exe,PlayGTAV.exe,update\update.rpf ) :SetBackupFolder set backupfolder=%backupfolder:gamefolder=!gamefolder!% set backupfolder=%backupfolder:"=% set backupfolder="%backupfolder%\%version%" if NOT exist %backupfolder% ( mkdir %backupfolder% || ( CALL :ReportMkDirFailure %backupfolder% & pause & goto :eof ) ) echo Backup Folder %backupfolder% & echo. :IterateFiles set copycount=0 set failcount=0 for %%F in (%files_tocopy%) do ( if exist %backupfolder%\%%F ( CALL :AlreadyBackedUp %%F ) else ( CALL :CopyFile %%F ) ) :Finish CALL :ReportALL echo. pause if %open_explorer_window%==true explorer %backupfolder% goto :eof :: -------------------------------------------------------------------------------------------------------------------------- :CopyFile xcopy /Y %gamefolder%\%1 %backupfolder%\%1* if !errorlevel!==0 ( CALL :LogSuccess %1 ) else ( CALL :LogFailure %1 ) goto :eof :AlreadyBackedUp echo %1 - already backed up goto :eof :LogFailure if "!failedfiles!"=="" ( set "failedfiles=%1" ) else ( set "failedfiles=!failedfiles!, %1" ) set /a "failcount=!failcount!+1" goto :eof :LogSuccess if "!copiedfiles!"=="" ( set "copiedfiles=%1" ) else ( set "copiedfiles=!copiedfiles!, %1" ) set /a "copycount=!copycount!+1" goto :eof :ReportALL CALL :ReportSuccess CALL :ReportFailure goto :eof :ReportMkDirFailure echo --------------------------------------------------------------------------------------- echo ERROR echo CAN'T CREATE FOLDER %1 echo CHECK PERMISSIONS echo --------------------------------------------------------------------------------------- goto :eof :ReportFailure if %failcount% GTR 0 ( if %failcount% GTR 1 (set filesplural=files) else (set filesplural=file) echo ------------------------------------------------------------------------ echo FAILED TO COPY %failcount% !filesplural!: !failedfiles! echo ------------------------------------------------------------------------ ) set failcount=0 set failedfiles= goto :eof :ReportSuccess if %copycount% GTR 0 ( if %copycount% GTR 1 (set filesplural=files) else (set filesplural=file) echo ------------------------------------------------------------------------ echo %copycount% !filesplural! copied: !copiedfiles! echo ------------------------------------------------------------------------ ) set copycount=0 set copiedfiles= goto :eof

This is the main script that does the backup process.
Basic breakdown of script steps:
  • auto-detection of game folder / platform / logged version
  • copying of the files to backupfolder
  • (optional) opens backupfolder in windows explorer

As explained in the previous sections, it will automatically detect game folder, platform and game version.

Note: if your game is installed under C:\Program Files\ ... , and if your backup folder is set to be inside gamefolder ( which is the default setting ), then you'd have to run the backup script as administrator in order for it to have write access.

This is how the output of the script looks for the first 4 lines - the auto-detection prints:
-
Then it copies the files and reports success or errors:
-
Finally, once finished, it pauses/waits for you to press any key, and if
%open_explorer_window% setting is enabled ( it's in the start of the script )
set open_explorer_window=true
opens an explorer window for the backup subfolder that is named after the game version:
-

If you run script again, it will see that it already has copied the files of this version ( it will look for a subfolder for that game version and check if the files exist there ) and report that:
-
Note that it only checks if each file exists, I did not deem it necessary to use checksum or creation date checks.


Error reporting:
In case of errors, for example, if the script can't find a folder, or doesn't have write access - you would get prints like these:
Script #2 "check_backups.bat"
@echo off setLocal EnableDelayedExpansion :: ------------------------ SET VARIABLES (don't touch) ---------------------------- set LauncherFolder="%userprofile%\Documents\Rockstar Games\Launcher" :: ------------------------ USER OPTIONS ---------------------------------------------- :: gamefolder will be replaced by actual game folder. BUT, you can put a completely custom path here, like "F:\my backups\gta_backup" , BUT please use " marks if your path has spaces! set backupfolder=gamefolder\_backup :: ---------------------------------------------------------------------------------------- :Start :GetGameFolder if exist %LauncherFolder% ( cd /d %LauncherFolder% if exist launcher.log ( for /f tokens^=2^ delims^=^" %%i in ('type launcher.log ^|find "GTA5.exe"') do set "exepath=%%i" if "!exepath!"=="" ( for /f "tokens=1 delims=" %%i in ('type launcher.log ^|find "Grand Theft Auto V"') do ( set "_p=%%i" set "_p=!_p:*Location: =!" set gamepath="!_p!" set "exepath=!_p!\gta5.exe" ) if "!gamepath!"=="" echo ERROR: COULD NOT DETECT GAMEFOLDER & pause & goto :eof ) else ( set gamepath="!exepath:\GTA5.exe=!" ) if exist !gamepath! ( set "gamefolder=!gamepath!" & echo Detected Game Folder !gamepath! & echo. ) else ( echo ERROR: COULD NOT DETECT GAMEFOLDER & pause & goto :eof ) ) ) else ( echo Warning: CAN'T FIND LAUNCHER FOLDER %LauncherFolder% & pause & goto :eof ) :GetVersion set exepath2=!exepath:\=\\! for /f "tokens=*" %%V in ( ' wmic datafile where "name='!exepath2!'" get version ' ) do ( for /F "delims=" %%A IN ("%%V") do ( if not "%%V"=="" ( if not "%%V"=="Version" set "version=%%V" ) ) ) set "version=%version: =%" if '!version!'=='' ( echo ERROR: COULD NOT DETECT VERSION & pause & goto :eof ) else ( echo Game Version: %version% ) :GetPlatform cd /d %LauncherFolder% if exist launcher.log ( for /f "tokens=*" %%i in ('type launcher.log ^|find "Running in Steam mode"') do set "Is_Steam=true" ) else ( echo ERROR: CAN'T FIND %cd%\launcher.log ) :SetFileList if defined is_steam ( set files_tocopy=GTA5.exe,GTAVLauncher.exe,GTAVLanguageSelect.exe,PlayGTAV.exe,steam_api64.dll,update\update.rpf ) else ( set files_tocopy=GTA5.exe,GTAVLauncher.exe,GTAVLanguageSelect.exe,PlayGTAV.exe,update\update.rpf ) :CheckBackupFolder set backupfolder=%backupfolder:gamefolder=!gamefolder!% set backupfolder=%backupfolder:"=% set backupfolder="%backupfolder%" if exist %backupfolder% ( echo. & echo Backup Folder %backupfolder% set bkup_count=0 cd /d %backupfolder% for /f "tokens=* delims= " %%A in ( ' dir /b /-p /a:d /o:-n /t:w *.* ' ) do ( set "var=" & for /f "delims=.0123456789" %%i in ('echo %%A') do set var=%%i if "!var!"=="" ( set "var=" set /a bkup_count=!bkup_count!+1 if not "!backups!"=="" ( set "backups=!backups!,%%A") else ( set "backups=%%A") echo found backup %%A ) ) if !bkup_count!==0 echo NO BACKUPS HAVE BEEN FOUND. EXITING. & pause & goto :eof ) else ( echo ERROR: CAN'T FIND BACKUPFOLDER & pause & goto :eof ) :CheckGameFiles echo. & echo Game Folder files: & echo. echo GTA5.exe = %version% (actual version) for %%F in (%files_tocopy%) do ( if /i not %%F==gta5.exe ( for /f "delims=" %%i in ('certutil -v -hashfile %gamefolder%\%%F MD5 ^| find /i /v "md5" ^| find /i /v "certutil"') do set "hash1=%%i" CALL :CompareFileToBackups %%F ) ) :CompareAllBackups set bkup1= cd /d %backupfolder% echo. & echo. & echo Comparing Files Between Backups... for %%A in (%backups%) do ( if '!bkup1!'=='' ( set bkup1=%%A ) else ( CALL :Compare_bkup2bkup !bkup1! %%A set bkup1=%%A ) ) :Finished echo. & echo. echo -------------------------------------------------- echo Finished. echo -------------------------------------------------- echo. pause goto :eof :Compare_bkup2bkup cd /d %backupfolder% echo. echo -------------------------------------------------- echo %1 ^<=^> %2 echo. for %%F in (%files_tocopy%) do ( set hash1= set hash2= for /f "delims=" %%i in ('certutil -v -hashfile %1\%%F MD5 ^| find /i /v "md5" ^| find /i /v "certutil"') do set "hash1=%%i" for /f "delims=" %%i in ('certutil -v -hashfile %2\%%F MD5 ^| find /i /v "md5" ^| find /i /v "certutil"') do set "hash2=%%i" if !hash1!==!hash2! ( echo %%F = %%F ) else ( echo %%F ^^!= %%F ) ) goto :eof :CompareFileToBackups cd /d %backupfolder% for %%A in (%backups%) do ( for /f "delims=" %%i in ('certutil -v -hashfile %backupfolder%\%%A\%1 MD5 ^| find /i /v "md5" ^| find /i /v "certutil"') do set "hash2=%%i" if !hash1!==!hash2! ( echo %1 = %%A (as compared to backups^) goto :eof ) ) echo %1 = unknown goto :eof

This is a much more recent script, built as a variation of the first one.
This script checks previously made backups and compares files.
Basic breakdown of script steps:
  • auto-detection of game folder / platform / version
  • scans backupfolder and prints found backed-up versions (subfolders)
  • compares files in gamefolder against backups, starting from the newest
  • compares files between pairs of backups, starting from the newest

-
This script uses CertUtil command to get md5 hashes of files for comparison.
As the first script, it loops through same four files
( GTA5.exe,GTAVLauncher.exe,steam_api64.dll,update\update.rpf )

First, it checks files in gamefolder against backups found in backupfolder,
by iterating subfolders within backupfolder starting from the newest version ( they are sorted in reverse-alphanumeric order for that ). When a match is found, it prints the version that was matched next to the file:
It should be noted that due to the mechanics of the script, it only checks until first match.
Also, if no match is found for a file, it will print "unknown"
-
Then, it does the same comparison between pairs of backup subfolders, starting from the newest:
= means the files are same, while != means they are different
-
Script #3 "Downgrade.bat"
@echo off setLocal EnableDelayedExpansion :: ------------------------ SET VARIABLES (don't touch) ---------------------------- set LauncherFolder="%userprofile%\Documents\Rockstar Games\Launcher" :: ------------------------ USER OPTIONS ---------------------------------------------- :: gamefolder will be replaced by actual game folder. BUT, you can put a completely custom path here, like "F:\my backups\gta_backup" , BUT please use " marks if your path has spaces! set backupfolder=gamefolder\_backup set use_checksum=true :: ---------------------------------------------------------------------------------------- :Start :GetGameFolder if exist %LauncherFolder% ( cd /d %LauncherFolder% if exist launcher.log ( for /f tokens^=2^ delims^=^" %%i in ('type launcher.log ^|find "GTA5.exe"') do set "exepath=%%i" if "!exepath!"=="" ( for /f "tokens=1 delims=" %%i in ('type launcher.log ^|find "Grand Theft Auto V"') do ( set "_p=%%i" set "_p=!_p:*Location: =!" set gamepath="!_p!" set "exepath=!_p!\gta5.exe" ) if "!gamepath!"=="" echo ERROR: COULD NOT DETECT GAMEFOLDER & pause & goto :eof ) else ( set gamepath="!exepath:\GTA5.exe=!" ) if exist !gamepath! ( set "gamefolder=!gamepath!" & echo Detected Game Folder !gamepath! & echo. ) else ( echo ERROR: COULD NOT DETECT GAMEFOLDER & pause & goto :eof ) ) ) else ( echo Warning: CAN'T FIND LAUNCHER FOLDER %LauncherFolder% & pause & goto :eof ) :GetVersion set exepath2=!exepath:\=\\! for /f "tokens=*" %%V in ( ' wmic datafile where "name='!exepath2!'" get version ' ) do ( for /F "delims=" %%A IN ("%%V") do ( if not "%%V"=="" ( if not "%%V"=="Version" set "version=%%V" ) ) ) set "version=%version: =%" if '!version!'=='' ( echo ERROR: COULD NOT DETECT VERSION & pause & goto :eof ) else ( echo Game Version: %version% ) :GetPlatform cd /d %LauncherFolder% if exist launcher.log ( for /f "tokens=*" %%i in ('type launcher.log ^|find "Running in Steam mode"') do set "Is_Steam=true" ) else ( echo ERROR: CAN'T FIND %cd%\launcher.log ) :SetFileList if defined is_steam ( set files_tocopy=GTA5.exe,GTAVLauncher.exe,GTAVLanguageSelect.exe,PlayGTAV.exe,steam_api64.dll,update\update.rpf ) else ( set files_tocopy=GTA5.exe,GTAVLauncher.exe,GTAVLanguageSelect.exe,PlayGTAV.exe,update\update.rpf ) :CheckBackupFolder set backupfolder=%backupfolder:gamefolder=!gamefolder!% set backupfolder=%backupfolder:"=% set backupfolder="%backupfolder%" if exist %backupfolder% ( echo. & echo Backup Folder %backupfolder% & echo. set bkup_count=0 set lastbkup_counter=0 cd /d %backupfolder% for /f "tokens=* delims= " %%A in ( ' dir /b /-p /o:-n /t:w *.* ' ) do ( set "var=" & for /f "delims=.0123456789" %%i in ('echo %%A') do set var=%%i if "!var!"=="" ( set "var=" set /a bkup_count=!bkup_count!+1 if !bkup_count!==1 set "last_backup=%%A" if !bkup_count!==2 set "prev_backup=%%A" if not "!backups!"=="" ( set "backups=!backups!,%%A") else ( set "backups=%%A") echo found backup %%A ) ) if !bkup_count!==0 echo NO BACKUPS HAVE BEEN FOUND. EXITING. & pause & goto :eof ) else ( echo ERROR: CAN'T FIND BACKUPFOLDER & pause & goto :eof ) :CheckEXE if %version%==%last_backup% ( set "do_downgrade=true" ) else ( if %version% GTR %last_backup% ( echo. & echo New version %version% , not yet backed up. Please backup first! & echo. & pause & goto :eof ) else ( if not exist %backupfolder%\%version% ( echo. & echo Old version %version% , no backup. Please back that up first! & echo. & pause & goto :eof) ) ) :Prompt echo. if defined do_downgrade ( set "msg=Downgrade from %version% to version %prev_backup%" ) else ( set "msg=Re-Update from %version% to version %last_backup%" ) set proceed= set /p "proceed=%msg% (Y/N)?" if not "!proceed!"=="" ( set "proceed=!proceed: =!" for /f "delims=yYnN" %%A in ('echo !proceed!') do goto :Prompt ) if /i !proceed!==y goto Process if /i !proceed!==n goto :eof goto :Prompt :Process if defined do_downgrade ( CALL :IterateFiles %prev_backup%) else ( CALL :IterateFiles %last_backup%) :Report if not "!copycount!"=="" ( echo. echo --------------------------------------------------------------------------------------- echo Copied !copycount! files: !copiedfiles! echo --------------------------------------------------------------------------------------- ) if not "!failcount!"=="" ( echo. echo --------------------------------------------------------------------------------------- echo FAILED TO COPY !failcount! files: !failedfiles! echo --------------------------------------------------------------------------------------- ) echo. pause goto :eof :IterateFiles echo. for %%F in (%files_tocopy%) do ( if %use_checksum%==true ( for /f "delims=" %%i in ('certutil -v -hashfile %gamefolder%\%%F MD5 ^| find /i /v "md5" ^| find /i /v "certutil"') do set "hash1=%%i" for /f "delims=" %%i in ('certutil -v -hashfile %backupfolder%\%1\%%F MD5 ^| find /i /v "md5" ^| find /i /v "certutil"') do set "hash2=%%i" if not !hash1!==!hash2! CALL :CopyFileFromBackup %1 %%F ) else ( CALL :CopyFileFromBackup %1 %%F) ) goto :eof :CopyFileFromBackup echo. & echo %2 copy %backupfolder%\%1\%2 %gamefolder%\%2 if "!errorlevel!"=="0" ( CALL :LogSuccess %2) else ( CALL :LogFailure %2) goto :eof :LogFailure if "!failcount!"=="" ( set "failcount=1" ) else ( set /a "failcount=!failcount!+1" ) if "!failedfiles!"=="" ( set "failedfiles=%1" ) else ( set "failedfiles=!failedfiles!, %1" ) goto :eof :LogSuccess if "!copycount!"=="" ( set "copycount=1" ) else ( set /a "copycount=!copycount!+1" ) if "!copiedfiles!"=="" ( set "copiedfiles=%1" ) else ( set "copiedfiles=!copiedfiles!, %1" ) goto :eof

This script downgrades the game to previous backed up version.

It works as a toggle - if it detects that gta5.exe version matches the last backup, it will offer to downgrade to previous version. Otherwise, if newer backup available, it will offer to re-update.
The script also uses hash-comparison, so it will only copy files that are different ( for that reason, it freezes up on update.rpf for a few seconds - to calculate the hash ).

If the script detects that the gta5.exe version is newer or older than any existing backups, it will not progress further and print a warning suggesting to back up current version.

Final Words
Well, I hope it wasn't all too convoluted and perhaps is useful to someone.

1 Comments
MARK2580 19 Jun, 2019 @ 12:48pm 
ой легче файлы скопипастить ручками