; /* ------------------------------------------------------------ */ ; Script Name : Singularity Updater (For Resistance Saga) ; Version : 3.0.4.5142 ; Author : Yandols Z'eon X ; Supported Platforms : Any 64-bit system ; /* ------------------------------------------------------------ */ #Include lib\ssdp-i.ahk #Include lib\hashvalidate.ahk #SingleInstance Ignore #NoEnv #NoTrayIcon ; #Warn ;-- Enable to display some debug information. SendMode Input SetWorkingDir %A_ScriptDir% ;; ---------------------------------- ;; Configuration Section -- Start ProductName = Resistance Saga ProductProcessName = rs-Launcher.exe AppName = Singularity Updater AppAuth = Yandols Zeon X UpdaterInternalName = Singularity Updater UpdaterInternalVersion = 3.0.4.5142 UpdaterProcessName = rs-Updater.exe UpdaterHost = https://kin.yandols.xyz UpdaterRemoteConfig = rs-fyp.ini UpdaterServerKeyprint = f3e371ec28b221c0ff46b45f44e1e647 CacheDir = %A_Temp% CachedPatchName = rs-gameupdate-package.vi ConfigFileName = csu-resistancesaga-2.vs AliasFileName = csu-multiupdate0.vs LauncherAlias = CSU_ VersionAlias = 3045141_ ;; Configuration Section -- End ;; Anything beyond this line should only need to be changed whenever things like libraries are updated and parameters need to be recoded. ;; ---------------------------------- ;; De-instancer for after program self-updating is completed. IfExist, %A_ScriptDir%\%LauncherAlias%_patchrstats.vs { goto PostUpdateCompletion return } ;; De-instancer (Compatibility Fix for updating from Pre-3.0.4 updater). IfExist, %A_ScriptDir%\PatchrCompletionNotice.vs { CompatibilityFixMode = 1 goto PostUpdateCompletion return } ;; ---------------------------------- ;; Instance the updater in cache folder to allow self-updating of the updater. If A_IsCompiled = 1 { If A_ScriptName != %LauncherAlias%%VersionAlias%%UpdaterProcessName% { ;Msgbox, 0, Debug Notice, Running in local directory FileCopy, %UpdaterProcessName%, %A_Temp%\%LauncherAlias%%VersionAlias%%UpdaterProcessName%, 1 FileDelete, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% FileAppend, %A_ScriptDir%, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% FileInstall, lib\UnFurl3.exe, %A_Temp%\FurlPatcher.exe, 1 Run, %A_Temp%\%LauncherAlias%%VersionAlias%%UpdaterProcessName% %1%, %A_ScriptDir%, UseErrorLevel If ErrorLevel ExitApp ExitApp } If A_ScriptName = %LauncherAlias%%VersionAlias%%UpdaterProcessName% { ;Msgbox, 0, Debug Notice, Running in alias directory FileRead, AliasWorkingDir, %LauncherAlias%%VersionAlias%%AliasFileName% } } ;; Added testing environment compatibility to speed up uncompiled testing Else If A_IsCompiled != 1 { ;Msgbox, 0, Debug Notice, Running in local directory (uncompiled) ;FileDelete, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% ;FileAppend, %A_ScriptDir%, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% ;FileRead, AliasWorkingDir, %LauncherAlias%%VersionAlias%%AliasFileName% AliasWorkingDir = %A_ScriptDir% } ;; ---------------------------------- ;; Check if /forceupdate paramter is passed. If 1 = /forceupdate goto ForceUpdate ;; ---------------------------------- ;; Normal operations - Update Prompt gosub ReadPatchFile If ExtUpdateNotice = true { If ReleaseDate != null NewUpdateMessage = An update for %ProductName% is available`, would you like to download the new update? `n`nThe latest version is %VersionToUse%, released %ReleaseDate% else NewUpdateMessage = An update for %ProductName% is available`, would you like to download the new update? `n`nThe latest version is %VersionToUse% } else NewUpdateMessage = An update for %ProductName% is available`, would you like to download the new update? Msgbox, 68, %AppName%, %NewUpdateMessage% IfMsgbox, Yes goto TaskUpdater else ExitApp return return ;; ---------------------------------- ;; Commence Downloader and Patcher Subroutines TaskUpdater: Process, Close, %ProductProcessName% ; Specific to RS only. Remove line here for other apps. If DownloadType = SingleFile ThePatchFile = %UpdaterHost%/%File% Else If DownloadType = URL ThePatchFile = %URL% Else ThePatchFile = %UpdaterHost%/%File% DownloadFile(ThePatchFile, CachedPatchName, True, True) sleep 500 ; Prevents thread overload Gui, Destroy ; Redundancy Backup Progress, Off ; Redundancy Backup fileToValidate := CachedPatchName LocalPatchHash := HashFile(fileToValidate,2) If LocalPatchHash != %FileHash% goto PatchValidationFailed sleep 250 ; Prevents thread overload Gui, Destroy ; Redundancy Backup Progress, Off ; Redundancy Backup ;Msgbox, 4, %AppName%, Patch file successfully downloaded`, install now? ;`n`nLocal Hash: %LocalPatchHash%`nRemote Hash: %FileHash% Msgbox, 0, %AppName%, Patch file successfully downloaded. Installation will now proceed. , 3 ;; ---------------------------------- ;; Handles Installing the downloaded patch. ;; Added in 5142 and removed Yes or No prompt since pressing No will always make the patch redownload again anyways. TaskInstallPatch: sleep 500 ; Prevents thread overload Process, Close, %ProductProcessName% sleep 100 ; Prevents thread overload IfExist, patched.log FileDelete, patched.log IfExist, patcherbat.bat FileDelete, patcherbat.bat FileInstall, lib\UnFurl3.exe, FurlPatcher.exe, 1 FileAppend, FurlPatcher.exe x -y "%CachedPatchName%" "%AliasWorkingDir%" >patched.log, patcherbat.bat FileSetAttrib, +R+H+S, FurlPatcher.exe FileSetAttrib, +R+H+S, patcherbat.bat RunWait, patcherbat.bat,, Hide UseErrorLevel ;RunWait, FurlPatcher.exe x -y "%CachedPatchName%" >patched.log,, UseErrorLevel If ErrorLevel { If ErrorLevel = 2 Msgbox, 16, %AppName%, A fatal error has occured. Try rebooting your computer and try again.`n[Error Code: %ErrorLevel%] Else If ErrorLevel = 3 Msgbox, 16, %AppName%, Patching has failed due to invalid checksum, the internal data is damaged. Open the file "patched.log" in a text editor before starting the updater again for error information.`n[Error Code: %ErrorLevel%] Else If ErrorLevel = 6 Msgbox, 16, %AppName%, Patching has failed due to one or more required files are locked by other processes such as anti-virus software. Open the file "patched.log" in a text editor before starting the updater again for error information.`n[Error Code: %ErrorLevel%] Else If ErrorLevel = 7 Msgbox, 16, %AppName%, Patching has failed. Open the file "patched.log" in a text editor before starting the updater again for error information.`n[Error Code: %ErrorLevel%] Else If ErrorLevel = 8 Msgbox, 16, %AppName%, A memory leak has been detected, patching has been aborted. Please reboot your computer and try again.`n[Error Code: %ErrorLevel%] Else If ErrorLevel = 9 Msgbox, 16, %AppName%, Patching has failed partially. The updater was not able to instance itself and is most likely not able to replace one or more needed files. Try running the updater again with administrator privileges.`n[Error Code: %ErrorLevel%] Else If ErrorLevel = 10 Msgbox, 16, %AppName%, Patching has failed. The downloaded patch file seems to have disappeared. Try running the updater again with administrator privileges.`n[Error Code: %ErrorLevel%] Else If ErrorLevel = 11 Msgbox, 16, %AppName%, Patching has failed. The downloaded patch file is not a %ProductName% patch. Please contact the author to have this fixed asap.`n[Error Code: %ErrorLevel%] Else Msgbox, 16, %AppName%, Patching has failed. Open the file "patched.log" in a text editor before starting the updater again for error information.`n[Error Code: %ErrorLevel%] DontDeleteLogFile = 1 PatchHasFailed = 1 } sleep 100 ; Prevents thread overload FileSetAttrib, -R-S, FurlPatcher.exe FileSetAttrib, -R-S, patcherbat.bat FileDelete, FurlPatcher.exe FileDelete, patcherbat.bat FileDelete, %CachedPatchName% If DontDeleteLogFile != 1 FileDelete, patched.log If PatchHasFailed = 1 ExitApp FileAppend, STATUS_COMPLETED, %AliasWorkingDir%\%LauncherAlias%_patchrstats.vs FileSetAttrib, +H+S, %LauncherAlias%_patchrstats.vs sleep 150 ; Prevents thread overload Run, %AliasWorkingDir%\%UpdaterProcessName%,, UseErrorLevel If ErrorLevel { Msgbox, 16, %AppName%, Failed to switch instances. This may be caused by an invalid or failed update attempt. ExitApp } ; ;If PatchHasFailed != 1 ; ;Msgbox, 64, %AppName%, Patching completed. You are now running on the latest version of %ProductName%! ExitApp return ;; ---------------------------------- ;; Error handling when downloaded patch file's hash does not match remote hash file PatchValidationFailed: sleep 100 ; Prevents thread overload Msgbox, 16, %AppName%, Warning: Patch file validation has failed! The file that was downloaded may be corrupted, please try running the updater again. If problem persists, please contact the author to have this fixed asap. ExitApp return ;; ---------------------------------- ;; De-instancing handler and post update completion notice. PostUpdateCompletion: If CompatibilityFixMode = 1 { ;IniRead, VersionToUse, %CacheDir%/clayupdate-rmtclock.vc, SingularityUpdater, VersionToUse, null FileSetAttrib, -R+H+S, PatchrCompletionNotice.vs sleep 100 ; Prevents thread overload } IniRead, VersionToUse, %CacheDir%/%ConfigFileName%, SingularityUpdater, VersionToUse, null FileSetAttrib, -R+H+S, %LauncherAlias%_patchrstats.vs sleep 100 ; Prevents thread overload Msgbox, 64, %AppName%, Patching completed. Your version of %ProductName% has been updated to version %VersionToUse%! FileSetAttrib, -R-S, FurlPatcher.exe FileSetAttrib, -R-S, patcherbat.bat FileDelete, FurlPatcher.exe FileDelete, patcherbat.bat FileDelete, %CachedPatchName% FileDelete, %AliasFileName% FileDelete, %LauncherAlias%_patchrstats.vs If DontDeleteLogFile != 1 FileDelete, patched.log FileDelete, %LauncherAlias%%VersionAlias%%AliasFileName% FileDelete, %LauncherAlias%%VersionAlias%%UpdaterProcessName% If CompatibilityFixMode = 1 { FileDelete, %CachedPatchName% FileDelete, %AliasFileName% FileDelete, PatchrCmd.vs FileDelete, PatchrCompletionNotice.vs FileDelete, %LauncherAlias%%VersionAlias%PatchrCmd.vs FileDelete, %LauncherAlias%%VersionAlias%teal-updater.exe } Run, %A_ScriptDir%\%ProductProcessName%, UseErrorLevel ExitApp return ;; ---------------------------------- ;; Force Update Handler (Specific to RS only but may be adapted into main SU) ForceUpdate: IsForceUpdating = 1 If A_IsCompiled = 1 { If A_ScriptName != %LauncherAlias%%VersionAlias%%UpdaterProcessName% { ; Running in local directory FileCopy, %UpdaterProcessName%, %A_Temp%\%LauncherAlias%%VersionAlias%%UpdaterProcessName%, 1 FileDelete, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% FileAppend, %A_ScriptDir%, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% FileInstall, lib\UnFurl3.exe, %A_Temp%\FurlPatcher.exe, 1 Run, %A_Temp%\%LauncherAlias%%VersionAlias%%UpdaterProcessName%, %A_ScriptDir%, UseErrorLevel If ErrorLevel ExitApp ExitApp } If A_ScriptName = %LauncherAlias%%VersionAlias%%UpdaterProcessName% { ; Running in alias directory FileRead, AliasWorkingDir, %LauncherAlias%%VersionAlias%%AliasFileName% } } ;; Added testing environment compatibility to speed up uncompiled testing Else If A_IsCompiled != 1 AliasWorkingDir = %A_ScriptDir% gosub ReadPatchFile goto TaskUpdater Return ;; ---------------------------------- ;; Read the patch info downloaded from the remote config file ReadPatchFile: ;; Always force redownload the remote config file IfExist, %CacheDir%/%ConfigFileName% FileDelete, %CacheDir%/%ConfigFileName% UrlDownloadToFile, %UpdaterHost%/%UpdaterRemoteConfig%, %CacheDir%/%ConfigFileName% ;; Read Remote Config File IniRead, RetailVersion, %CacheDir%/%ConfigFileName%, SingularityUpdater, RetailVersion, null IniRead, VersionToUse, %CacheDir%/%ConfigFileName%, SingularityUpdater, VersionToUse, null IniRead, ReleaseDate, %CacheDir%/%ConfigFileName%, SingularityUpdater, ReleaseDate, null IniRead, ExtUpdateNotice, %CacheDir%/%ConfigFileName%, SingularityUpdater, ExtUpdateNotice, false IniRead, OCVersion, %CacheDir%/%ConfigFileName%, SingularityUpdater, OCVersion, 0 IniRead, Identifier, %CacheDir%/%ConfigFileName%, SingularityUpdater, Identifier, 0 IniRead, Keyprint, %CacheDir%/%ConfigFileName%, SingularityUpdater, Keyprint, 0 IniRead, Optimization, %CacheDir%/%ConfigFileName%, SingularityUpdater, Optimization, null IniRead, DownloadType, %CacheDir%/%ConfigFileName%, SingularityUpdater, DownloadType, SingleFile IniRead, File, %CacheDir%/%ConfigFileName%, SingularityUpdater, File, null IniRead, URL, %CacheDir%/%ConfigFileName%, SingularityUpdater, URL, null IniRead, FileHash, %CacheDir%/%ConfigFileName%, SingularityUpdater, FileHash, 0 ;; Make sure the remote config file is the correct one by validating keyprint. If Keyprint != %UpdaterServerKeyprint% { Msgbox, 16, %AppName%, Patch server authentication failed. ExitApp } ;; Make Forced Updating stop the thread here so that the prompts don't show up. If IsForceUpdating = 1 { If A_ScriptName != %LauncherAlias%%VersionAlias%%UpdaterProcessName% { FileDelete, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% FileAppend, %A_ScriptDir%, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% Return } Return } ;; Do not prompt a download if existing version is the same as latest [Compiled Version] If A_IsCompiled = 1 { If A_ScriptName != %LauncherAlias%%VersionAlias%%UpdaterProcessName% { ;Msgbox, 0, Debug Notice, Running in local directory FileDelete, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% FileAppend, %A_ScriptDir%, %A_Temp%\%LauncherAlias%%VersionAlias%%AliasFileName% ;FileGetVersion, ExistingVersion, %ProductProcessName% FileRead, ExistingVersion, win64\rversion.txt If ExistingVersion = %VersionToUse% { Msgbox, 64, %AppName%, You already have the latest version currently available. ExitApp } return } If A_ScriptName = %LauncherAlias%%VersionAlias%%UpdaterProcessName% { ;Msgbox, 0, Debug Notice, Running in alias directory FileRead, AliasWorkingDir, %LauncherAlias%%VersionAlias%%AliasFileName% ;FileGetVersion, ExistingVersion, %AliasWorkingDir%\%ProductProcessName% FileRead, ExistingVersion, %AliasWorkingDir%\win64\rversion.txt If CSU_NewVersion != %ProductVer% If ExistingVersion = %VersionToUse% { Msgbox, 64, %AppName%, You already have the latest version currently available. ExitApp } return } } ;; Do not prompt a download if existing version is the same as latest [Uncompiled Version] ;FileGetVersion, ExistingVersion, %ProductProcessName% FileRead, ExistingVersion, win64\rversion.txt If ExistingVersion = %VersionToUse% { Msgbox, 64, %AppName%, You already have the latest version currently available. ExitApp } return ;; ---------------------------------- ;; Nullify Progress Window Standard Closure Calls GuiClose: GuiExit: return