├── .gitattributes ├── .gitignore ├── .gitmodules ├── appveyor.yml ├── data ├── 7za.exe ├── III.VC.SA.SaveLoader.ini └── release.bat ├── license ├── premake5.bat ├── premake5.exe ├── premake5.lua ├── readme.md └── source ├── GTASNPTestApp.cpp ├── VersionInfo.h ├── VersionInfo.rc ├── dllmain.cpp ├── stdafx.cpp ├── stdafx.h └── targetver.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | data/**/*.asi 7 | data/**/*.zip 8 | 9 | # User-specific files 10 | *.suo 11 | *.user 12 | *.userosscache 13 | *.sln.docstates 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Build results 19 | [Dd]ebug/ 20 | [Dd]ebugPublic/ 21 | [Rr]elease/ 22 | [Rr]eleases/ 23 | x64/ 24 | x86/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | [Bb]uild/ 30 | 31 | # Visual Studio 2015 cache/options directory 32 | .vs/ 33 | # Uncomment if you have tasks that create the project's static files in wwwroot 34 | #wwwroot/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # .NET Core 50 | project.lock.json 51 | project.fragment.lock.json 52 | artifacts/ 53 | **/Properties/launchSettings.json 54 | 55 | *_i.c 56 | *_p.c 57 | *_i.h 58 | *.ilk 59 | *.meta 60 | *.obj 61 | *.pch 62 | *.pdb 63 | *.pgc 64 | *.pgd 65 | *.rsp 66 | *.sbr 67 | *.tlb 68 | *.tli 69 | *.tlh 70 | *.tmp 71 | *.tmp_proj 72 | *.log 73 | *.vspscc 74 | *.vssscc 75 | .builds 76 | *.pidb 77 | *.svclog 78 | *.scc 79 | 80 | # Chutzpah Test files 81 | _Chutzpah* 82 | 83 | # Visual C++ cache files 84 | ipch/ 85 | *.aps 86 | *.ncb 87 | *.opendb 88 | *.opensdf 89 | *.sdf 90 | *.cachefile 91 | *.VC.db 92 | *.VC.VC.opendb 93 | 94 | # Visual Studio profiler 95 | *.psess 96 | *.vsp 97 | *.vspx 98 | *.sap 99 | 100 | # TFS 2012 Local Workspace 101 | $tf/ 102 | 103 | # Guidance Automation Toolkit 104 | *.gpState 105 | 106 | # ReSharper is a .NET coding add-in 107 | _ReSharper*/ 108 | *.[Rr]e[Ss]harper 109 | *.DotSettings.user 110 | 111 | # JustCode is a .NET coding add-in 112 | .JustCode 113 | 114 | # TeamCity is a build add-in 115 | _TeamCity* 116 | 117 | # DotCover is a Code Coverage Tool 118 | *.dotCover 119 | 120 | # Visual Studio code coverage results 121 | *.coverage 122 | *.coveragexml 123 | 124 | # NCrunch 125 | _NCrunch_* 126 | .*crunch*.local.xml 127 | nCrunchTemp_* 128 | 129 | # MightyMoose 130 | *.mm.* 131 | AutoTest.Net/ 132 | 133 | # Web workbench (sass) 134 | .sass-cache/ 135 | 136 | # Installshield output folder 137 | [Ee]xpress/ 138 | 139 | # DocProject is a documentation generator add-in 140 | DocProject/buildhelp/ 141 | DocProject/Help/*.HxT 142 | DocProject/Help/*.HxC 143 | DocProject/Help/*.hhc 144 | DocProject/Help/*.hhk 145 | DocProject/Help/*.hhp 146 | DocProject/Help/Html2 147 | DocProject/Help/html 148 | 149 | # Click-Once directory 150 | publish/ 151 | 152 | # Publish Web Output 153 | *.[Pp]ublish.xml 154 | *.azurePubxml 155 | # TODO: Comment the next line if you want to checkin your web deploy settings 156 | # but database connection strings (with potential passwords) will be unencrypted 157 | *.pubxml 158 | *.publishproj 159 | 160 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 161 | # checkin your Azure Web App publish settings, but sensitive information contained 162 | # in these scripts will be unencrypted 163 | PublishScripts/ 164 | 165 | # NuGet Packages 166 | *.nupkg 167 | # The packages folder can be ignored because of Package Restore 168 | **/packages/* 169 | # except build/, which is used as an MSBuild target. 170 | !**/packages/build/ 171 | # Uncomment if necessary however generally it will be regenerated when needed 172 | #!**/packages/repositories.config 173 | # NuGet v3's project.json files produces more ignoreable files 174 | *.nuget.props 175 | *.nuget.targets 176 | 177 | # Microsoft Azure Build Output 178 | csx/ 179 | *.build.csdef 180 | 181 | # Microsoft Azure Emulator 182 | ecf/ 183 | rcf/ 184 | 185 | # Windows Store app package directories and files 186 | AppPackages/ 187 | BundleArtifacts/ 188 | Package.StoreAssociation.xml 189 | _pkginfo.txt 190 | 191 | # Visual Studio cache files 192 | # files ending in .cache can be ignored 193 | *.[Cc]ache 194 | # but keep track of directories ending in .cache 195 | !*.[Cc]ache/ 196 | 197 | # Others 198 | ClientBin/ 199 | ~$* 200 | *~ 201 | *.dbmdl 202 | *.dbproj.schemaview 203 | *.jfm 204 | *.pfx 205 | *.publishsettings 206 | orleans.codegen.cs 207 | 208 | # Since there are multiple workflows, uncomment next line to ignore bower_components 209 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 210 | #bower_components/ 211 | 212 | # RIA/Silverlight projects 213 | Generated_Code/ 214 | 215 | # Backup & report files from converting an old project file 216 | # to a newer Visual Studio version. Backup files are not needed, 217 | # because we have git ;-) 218 | _UpgradeReport_Files/ 219 | Backup*/ 220 | UpgradeLog*.XML 221 | UpgradeLog*.htm 222 | 223 | # SQL Server files 224 | *.mdf 225 | *.ldf 226 | 227 | # Business Intelligence projects 228 | *.rdl.data 229 | *.bim.layout 230 | *.bim_*.settings 231 | 232 | # Microsoft Fakes 233 | FakesAssemblies/ 234 | 235 | # GhostDoc plugin setting file 236 | *.GhostDoc.xml 237 | 238 | # Node.js Tools for Visual Studio 239 | .ntvs_analysis.dat 240 | node_modules/ 241 | 242 | # Typescript v1 declaration files 243 | typings/ 244 | 245 | # Visual Studio 6 build log 246 | *.plg 247 | 248 | # Visual Studio 6 workspace options file 249 | *.opt 250 | 251 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 252 | *.vbw 253 | 254 | # Visual Studio LightSwitch build output 255 | **/*.HTMLClient/GeneratedArtifacts 256 | **/*.DesktopClient/GeneratedArtifacts 257 | **/*.DesktopClient/ModelManifest.xml 258 | **/*.Server/GeneratedArtifacts 259 | **/*.Server/ModelManifest.xml 260 | _Pvt_Extensions 261 | 262 | # Paket dependency manager 263 | .paket/paket.exe 264 | paket-files/ 265 | 266 | # FAKE - F# Make 267 | .fake/ 268 | 269 | # JetBrains Rider 270 | .idea/ 271 | *.sln.iml 272 | 273 | # CodeRush 274 | .cr/ 275 | 276 | # Python Tools for Visual Studio (PTVS) 277 | __pycache__/ 278 | *.pyc 279 | 280 | # Cake - Uncomment if you are using it 281 | # tools/** 282 | # !tools/packages.config 283 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/curl"] 2 | path = external/curl 3 | url = https://github.com/curl/curl 4 | [submodule "external/cpr"] 5 | path = external/cpr 6 | url = https://github.com/whoshuu/cpr 7 | [submodule "external/hooking"] 8 | path = external/hooking 9 | url = https://github.com/ThirteenAG/Hooking.Patterns 10 | [submodule "external/injector"] 11 | path = external/injector 12 | url = https://github.com/thelink2012/injector 13 | [submodule "external/jsoncpp"] 14 | path = external/jsoncpp 15 | url = https://github.com/open-source-parsers/jsoncpp 16 | [submodule "external/inireader"] 17 | path = external/inireader 18 | url = https://github.com/ThirteenAG/IniReader 19 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 2.{build} 2 | skip_tags: true 3 | image: Visual Studio 2017 4 | configuration: Release 5 | platform: x86 6 | install: 7 | - cmd: >- 8 | git submodule update --init --recursive 9 | 10 | premake5.bat 11 | build: 12 | project: build/III.VC.SA.SaveLoader.vcxproj 13 | verbosity: minimal 14 | before_package: 15 | - cmd: >- 16 | cd data 17 | 18 | release.bat 19 | artifacts: 20 | - path: data/III.VC.SA.SaveLoader.zip 21 | name: III.VC.SA.SaveLoader.zip 22 | deploy: 23 | - provider: GitHub 24 | tag: v$(appveyor_build_version) 25 | release: III.VC.SA.SaveLoader v$(appveyor_build_version) 26 | description: A plugin for GTA 3, Vice City and San Andreas, which automatically loads most recent savegame at game's launch.\n\n[Requires ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases)\n\n[GTAForums topic](http://gtaforums.com/topic/602025-iiivcsa-saveloader/)\n 27 | auth_token: 28 | secure: SXMI7bm5RKh5j1S8A8dnUP2HFw97xHHlJH+mA0hx819vtxOPCpMFY3aFZ+2v16ri 29 | artifact: III.VC.SA.SaveLoader.zip -------------------------------------------------------------------------------- /data/7za.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThirteenAG/III.VC.SA.SaveLoader/647850df5275af5c52ba79490dc0a34d6734d437/data/7za.exe -------------------------------------------------------------------------------- /data/III.VC.SA.SaveLoader.ini: -------------------------------------------------------------------------------- 1 | [MAIN] 2 | LoadSlot = 0 // 0 - auto, 1-128 - available slots(8 shows ingame), 129 - new game. -1 - disable. 3 | SkipIntro = 1 4 | SkipOutro = 1 // Disables outro screen in VC. 5 | DisableLoadingScreens = 1 // Disables loadscreens in III and VC. Works also as fastloader in SA. 6 | CustomUserFilesDirectoryInGameDir = 0 7 | // user files will be stored in a specified directory, for example - 'save' (without quotes). Set to 0 to disable. 8 | 9 | [GTASnP.com] 10 | UploadSaves = 1 // When saving the game in 8th slot plugin will upload it to GTASnP.com and save the link here. You can continue the game while save is being uploaded. 11 | DownloadSaves = 1 // Loading save from 8th slot will result downloading it from GTASnP.com. 12 | CopyUrlToClipboard = 1 // After saving the game to 8th slot gtasnp link will be copied to clipboard. 13 | -------------------------------------------------------------------------------- /data/release.bat: -------------------------------------------------------------------------------- 1 | 7za a -tzip ".\III.VC.SA.SaveLoader.zip" ".\III.VC.SA.SaveLoader.asi" ".\III.VC.SA.SaveLoader.ini" 2 | EXIT 3 | 4 | 7-Zip Extra 5 | ~~~~~~~~~~~ 6 | License for use and distribution 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | Copyright (C) 1999-2016 Igor Pavlov. 10 | 11 | 7-Zip Extra files are under the GNU LGPL license. 12 | 13 | 14 | Notes: 15 | You can use 7-Zip Extra on any computer, including a computer in a commercial 16 | organization. You don't need to register or pay for 7-Zip. 17 | 18 | 19 | GNU LGPL information 20 | -------------------- 21 | 22 | This library is free software; you can redistribute it and/or 23 | modify it under the terms of the GNU Lesser General Public 24 | License as published by the Free Software Foundation; either 25 | version 2.1 of the License, or (at your option) any later version. 26 | 27 | This library is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 | Lesser General Public License for more details. 31 | 32 | You can receive a copy of the GNU Lesser General Public License from 33 | http://www.gnu.org/ 34 | 35 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ThirteenAG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /premake5.bat: -------------------------------------------------------------------------------- 1 | premake5 vs2017 -------------------------------------------------------------------------------- /premake5.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThirteenAG/III.VC.SA.SaveLoader/647850df5275af5c52ba79490dc0a34d6734d437/premake5.exe -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | workspace "III.VC.SA.SaveLoader" 2 | configurations { "Release", "Debug" } 3 | location "build" 4 | 5 | defines { "rsc_CompanyName=\"ThirteenAG\"" } 6 | defines { "rsc_LegalCopyright=\"MIT License\""} 7 | defines { "rsc_FileVersion=\"1.0.0.0\"", "rsc_ProductVersion=\"1.0.0.0\"" } 8 | defines { "rsc_InternalName=\"%{prj.name}\"", "rsc_ProductName=\"%{prj.name}\"", "rsc_OriginalFilename=\"%{prj.name}.asi\"" } 9 | defines { "rsc_FileDescription=\"https://github.com/ThirteenAG\"" } 10 | defines { "rsc_UpdateUrl=\"https://github.com/ThirteenAG/III.VC.SA.SaveLoader\"" } 11 | 12 | files { "source/*.h" } 13 | files { "source/*.cpp", "source/*.c" } 14 | files { "source/*.rc" } 15 | 16 | files { "external/cpr/cpr/*.cpp" } 17 | files { "external/jsoncpp/src/lib_json/*.cpp" } 18 | files { "external/hooking/Hooking.Patterns.h", "external/hooking/Hooking.Patterns.cpp" } 19 | 20 | includedirs { "source/" } 21 | includedirs { "external/hooking" } 22 | includedirs { "external/injector/include" } 23 | includedirs { "external/inireader" } 24 | includedirs { "external/curl/builds/libcurl-vc14-x86-release-static-ipv6-sspi-winssl/include" } 25 | includedirs { "external/cpr/include" } 26 | includedirs { "external/jsoncpp/include" } 27 | 28 | libdirs { "external/curl/builds/libcurl-vc14-x86-release-static-ipv6-sspi-winssl/lib" } 29 | 30 | links { "wldap32.lib", "Ws2_32.lib" } 31 | links { "libcurl_a.lib" } 32 | defines { "CURL_STATICLIB" } 33 | 34 | prebuildcommands { 35 | "cd ../external/curl/winbuild/", 36 | "nmake /f Makefile.vc mode=static RTLIBCFG=static ENABLE_IDN=no VC=14" 37 | } 38 | 39 | project "GTASNPTestApp" 40 | kind "ConsoleApp" 41 | language "C++" 42 | targetdir "bin/%{cfg.buildcfg}" 43 | targetextension ".exe" 44 | excludes { "source/dllmain.cpp" } 45 | 46 | filter "configurations:Debug" 47 | defines { "DEBUG" } 48 | flags { "Symbols" } 49 | 50 | filter "configurations:Release" 51 | defines { "NDEBUG" } 52 | optimize "On" 53 | flags { "StaticRuntime" } 54 | characterset ("MBCS") 55 | 56 | 57 | project "III.VC.SA.SaveLoader" 58 | kind "SharedLib" 59 | language "C++" 60 | targetdir "bin/%{cfg.buildcfg}" 61 | targetextension ".asi" 62 | excludes { "source/GTASNPTestApp.cpp" } 63 | 64 | filter "configurations:Debug" 65 | defines { "DEBUG" } 66 | flags { "Symbols" } 67 | characterset ("MBCS") 68 | 69 | filter "configurations:Release" 70 | defines { "NDEBUG" } 71 | optimize "On" 72 | flags { "StaticRuntime" } 73 | characterset ("MBCS") 74 | targetdir "data/" 75 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | SaveLoader 2 | =================== 3 | 4 | A plugin for GTA 3, Vice City and San Andreas, which automatically loads most recent savegame at game's launch. 5 | 6 | [Requires ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases) 7 | 8 | [GTAForums topic](http://gtaforums.com/topic/602025-iiivcsa-saveloader/) 9 | -------------------------------------------------------------------------------- /source/GTASNPTestApp.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | int main() 4 | { 5 | std::string save("http://gtasnp.com/download/file/ZAzP7H?slot=1"); 6 | 7 | auto r = cpr::Get(cpr::Url{ save }); 8 | 9 | if (r.status_code == 200) 10 | { 11 | std::cout << r.status_code << std::endl; 12 | 13 | std::fstream ifs; 14 | ifs.open(".\\1.bin", std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc); 15 | 16 | if (ifs.is_open()) 17 | { 18 | ifs << r.text; 19 | ifs.close(); 20 | } 21 | 22 | } 23 | 24 | 25 | //upload 26 | /*auto url = cpr::Url{ "http://gtasnp.com/upload/process" }; 27 | auto multipart = cpr::Multipart{ { "file", cpr::File{ "GTASAsf1.b" } } }; 28 | auto header = cpr::Header 29 | { 30 | { "Host", "gtasnp.com" }, 31 | { "Accept", "application/json" }, 32 | { "Accept-Encoding", "gzip, deflate" }, 33 | { "Cache-Control", "no-cache" }, 34 | { "X-Requested-With", "XMLHttpRequest" }, 35 | { "Referer", "http://gtasnp.com/upload" } 36 | }; 37 | 38 | auto r = cpr::Post(url, multipart, header); 39 | std::cout << r.text << std::endl;*/ 40 | return 0; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /source/VersionInfo.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThirteenAG/III.VC.SA.SaveLoader/647850df5275af5c52ba79490dc0a34d6734d437/source/VersionInfo.h -------------------------------------------------------------------------------- /source/VersionInfo.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThirteenAG/III.VC.SA.SaveLoader/647850df5275af5c52ba79490dc0a34d6734d437/source/VersionInfo.rc -------------------------------------------------------------------------------- /source/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | bool bDelay; 4 | auto& gvm = injector::address_manager::singleton(); 5 | 6 | int32_t nSaveNum; 7 | bool bSkipIntro, bSkipOutro, bDisableLoadingScreens; 8 | bool bUploadSaves, bDownloadSaves, bCopyUrlToClipboard; 9 | char szCustomUserFilesDirectory[MAX_PATH]; 10 | 11 | char* pUserDirPath; 12 | uint32_t bCurrentSaveSlot; 13 | uint32_t* TheText; 14 | static wchar_t backupText[50]; 15 | static wchar_t backupText2[50]; 16 | size_t bckpTxtSize, bckpTxtSize2; 17 | wchar_t* (__thiscall *pfGetText)(int, char *); 18 | char* (__thiscall *pfGetTextSA)(int, char *); 19 | const static wchar_t SnPString[] = L"Uploading to gtasnp.com..."; 20 | const static char SnPStringSA[] = "Uploading to gtasnp.com..."; 21 | 22 | DWORD WINAPI UploadSave(LPVOID lpParameter) 23 | { 24 | std::string SFPath(pUserDirPath); 25 | SFPath += "8.b"; 26 | auto url = cpr::Url{ "http://gtasnp.com/upload/process" }; 27 | auto multipart = cpr::Multipart{ { "file", cpr::File{ SFPath } } }; 28 | auto header = cpr::Header 29 | { 30 | { "Host", "gtasnp.com" }, 31 | { "Accept", "application/json" }, 32 | { "Accept-Encoding", "gzip, deflate" }, 33 | { "Cache-Control", "no-cache" }, 34 | { "X-Requested-With", "XMLHttpRequest" }, 35 | { "Referer", "http://gtasnp.com/upload" } 36 | }; 37 | 38 | auto r = cpr::Post(url, multipart, header); 39 | 40 | Json::Value parsedFromString; 41 | Json::Reader reader; 42 | bool parsingSuccessful = reader.parse(r.text, parsedFromString); 43 | if (parsingSuccessful && parsedFromString["error_code"].asBool() == false) 44 | { 45 | /* 46 | { 47 | game: 'gtasa_pc', // string if successful, false if error 48 | error_code: false, // string if error, false if no error 49 | error_message: '', // always string, empty if no error 50 | uuid: 'xhnDKn' // string if successful, false if error 51 | } 52 | */ 53 | std::string result; 54 | if (gvm.IsSA()) 55 | { 56 | std::string wc("Save uploaded to gtasnp.com/"); 57 | result = (parsedFromString["uuid"].asCString()); 58 | wc += result; 59 | strncpy((char*)lpParameter, &wc[0], bckpTxtSize); 60 | } 61 | else 62 | { 63 | std::wstring wc(L"Save uploaded to gtasnp.com/"); 64 | if (gvm.IsIII()) 65 | { 66 | wc = L"URL: gtasnp.com/"; 67 | } 68 | result = (parsedFromString["uuid"].asCString()); 69 | std::wstring uuid(result.size(), L'#'); 70 | mbstowcs(&uuid[0], result.c_str(), result.size()); 71 | wc += uuid; 72 | wcsncpy((wchar_t*)lpParameter, &wc[0], bckpTxtSize); 73 | } 74 | 75 | CIniReader iniWriter(""); 76 | result = "http://gtasnp.com/" + result; 77 | iniWriter.WriteString("GTASnP.com", "LatestUpload", (char*)result.c_str()); 78 | 79 | if (bCopyUrlToClipboard) 80 | { 81 | OpenClipboard(0); 82 | EmptyClipboard(); 83 | HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, result.size() + 1); 84 | if (hg) 85 | { 86 | memcpy(GlobalLock(hg), result.c_str(), result.size() + 1); 87 | GlobalUnlock(hg); 88 | SetClipboardData(CF_TEXT, hg); 89 | CloseClipboard(); 90 | GlobalFree(hg); 91 | } 92 | CloseClipboard(); 93 | } 94 | //MessageBox(0, parsedFromString["uuid"].asCString(), 0, 0); 95 | } 96 | else 97 | { 98 | std::string result(parsedFromString["error_message"].asCString()); 99 | std::wstring wc(result.size(), L'#'); 100 | mbstowcs(&wc[0], result.c_str(), result.size()); 101 | wcsncpy((wchar_t*)lpParameter, &wc[0], bckpTxtSize); 102 | } 103 | 104 | return 1; 105 | } 106 | 107 | DWORD WINAPI DownloadSave(LPVOID lpParameter) 108 | { 109 | std::string SFPath(pUserDirPath); 110 | SFPath += "8.b"; 111 | 112 | std::string ID((char*)lpParameter); 113 | ID = ID.substr(ID.find_last_of("/") + 1); 114 | 115 | std::string URL; 116 | URL = "gtasnp.com/download/file/" + ID + "?slot=8"; 117 | 118 | auto r = cpr::Get(cpr::Url{ URL }); 119 | 120 | if (r.status_code == 200) 121 | { 122 | std::fstream fs; 123 | fs.open(SFPath, std::fstream::binary | std::fstream::in | std::fstream::out | std::fstream::trunc); 124 | 125 | if (fs.is_open()) 126 | { 127 | fs << r.text; 128 | fs.close(); 129 | } 130 | } 131 | return r.status_code; 132 | } 133 | 134 | injector::hook_back hbPcSaveSaveSlot; 135 | char __fastcall PcSaveSaveSlotHook(DWORD* _this, int bSlotIndex) 136 | { 137 | _asm mov bCurrentSaveSlot, eax //for some reason bSlotIndex returns dl instead of eax 138 | return hbPcSaveSaveSlot.fun(_this, bSlotIndex); 139 | } 140 | 141 | injector::hook_back hbCheckSlotDataValid; 142 | bool __cdecl CheckSlotDataValidHook(int nSlotIndex) 143 | { 144 | CIniReader iniReader(""); 145 | static char* szLatestUpload = iniReader.ReadString("GTASnP.com", "LatestUpload", ""); 146 | 147 | if (szLatestUpload[0] != 0) 148 | { 149 | wchar_t* ptr; 150 | if (!gvm.IsSA() && !gvm.IsIII()) 151 | { 152 | ptr = pfGetText((int)TheText, "FELD_WR"); 153 | if (backupText2[0] == 0) 154 | { 155 | bckpTxtSize2 = wcslen(ptr); 156 | wcsncpy(backupText2, ptr, bckpTxtSize2); 157 | } 158 | } 159 | 160 | if (nSlotIndex == 7) 161 | { 162 | auto status_code = DownloadSave(szLatestUpload); 163 | if (status_code == 200) 164 | { 165 | if (!gvm.IsSA() && !gvm.IsIII()) 166 | wcsncpy(ptr, L"Save loaded from gtasnp.com", bckpTxtSize2); 167 | } 168 | else 169 | { 170 | if (!gvm.IsSA() && !gvm.IsIII()) 171 | wcsncpy(ptr, L"Error downloading save file.", bckpTxtSize2); 172 | } 173 | } 174 | else 175 | { 176 | if (!gvm.IsSA() && !gvm.IsIII()) 177 | wcsncpy(ptr, backupText2, bckpTxtSize2); 178 | } 179 | } 180 | return hbCheckSlotDataValid.fun(nSlotIndex); 181 | } 182 | 183 | injector::hook_back hbMenuGotoPageHook; 184 | void __fastcall MenuGotoPageHook(DWORD* _this, int PageId) 185 | { 186 | wchar_t* ptr = pfGetText((int)TheText, "FES_SSC"); 187 | if (backupText[0] == 0) 188 | { 189 | bckpTxtSize = wcslen(ptr); 190 | wcsncpy(backupText, ptr, bckpTxtSize); 191 | } 192 | 193 | if (bCurrentSaveSlot == 7) //8th 194 | { 195 | wcsncpy(ptr, SnPString, bckpTxtSize); 196 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&UploadSave, ptr, 0, NULL); 197 | } 198 | else 199 | { 200 | wcsncpy(ptr, backupText, bckpTxtSize); 201 | } 202 | 203 | return hbMenuGotoPageHook.fun(_this, PageId); 204 | } 205 | 206 | char* __cdecl InitUserDirectories() 207 | { 208 | CreateDirectory(szCustomUserFilesDirectory, NULL); 209 | return szCustomUserFilesDirectory; 210 | } 211 | 212 | void GetSystemTimeFromSave(SYSTEMTIME& SystemLastWriteTime, WIN32_FIND_DATA& fd) 213 | { 214 | FILE* hFile = fopen(fd.cFileName, "rb"); 215 | if (hFile) { 216 | fseek(hFile, 0x34, SEEK_SET); 217 | fread(&SystemLastWriteTime, sizeof(SYSTEMTIME), 1, hFile); 218 | fclose(hFile); 219 | } 220 | SystemTimeToFileTime(&SystemLastWriteTime, &fd.ftLastWriteTime); 221 | } 222 | 223 | void FindFiles() 224 | { 225 | nSaveNum = 129; 226 | std::string SFPath(pUserDirPath); 227 | SFPath += "*.b"; 228 | 229 | SYSTEMTIME SystemLastWriteTime; 230 | WIN32_FIND_DATA fd; 231 | HANDLE File = FindFirstFile(SFPath.c_str(), &fd); 232 | GetSystemTimeFromSave(SystemLastWriteTime, fd); 233 | FILETIME LastWriteTime = fd.ftLastWriteTime; 234 | 235 | if (File != INVALID_HANDLE_VALUE) 236 | { 237 | do 238 | { 239 | if (CompareFileTime(&fd.ftLastWriteTime, &LastWriteTime) >= 0) 240 | { 241 | LastWriteTime = fd.ftLastWriteTime; 242 | std::string str(fd.cFileName); 243 | str.erase(0, 4); //del GTA3 244 | auto n = str.find_first_of("0123456789"); 245 | if (n != std::string::npos) 246 | { 247 | nSaveNum = std::atoi(&str[n]); 248 | } 249 | } 250 | GetSystemTimeFromSave(SystemLastWriteTime, fd); 251 | } while (FindNextFile(File, &fd)); 252 | FindClose(File); 253 | } 254 | } 255 | 256 | injector::hook_back hbFrontendIdle; 257 | void __cdecl FrontendIdleHook() 258 | { 259 | _asm pushad 260 | bool bNoLoad = (GetAsyncKeyState(VK_SHIFT) & 0xF000) != 0; 261 | if (!bNoLoad && nSaveNum != -1) 262 | { 263 | if (nSaveNum == 0) 264 | FindFiles(); 265 | 266 | //MessageBox(0, std::to_string(nSaveNum).c_str(), 0, 0); 267 | 268 | if (nSaveNum != 0 && nSaveNum != 129) 269 | { 270 | auto pattern = hook::pattern("8B 44 24 04 C7 05 ? ? ? ? 00 00 00 00 68 ? ? ? ? 50"); 271 | static auto CheckSlotDataValid = (bool(__cdecl*)(int))(pattern.get(0).get(0)); 272 | if (!CheckSlotDataValid(nSaveNum - 1)) 273 | { 274 | nSaveNum = 129; 275 | } 276 | } 277 | 278 | auto pattern = hook::pattern("53 B9 ? ? ? ? 83 EC 28 68 ? ? ? ? 68"); //0x869630 279 | 280 | if (gvm.IsIII()) 281 | pattern = hook::pattern("? B9 ? ? ? ? C6 05 ? ? ? ? 01 E8 ? ? ? ? B9 ? ? ? ? C6"); //0x8F59D8 gta3 282 | 283 | static uint32_t* CMenuManager = *pattern.get(0).get(2); 284 | 285 | if (gvm.IsVC()) 286 | { 287 | pattern = hook::pattern("80 3D ? ? ? ? 00 53 89 CB ? ? ? ? ? ? 80"); //0x498E5F 288 | static auto ProcessOnOffMenuOptions = (void(__fastcall*)(uint32_t* _this))(pattern.get(0).get(0)); 289 | ProcessOnOffMenuOptions(CMenuManager); 290 | } 291 | 292 | if (nSaveNum == 129) //NG 293 | { 294 | if (gvm.IsIII()) 295 | { 296 | static auto dword_485134 = hook::pattern("C6 85 ? 01 00 00 00 E8 ? ? ? ? 6A").get(0).get(2); 297 | injector::WriteMemory(dword_485134, 0x10, true); 298 | 299 | auto dword_48C7F8 = hook::pattern("B9 ? ? ? ? 68 ? ? ? ? E8 ? ? ? ? 43 83 FB 32"); 300 | static auto dword_8F59D8 = *dword_48C7F8.get(0).get(1); 301 | 302 | struct EmergencyVehiclesFix 303 | { 304 | void operator()(injector::reg_pack& regs) 305 | { 306 | regs.eax = (uint32_t)dword_8F59D8; 307 | injector::WriteMemory(dword_485134, 0x14, true); 308 | injector::WriteMemory((uint32_t)CMenuManager + 0x111, 0); 309 | } 310 | }; injector::MakeInline(dword_48C7F8.get(0).get(0), dword_48C7F8.get(0).get(5)); 311 | } 312 | 313 | uint32_t NewGameStart = gvm.IsIII() ? 10 : 7; 314 | injector::WriteMemory((uint32_t)CMenuManager + (gvm.IsIII() ? 0x548 : 0xF8), NewGameStart); 315 | } 316 | else 317 | { 318 | injector::WriteMemory((uint32_t)CMenuManager + (gvm.IsIII() ? 0x55C : 0x100), nSaveNum - 1); //LastUsedSlot 319 | injector::WriteMemory((uint32_t)CMenuManager + (gvm.IsIII() ? 0x548 : 0xF8), gvm.IsIII() ? 14 : 12); //currentMenuItem 320 | } 321 | 322 | injector::WriteMemory((uint32_t)CMenuManager + (gvm.IsIII() ? 0x115 : 0x11), 1); 323 | injector::WriteMemory((uint32_t)CMenuManager + (gvm.IsIII() ? 0x111 : 0x38), 0); 324 | injector::WriteMemory((uint32_t)CMenuManager + (gvm.IsIII() ? 0x114 : 0x39), 1); 325 | injector::WriteMemory((uint32_t)CMenuManager + (gvm.IsIII() ? 0x454 : 0x3C), 1); 326 | 327 | } 328 | auto pattern = hook::pattern("E8 ? ? ? ? 83 C4 08 B8 01 00 00 00 5B C3"); 329 | auto pattern2 = hook::pattern("83 EC 08 E8 ? ? ? ? DD D8"); 330 | auto pattern3 = hook::pattern("83 EC 08 E8 ? ? ? ? E8 ? ? ? ? E8"); 331 | if (gvm.IsIII()) 332 | injector::MakeCALL(pattern.get(2).get(0), pattern3.get(1).get(0)); //0x48E90F 0x48E700 333 | else 334 | injector::MakeCALL(pattern.get(3).get(0), pattern2.get(0).get(0)); //0x4A5BF2 0x4A5C60*/ 335 | __asm popad 336 | return hbFrontendIdle.fun(); 337 | } 338 | 339 | void III() 340 | { 341 | auto pattern = hook::pattern("68 ? ? ? ? 68 ? ? ? ? 50 C7 84 24 80 00 00 00 00"); 342 | pUserDirPath = *pattern.get(0).get(1); 343 | 344 | pattern = hook::pattern("C7 05 ? ? ? ? 00 00 00 00 C7 05 ? ? ? ? 00 00 00 00 E8"); //0x5811CE 345 | static uint32_t* dword_72CF84 = *pattern.get(10).get(12); 346 | 347 | struct psInitialize 348 | { 349 | void operator()(injector::reg_pack&) 350 | { 351 | injector::WriteMemory(dword_72CF84, 0, true); 352 | 353 | if (strncmp(szCustomUserFilesDirectory, "0", 1) != 0) 354 | { 355 | char moduleName[MAX_PATH]; 356 | GetModuleFileName(NULL, moduleName, MAX_PATH); 357 | char* tempPointer = strrchr(moduleName, '\\'); 358 | *(tempPointer + 1) = '\0'; 359 | strcat(moduleName, szCustomUserFilesDirectory); 360 | strcpy(szCustomUserFilesDirectory, moduleName); 361 | 362 | auto pattern = hook::pattern("E8 ? ? ? ? 50 E8 ? ? ? ? 59 C3"); 363 | injector::MakeCALL(pattern.get(0).get(0), InitUserDirectories, true); //0x479080 364 | pattern = hook::pattern("E8 ? ? ? ? 50 E8 ? ? ? ? 59 E8"); 365 | injector::MakeCALL(pattern.get(0).get(0), InitUserDirectories, true); //0x5811DD 366 | pattern = hook::pattern("E8 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? E8 ? ? ? ? 89 C5 59 85 ED"); 367 | injector::MakeCALL(pattern.get(1).get(0), InitUserDirectories, true); //0x591EDD 368 | } 369 | 370 | if (bSkipIntro) 371 | { 372 | auto pattern = hook::pattern("C7 05 ? ? ? ? ? ? ? ? E9 ? ? ? ? 83 3D"); 373 | injector::WriteMemory(pattern.get(1).get(6), 0x05, true); //0x582A75 374 | } 375 | 376 | if (bDisableLoadingScreens) 377 | { 378 | auto pattern = hook::pattern("53 83 EC 50"); 379 | injector::WriteMemory(pattern.get(0).get(0), 0xC3, true); //0x48D770 380 | } 381 | 382 | auto pattern = hook::pattern("E8 ? ? ? ? 83 C4 08 B8 01 00 00 00 5B C3"); 383 | hbFrontendIdle.fun = injector::MakeCALL(pattern.get(2).get(0), FrontendIdleHook).get(); //0x48E90F 384 | } 385 | }; injector::MakeInline(pattern.get(10).get(10), pattern.get(10).get(20)); 386 | 387 | if (bUploadSaves) 388 | { 389 | pattern = hook::pattern("8B 85 48 05 00 00 89 85 54 05 00 00 C7 85"); //0x485217 390 | struct GotoPageIII 391 | { 392 | void operator()(injector::reg_pack& regs) 393 | { 394 | bCurrentSaveSlot = *(uint8_t *)(regs.ebp + 0x55C); 395 | 396 | wchar_t* ptr = pfGetText((int)TheText, "FES_SSC"); 397 | if (backupText[0] == 0) 398 | { 399 | bckpTxtSize = wcslen(ptr); 400 | wcsncpy(backupText, ptr, bckpTxtSize); 401 | } 402 | 403 | if (bCurrentSaveSlot == 7) //8th 404 | { 405 | wcsncpy(ptr, SnPString, bckpTxtSize); 406 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&UploadSave, ptr, 0, NULL); 407 | } 408 | else 409 | { 410 | wcsncpy(ptr, backupText, bckpTxtSize); 411 | } 412 | 413 | regs.eax = *(uint32_t *)(regs.ebp + 0x548); 414 | } 415 | }; injector::MakeInline(pattern.get(1).get(0), pattern.get(1).get(6)); 416 | } 417 | 418 | if (bDownloadSaves) 419 | { 420 | auto pattern = hook::pattern("E8 ? ? ? ? 84 C0 59 0F 84"); 421 | hbCheckSlotDataValid.fun = injector::MakeCALL(pattern.get(4).get(0), CheckSlotDataValidHook).get(); //0x48525F 422 | } 423 | 424 | if (bUploadSaves || bDownloadSaves) 425 | { 426 | pattern = hook::pattern("B9 ? ? ? ? 68 ? ? ? ? E8 ? ? ? ? C2 04 00"); 427 | auto GetTextCall = pattern.get(0).get(10); 428 | auto GetText = injector::GetBranchDestination(GetTextCall, true).as_int(); 429 | pfGetText = (wchar_t *(__thiscall *)(int, char *))GetText; 430 | TheText = *pattern.get(0).get(1); 431 | } 432 | } 433 | 434 | void VC() 435 | { 436 | auto pattern = hook::pattern("68 ? ? ? ? 68 ? ? ? ? 50 C7 84 24 80 00 00 00 00"); 437 | pUserDirPath = *pattern.get(0).get(1); 438 | 439 | pattern = hook::pattern("C7 05 ? ? ? ? 00 00 00 00 C7 05 ? ? ? ? 00 00 00 00 E8"); 440 | static uint32_t* dword_813D44 = *pattern.get(17).get(12); 441 | static uint32_t* dword_601A40 = pattern.get(17).get(25); 442 | struct psInitialize 443 | { 444 | void operator()(injector::reg_pack&) 445 | { 446 | injector::WriteMemory(dword_813D44, 0, true); 447 | 448 | if (strncmp(szCustomUserFilesDirectory, "0", 1) != 0) 449 | { 450 | char moduleName[MAX_PATH]; 451 | GetModuleFileName(NULL, moduleName, MAX_PATH); 452 | char* tempPointer = strrchr(moduleName, '\\'); 453 | *(tempPointer + 1) = '\0'; 454 | strcat(moduleName, szCustomUserFilesDirectory); 455 | strcpy(szCustomUserFilesDirectory, moduleName); 456 | 457 | auto pattern = hook::pattern("E8 ? ? ? ? 50 E8 ? ? ? ? 59 C3"); 458 | injector::MakeCALL(pattern.get(0).get(0), InitUserDirectories, true); //0x48E020 459 | pattern = hook::pattern("E8 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? E8 ? ? ? ? 89 C5"); 460 | injector::MakeCALL(pattern.get(2).get(0), InitUserDirectories, true); //0x61D8CA 461 | injector::MakeCALL(dword_601A40, InitUserDirectories, true); //0x601A40 462 | pattern = hook::pattern("50 E8 ? ? ? ? 59 E8 ? ? ? ? C7 05 ? ? ? ? 00 00 00 00"); 463 | injector::MakeJMP((uint32_t)dword_601A40 + 5, pattern.get(0).get(0), true); 464 | } 465 | 466 | if (bSkipIntro) 467 | { 468 | auto pattern = hook::pattern("C7 05 ? ? ? ? ? ? ? ? E9 ? ? ? ? 83 3D"); 469 | injector::WriteMemory(pattern.get_first(6), 0x05, true); //0x5FFFAB 470 | } 471 | 472 | if (bSkipOutro) 473 | { 474 | auto pattern = hook::pattern("83 3D ? ? ? ? 00 75 10"); 475 | auto pattern2 = hook::pattern("6A 00 6A 1E E8 ? ? ? ? 59 59"); 476 | injector::MakeJMP(pattern.get(0).get(0), pattern2.get(0).get(0), true); // 0x495809 0x49596E outro 477 | } 478 | 479 | if (bDisableLoadingScreens) 480 | { 481 | auto pattern = hook::pattern("53 83 EC 68 ? ? ? ? ? E8"); 482 | injector::WriteMemory(pattern.get(0).get(0), 0xC3, true); //0x4A69D0 483 | } 484 | 485 | auto pattern = hook::pattern("E8 ? ? ? ? 83 C4 08 B8 01 00 00 00 5B C3"); 486 | hbFrontendIdle.fun = injector::MakeCALL(pattern.get(3).get(0), FrontendIdleHook).get(); //0x4A5BF2 487 | } 488 | }; injector::MakeInline(pattern.get(17).get(10), pattern.get(17).get(20)); 489 | 490 | if (bUploadSaves) 491 | { 492 | auto pattern = hook::pattern("E8 ? ? ? ? B9 ? ? ? ? 88 C3 E8 ? ? ? ? 84 DB"); 493 | hbPcSaveSaveSlot.fun = injector::MakeCALL(pattern.get(0).get(0), PcSaveSaveSlotHook).get(); //0x49728C 494 | 495 | pattern = hook::pattern("E8 ? ? ? ? EB 4E"); 496 | hbMenuGotoPageHook.fun = injector::MakeCALL(pattern.get(0).get(0), MenuGotoPageHook).get(); //0x4972A5 497 | } 498 | 499 | if (bDownloadSaves) 500 | { 501 | auto pattern = hook::pattern("E8 ? ? ? ? 84 C0 59 74 7D"); 502 | hbCheckSlotDataValid.fun = injector::MakeCALL(pattern.get(0).get(0), CheckSlotDataValidHook).get(); //0x49730C 503 | } 504 | 505 | if (bUploadSaves || bDownloadSaves) 506 | { 507 | pattern = hook::pattern("E8 ? ? ? ? DB 05 ? ? ? ? 50 89 C3 D8 0D"); 508 | auto GetTextCall = pattern.get(0).get(0); 509 | auto GetText = injector::GetBranchDestination(GetTextCall, true).as_int(); 510 | pfGetText = (wchar_t *(__thiscall *)(int, char *))GetText; 511 | TheText = *pattern.get(0).get(-9); 512 | } 513 | } 514 | 515 | DWORD RsCameraBeginUpdateNOP() 516 | { 517 | return 0; 518 | } 519 | 520 | injector::hook_back hbFrontendIdleSA; 521 | void __cdecl FrontendIdleHookSA() 522 | { 523 | static int nTimes = 0; 524 | injector::MakeCALL(0x53E80E, RsCameraBeginUpdateNOP, true); 525 | 526 | if (++nTimes >= 2) 527 | { 528 | bool bNoLoad = (GetAsyncKeyState(VK_SHIFT) & 0xF000) != 0; 529 | if (!bNoLoad && nSaveNum != -1) 530 | { 531 | if (nSaveNum == 0) 532 | FindFiles(); 533 | 534 | //MessageBox(0, std::to_string(nSaveNum).c_str(), 0, 0); 535 | 536 | if (nSaveNum != 0 && nSaveNum != 129) 537 | { 538 | static auto CheckSlotDataValid = (bool(__cdecl*)(int))0x5D1380; 539 | if (!CheckSlotDataValid(nSaveNum - 1)) 540 | { 541 | nSaveNum = 129; 542 | } 543 | } 544 | 545 | static uint32_t CMenuManager = 0xBA6748; 546 | if (nSaveNum == 129) //NG 547 | { 548 | *injector::memory_pointer(CMenuManager + 0x5D).get() = 1; 549 | *injector::memory_pointer(CMenuManager + 0x5C).get() = 0; //menu.m_bMenuActive 550 | 551 | } 552 | else 553 | { 554 | // Make the game load automatically 555 | *injector::memory_pointer(CMenuManager + 0x32).get() = 0; // menu.bDeactivateMenu 556 | *injector::memory_pointer(CMenuManager + 0x15F).get() = (nSaveNum - 1); // menu.SaveNumber 557 | *injector::memory_pointer(0xB72910).get() = 0; // game.bMissionPack 558 | 559 | // Simulate that we came into the menu and clicked to load game 560 | *injector::memory_pointer(CMenuManager + 0x15D).get() = 13; 561 | *injector::memory_pointer(CMenuManager + 0x1B3C).get() = 1; 562 | } 563 | *injector::memory_pointer(0xB7CB49).get() = 0; //game.m_UserPause 564 | } 565 | 566 | injector::MakeCALL(0x53E80E, 0x619450); 567 | injector::MakeCALL(0x53ECCB, 0x53E770); 568 | } 569 | 570 | return hbFrontendIdleSA.fun(); 571 | } 572 | 573 | void SimulateCopyrightScreen() 574 | { 575 | // Simulate that the copyright screen happened 576 | *injector::memory_pointer(0x8D093C).get() = 0; // Previous splash index = copyright notice 577 | *injector::memory_pointer(0xBAB340).get() -= 1000.0;// Decrease timeSinceLastScreen, so it will change immediately 578 | *injector::memory_pointer(0xBAB31E).get() = 1; // First Loading Splash 579 | } 580 | 581 | void SA() 582 | { 583 | pUserDirPath = (char*)0xC16F18; 584 | 585 | struct psInitialize 586 | { 587 | void operator()(injector::reg_pack&) 588 | { 589 | injector::WriteMemory(0xC8CF98, 0, true); 590 | 591 | if (strncmp(szCustomUserFilesDirectory, "0", 1) != 0) 592 | { 593 | char moduleName[MAX_PATH]; 594 | GetModuleFileName(NULL, moduleName, MAX_PATH); 595 | char* tempPointer = strrchr(moduleName, '\\'); 596 | *(tempPointer + 1) = '\0'; 597 | strcat(moduleName, szCustomUserFilesDirectory); 598 | strcpy(szCustomUserFilesDirectory, moduleName); 599 | 600 | injector::MakeCALL(0x538860, InitUserDirectories, true); 601 | injector::MakeCALL(0x619075, InitUserDirectories, true); 602 | injector::MakeCALL(0x747470, InitUserDirectories, true); 603 | } 604 | 605 | if (bSkipIntro) 606 | { 607 | injector::MakeNOP(0x747483, 6); // Disable gGameState = 0 setting 608 | injector::WriteMemory(0xC8D4C0, 5); // Put the game where the user wants (default's to the copyright screen) 609 | 610 | // Hook the copyright screen fading in/out and simulates that it has happened 611 | injector::MakeNOP(0x748C2B, 5); 612 | injector::MakeCALL(0x748C9A, injector::raw_ptr(SimulateCopyrightScreen)); 613 | } 614 | 615 | if (bDisableLoadingScreens) 616 | { 617 | // Skip fading screen rendering 618 | injector::MakeJMP(0x590AE4, 0x590C9E); 619 | 620 | // Disable loading bar rendering 621 | injector::MakeNOP(0x5905B4, 5); 622 | 623 | // Disable loading screen rendering 624 | injector::MakeNOP(0x590D9F, 5); 625 | injector::WriteMemory(0x590D9F, 0xC3, true); 626 | 627 | // Disable audio tune from loading screen 628 | injector::MakeNOP(0x748CF6, 5); 629 | } 630 | 631 | injector::MakeNOP(0x748CBD, 2); // Let FrontentIdle run even when minimized 632 | hbFrontendIdleSA.fun = injector::MakeCALL(0x53ECCB, FrontendIdleHookSA).get(); 633 | } 634 | }; injector::MakeInline(0x74742F, 0x747439); 635 | 636 | if (bUploadSaves) 637 | { 638 | struct GotoPageSA 639 | { 640 | void operator()(injector::reg_pack& regs) 641 | { 642 | bCurrentSaveSlot = *(uint8_t *)(0xBA6748 + 0x15F); 643 | 644 | char* ptr = pfGetTextSA((int)TheText, "FES_SSC"); 645 | if (backupText[0] == 0) 646 | { 647 | bckpTxtSize = strlen(ptr); 648 | strncpy((char*)backupText, ptr, bckpTxtSize); 649 | } 650 | 651 | if (bCurrentSaveSlot == 7) //8th 652 | { 653 | strncpy(ptr, SnPStringSA, bckpTxtSize); 654 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&UploadSave, ptr, 0, NULL); 655 | } 656 | else 657 | { 658 | strncpy(ptr, (char*)backupText, bckpTxtSize); 659 | } 660 | 661 | *(uint8_t *)0xBA8286 = 0; 662 | } 663 | }; injector::MakeInline(0x578E2C, 0x578E2C + 0x7); 664 | } 665 | 666 | if (bDownloadSaves) 667 | { 668 | hbCheckSlotDataValid.fun = injector::MakeCALL(0x578EF2, CheckSlotDataValidHook).get(); 669 | } 670 | 671 | if (bUploadSaves || bDownloadSaves) 672 | { 673 | pfGetTextSA = (char *(__thiscall *)(int, char *))0x6A0050; 674 | TheText = (uint32_t*)0xC1B340; 675 | } 676 | } 677 | 678 | DWORD WINAPI Init(LPVOID) 679 | { 680 | CIniReader iniReader(""); 681 | nSaveNum = iniReader.ReadInteger("MAIN", "LoadSlot", 0); 682 | bSkipIntro = iniReader.ReadInteger("MAIN", "SkipIntro", 1) != 0; 683 | bSkipOutro = iniReader.ReadInteger("MAIN", "SkipOutro", 1) != 0; 684 | bDisableLoadingScreens = iniReader.ReadInteger("MAIN", "DisableLoadingScreens", 1) != 0; 685 | char* str = iniReader.ReadString("MAIN", "CustomUserFilesDirectoryInGameDir", "0"); 686 | strcpy(szCustomUserFilesDirectory, str); 687 | 688 | bUploadSaves = iniReader.ReadInteger("GTASnP.com", "UploadSaves", 1) != 0; 689 | bDownloadSaves = iniReader.ReadInteger("GTASnP.com", "DownloadSaves", 1) != 0; 690 | bCopyUrlToClipboard = iniReader.ReadInteger("GTASnP.com", "CopyUrlToClipboard", 1) != 0; 691 | 692 | auto pattern = hook::pattern("64 89 25 00 00 00 00"); 693 | if (!(pattern.size() > 0) && !bDelay) 694 | { 695 | bDelay = true; 696 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&Init, NULL, 0, NULL); 697 | return 0; 698 | } 699 | 700 | if (bDelay) 701 | { 702 | while (!(pattern.size() > 0)) 703 | pattern = hook::pattern("64 89 25 00 00 00 00"); 704 | } 705 | 706 | if (gvm.IsIII()) 707 | { 708 | III(); 709 | } 710 | else 711 | { 712 | if (gvm.IsVC()) 713 | { 714 | VC(); 715 | } 716 | else 717 | { 718 | if (gvm.IsSA()) 719 | { 720 | SA(); 721 | } 722 | } 723 | } 724 | return 0; 725 | } 726 | 727 | 728 | BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID) 729 | { 730 | if (reason == DLL_PROCESS_ATTACH) 731 | { 732 | Init(NULL); 733 | } 734 | return TRUE; 735 | } 736 | -------------------------------------------------------------------------------- /source/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // III.VC.SA.SaveLoader.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /source/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "targetver.h" 4 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "Hooking.Patterns.h" 15 | #include "IniReader.h" 16 | #include "json/reader.h" 17 | #include "injector/injector.hpp" 18 | #include "injector/assembly.hpp" 19 | #include "injector/hooking.hpp" 20 | #include "injector/calling.hpp" 21 | #include "injector/utility.hpp" -------------------------------------------------------------------------------- /source/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | --------------------------------------------------------------------------------