├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── Android.mk ├── Application.mk ├── LICENSE ├── README.md ├── alog.cpp ├── aml.cpp ├── build.ps1 ├── curl_config.h ├── icfg.cpp ├── icfg_desc.h ├── il2cpp ├── functions.cpp ├── functions.h ├── gc.cpp ├── typedefs.h └── types.h ├── include ├── aml.h ├── defines.h ├── interfaces.h ├── jnifn.h ├── mls.h ├── modpaks.h └── modslist.h ├── interface.cpp ├── main.cpp ├── mls.cpp ├── mod ├── amlmod.h ├── config.cpp ├── config.h ├── config_inipp.cpp ├── iaml.h ├── icfg.h ├── il2cpp.h ├── interface.h ├── listitem.h ├── logger.cpp ├── logger.h └── thirdparty │ ├── INICPP_LICENSE │ ├── STB_LICENSE │ ├── inicpp.h │ └── stb_sprintf.h ├── modpaks.cpp ├── modslist.cpp ├── ndkpath.txt ├── news.txt ├── signal.cpp ├── template_of_mod ├── Android.mk ├── Application.mk ├── build.ps1 ├── main.cpp ├── mod │ ├── amlmod.h │ ├── config.cpp │ ├── config.h │ ├── config_inipp.cpp │ ├── iaml.h │ ├── icfg.h │ ├── il2cpp.h │ ├── interface.h │ ├── listitem.h │ ├── logger.cpp │ ├── logger.h │ └── thirdparty │ │ ├── INICPP_LICENSE │ │ ├── STB_LICENSE │ │ ├── inicpp.h │ │ └── stb_sprintf.h └── ndkpath.txt ├── vtable_hooker.cpp └── vtable_hooker.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: AML Mod Compiler 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - name: Checking out repository... 15 | uses: actions/checkout@v4 16 | with: 17 | submodules: recursive 18 | 19 | - name: Installing Android NDK (r24)... 20 | uses: nttld/setup-ndk@v1 21 | with: 22 | ndk-version: r24 23 | local-cache: true 24 | 25 | - name: Building ARMPatch... 26 | run: ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./ARMPatch/armpatch_src/Android.mk NDK_APPLICATION_MK=./ARMPatch/armpatch_src/Application.mk NDK_DEBUG=0 -j12 27 | 28 | - name: Building AML... 29 | run: ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk NDK_DEBUG=0 -j12 30 | 31 | - name: Finished. Uploading the results. 32 | uses: actions/upload-artifact@v4 33 | with: 34 | name: AML_Libraries 35 | path: ./libs/**/libAML.so 36 | -------------------------------------------------------------------------------- /.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/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | 400 | # Own 401 | libs/ 402 | *.bak 403 | build.ps1 404 | ndkpath.txt 405 | GTASA_ENUMS.h 406 | GTASA_STRUCTS.h 407 | RW_STRUCTS.h 408 | .vscode/settings.json 409 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ARMPatch"] 2 | path = ARMPatch 3 | url = https://github.com/RusJJ/ARMPatch 4 | [submodule "curl"] 5 | path = curl 6 | url = https://github.com/curl/curl 7 | [submodule "wolfssl"] 8 | path = wolfssl 9 | url = https://github.com/wolfSSL/wolfssl 10 | [submodule "zlib"] 11 | path = zlib 12 | url = https://github.com/madler/zlib 13 | [submodule "AML_PrecompiledLibs"] 14 | path = AML_PrecompiledLibs 15 | url = https://github.com/RusJJ/AML_PrecompiledLibs 16 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | 4 | # ARMPatch 5 | 6 | include $(CLEAR_VARS) 7 | LOCAL_MODULE := armpatch 8 | LOCAL_SRC_FILES := obj/local/$(TARGET_ARCH_ABI)/libarmpatch.a 9 | include $(PREBUILT_STATIC_LIBRARY) 10 | 11 | 12 | # ThirdParty libraries 13 | 14 | include $(CLEAR_VARS) 15 | LOCAL_MODULE := substrate 16 | LOCAL_SRC_FILES := obj/local/$(TARGET_ARCH_ABI)/libsubstrate.a 17 | include $(PREBUILT_STATIC_LIBRARY) 18 | 19 | # include $(CLEAR_VARS) 20 | # LOCAL_MODULE := dobby 21 | # LOCAL_SRC_FILES := AML_PrecompiledLibs/$(TARGET_ARCH_ABI)/libdobby.a 22 | # include $(PREBUILT_STATIC_LIBRARY) 23 | 24 | include $(CLEAR_VARS) 25 | LOCAL_MODULE := gloss 26 | LOCAL_SRC_FILES := AML_PrecompiledLibs/$(TARGET_ARCH_ABI)/libGlossHook.a 27 | include $(PREBUILT_STATIC_LIBRARY) 28 | 29 | include $(CLEAR_VARS) 30 | LOCAL_MODULE := libz 31 | LOCAL_SRC_FILES := AML_PrecompiledLibs/$(TARGET_ARCH_ABI)/libz.a 32 | include $(PREBUILT_STATIC_LIBRARY) 33 | 34 | include $(CLEAR_VARS) 35 | LOCAL_MODULE := wolfssl 36 | LOCAL_SRC_FILES := AML_PrecompiledLibs/$(TARGET_ARCH_ABI)/libwolfssl.a 37 | include $(PREBUILT_STATIC_LIBRARY) 38 | 39 | include $(CLEAR_VARS) 40 | LOCAL_MODULE := curl 41 | LOCAL_SHARED_LIBRARIES := libz wolfssl 42 | LOCAL_SRC_FILES := AML_PrecompiledLibs/$(TARGET_ARCH_ABI)/libcurl.a 43 | include $(PREBUILT_STATIC_LIBRARY) 44 | 45 | 46 | # xUnwind 47 | 48 | include $(CLEAR_VARS) 49 | LOCAL_MODULE := xUnwind 50 | LOCAL_SHARED_LIBRARIES := armpatch 51 | LOCAL_SRC_FILES := AML_PrecompiledLibs/$(TARGET_ARCH_ABI)/libxUnwind.a 52 | include $(PREBUILT_STATIC_LIBRARY) 53 | 54 | 55 | # AML library 56 | 57 | include $(CLEAR_VARS) 58 | LOCAL_CPP_EXTENSION := .cpp .cc 59 | LOCAL_SHARED_LIBRARIES := armpatch substrate curl gloss xUnwind 60 | LOCAL_MODULE := AML 61 | LOCAL_SRC_FILES := main.cpp interface.cpp aml.cpp modpaks.cpp signal.cpp \ 62 | modslist.cpp icfg.cpp vtable_hooker.cpp alog.cpp mls.cpp \ 63 | mod/logger.cpp mod/config.cpp 64 | 65 | ## FLAGS ## 66 | LOCAL_CFLAGS += -O2 -mfloat-abi=softfp -DNDEBUG -D__AML -DNO_HOOKDEFINES -DFASTMAN92_CODE -std=c17 -mthumb 67 | LOCAL_CXXFLAGS += -O2 -mfloat-abi=softfp -DNDEBUG -D__AML -DNO_HOOKDEFINES -DFASTMAN92_CODE -std=c++17 -mthumb -fexceptions 68 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/curl $(LOCAL_PATH)/curl/include $(LOCAL_PATH)/wolfssl $(LOCAL_PATH)/AML_PrecompiledLibs/include 69 | LOCAL_LDLIBS += -llog -ldl -landroid 70 | 71 | # Uncomment these two lines to add IL2CPP support! (NOT WORKING) 72 | # LOCAL_SRC_FILES += il2cpp/gc.cpp il2cpp/functions.cpp 73 | # LOCAL_CFLAGS += -D__IL2CPPUTILS 74 | # Uncomment these two lines to add IL2CPP support! (NOT WORKING) 75 | 76 | ## BUILD ## 77 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /Application.mk: -------------------------------------------------------------------------------- 1 | APP_STL := c++_static 2 | APP_ABI := armeabi-v7a arm64-v8a 3 | APP_OPTIM := release 4 | APP_PLATFORM := android-21 5 | NDK_TOOLCHAIN_VERSION := clang -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 RusJJ 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What is that?! 2 | AML is a mod loader for almost ANY android game or application! 3 | 4 | AML has been started as a GTA-series mod loader AND as a Gorilla Tag mod loader. Since Gorilla Tag is a Unity-application, AML should be "upgraded" with some IL2CPP tools that are NOT ready now. That means you CAN mod for Unity-games but you NEED some external tools. 5 | 6 | # How is this working? 7 | AML provides you an interface system (like in Source Engine). You can add your own interfaces or get an AML Interface (does automatically on mod declaration) that can you help with: patching, memory writing, functions hooking & more (it uses ARMPatch that was made using of 4x11's ARMhook and DobbyHook). 8 | 9 | AML should be loaded after all libraries somehow. For example: added through the smali code (easiest way?). 10 | 11 | AML supports hard dependencies and can help you get info about mod (if it's loaded) just like a SOFT dependency. That's really cool. 12 | 13 | # Examples 14 | For any examples visit the repository for all official mods: https://github.com/AndroidModLoader?tab=repositories 15 | 16 | # Discord 17 | Discord Server of this project located here: https://discord.gg/2MY7W39kBg 18 | 19 | # Web 20 | We now have a WEB site everyone may use now! It`s still in progress so everything may look bad: https://aml-mods.ru/ 21 | 22 | # YouTube 23 | We DO have a YouTube channel but it`s inactive for a reason: https://www.youtube.com/@amloader 24 | -------------------------------------------------------------------------------- /alog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void* hAndroidLog; 9 | bool bAndroidLog_OnlyImportant, bAndroidLog_NoAfter; 10 | std::ofstream oAndroidLogFile; 11 | 12 | inline const char* EnumPriority(int prio) 13 | { 14 | switch(prio) 15 | { 16 | case ANDROID_LOG_UNKNOWN: return "UNKNOWN"; 17 | case ANDROID_LOG_DEFAULT: return "DEFAULT"; 18 | case ANDROID_LOG_VERBOSE: return "VERBOSE"; 19 | case ANDROID_LOG_DEBUG: return "DEBUG"; 20 | case ANDROID_LOG_INFO: return "INFO"; 21 | case ANDROID_LOG_WARN: return "WARN"; 22 | case ANDROID_LOG_ERROR: return "ERROR"; 23 | case ANDROID_LOG_FATAL: return "FATAL"; 24 | case ANDROID_LOG_SILENT: return "SILENT"; 25 | } 26 | return "UNKNOWN"; 27 | } 28 | inline bool IsImportantLogLevel(int prio) 29 | { 30 | switch(prio) 31 | { 32 | case ANDROID_LOG_DEBUG: 33 | case ANDROID_LOG_WARN: 34 | case ANDROID_LOG_ERROR: 35 | case ANDROID_LOG_FATAL: 36 | return true; 37 | } 38 | return false; 39 | } 40 | 41 | char text[4096]; // Log texts are not bigger than 4kb 42 | extern DECL_HOOKv(__aml_log_print, int prio, const char *tag, const char *fmt, ...); 43 | DECL_HOOKv(__aml_log_vprint, int prio, const char *tag, const char *fmt, va_list ap) 44 | { 45 | if(!fmt) return; 46 | if(!tag) tag = "AML: Untagged sender"; 47 | 48 | vsprintf(text, fmt, ap); 49 | __aml_log_print(prio, tag, text); 50 | 51 | if(bAndroidLog_OnlyImportant && !IsImportantLogLevel(prio)) return; 52 | 53 | time_t rawtime; 54 | time ( &rawtime ); 55 | 56 | oAndroidLogFile << asctime(localtime ( &rawtime )) << " [" << EnumPriority(prio) << "][AML Hook: " << tag << "] " << text << std::endl << std::endl; 57 | oAndroidLogFile.flush(); 58 | } 59 | 60 | DECL_HOOKv(__aml_log_print, int prio, const char *tag, const char *fmt, ...) 61 | { 62 | if(!fmt) return; 63 | 64 | va_list ap; 65 | va_start(ap, fmt); 66 | if(!bAndroidLog_NoAfter) HookOf___aml_log_vprint(prio, tag, fmt, ap); 67 | va_end(ap); 68 | } 69 | 70 | void HookALog() 71 | { 72 | hAndroidLog = aml->GetLibHandle("liblog.so"); 73 | if(!hAndroidLog) return; 74 | 75 | uintptr_t __android_log_print_addr = aml->GetSym(hAndroidLog, "__android_log_print"); 76 | uintptr_t __android_log_vprint_addr = aml->GetSym(hAndroidLog, "__android_log_vprint"); 77 | 78 | if(!__android_log_print_addr && !__android_log_vprint_addr) 79 | { 80 | logger->Error("AML Core just failed to patch logs function!"); 81 | return; 82 | } 83 | 84 | char path[320]; 85 | sprintf(path, "%s/android_log_print.txt", aml->GetAndroidDataRootPath()); 86 | oAndroidLogFile.open(path, std::ios::out | std::ios::trunc); 87 | 88 | if(oAndroidLogFile.is_open()) 89 | { 90 | if(__android_log_print_addr) HOOK(__aml_log_print, __android_log_print_addr); 91 | if(__android_log_vprint_addr) HOOK(__aml_log_vprint, __android_log_vprint_addr); 92 | } 93 | else 94 | { 95 | an_epic_fail_ever: 96 | logger->Error("AML Core just failed to open log file!"); 97 | } 98 | } -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | $NDKPath = Get-Content $PSScriptRoot/NDKPath.txt 2 | Write-Output "NDK located at: $NDKPath" 3 | 4 | $buildScript = "$NDKPath/build/ndk-build" 5 | if (-not ($PSVersionTable.PSEdition -eq "Core")) 6 | { 7 | $buildScript += ".cmd" 8 | } 9 | 10 | Write-Output "[BUILD] Starting NDK..." 11 | Write-Output "[BUILD] ARMPatch:" 12 | & $buildScript NDK_PROJECT_PATH=$PSScriptRoot APP_BUILD_SCRIPT=$PSScriptRoot/ARMPatch/armpatch_src/Android.mk NDK_APPLICATION_MK=$PSScriptRoot/ARMPatch/armpatch_src/Application.mk NDK_DEBUG=0 -j12 13 | Write-Output "[BUILD] AML:" 14 | & $buildScript NDK_PROJECT_PATH=$PSScriptRoot APP_BUILD_SCRIPT=$PSScriptRoot/Android.mk NDK_APPLICATION_MK=$PSScriptRoot/Application.mk NDK_DEBUG=0 -j12 15 | Write-Output "[BUILD] Done!" 16 | 17 | Exit $LASTEXITCODE -------------------------------------------------------------------------------- /icfg.cpp: -------------------------------------------------------------------------------- 1 | #ifndef DONT_USE_STB 2 | #include 3 | #define sprintf stbsp_sprintf 4 | #define snprintf stbsp_snprintf 5 | #endif 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | extern char g_szCfgPath[0xFF]; 14 | 15 | void* CFG::InitIniPointer() 16 | { 17 | void* ret = new ini::IniFile; 18 | return ret; 19 | } 20 | void CFG::ParseInputStream(void* iniPointer, const char* szFilename) 21 | { 22 | char path[0xFF]; 23 | snprintf(path, sizeof(path), "%s/%s.ini", g_szCfgPath, szFilename); 24 | ((ini::IniFile*)iniPointer)->load(path); 25 | } 26 | void CFG::GenerateToOutputStream(void* iniPointer, const char* szFilename) 27 | { 28 | char path[0xFF]; 29 | snprintf(path, sizeof(path), "%s/%s.ini", g_szCfgPath, szFilename); 30 | ((ini::IniFile*)iniPointer)->save(path); 31 | } 32 | const char* CFG::GetValueFrom(void* iniPointer, const char* szSection, const char* szKey) 33 | { 34 | return (*(ini::IniFile*)iniPointer)[szSection][szKey].as(); 35 | } 36 | void CFG::SetValueTo(void* iniPointer, const char* szSection, const char* szKey, const char* szValue) 37 | { 38 | (*(ini::IniFile*)iniPointer)[szSection][szKey] = szValue; 39 | } 40 | -------------------------------------------------------------------------------- /icfg_desc.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class CFG : public ICFG 4 | { 5 | public: 6 | void* InitIniPointer(); 7 | void ParseInputStream(void* iniPointer, const char* szFilename); 8 | void GenerateToOutputStream(void* iniPointer, const char* szFilename); 9 | const char* GetValueFrom(void* iniPointer, const char* szSection, const char* szKey); 10 | void SetValueTo(void* iniPointer, const char* szSection, const char* szKey, const char* szValue); 11 | }; -------------------------------------------------------------------------------- /il2cpp/functions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace IL2CPP::Func 6 | { 7 | void* pIL2CPP = NULL; 8 | static bool m_bInitialized = false; 9 | void HookFunctions() 10 | { 11 | if(m_bInitialized) return; 12 | 13 | if(!(pIL2CPP = dlopen("libil2cpp.so", RTLD_LAZY))) 14 | { 15 | logger->Error("IL2CPP: Looks like this is not a Unity game?"); 16 | return; 17 | } 18 | 19 | m_bInitialized = true; 20 | } 21 | } -------------------------------------------------------------------------------- /il2cpp/functions.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "types.h" 3 | #include "typedefs.h" 4 | 5 | namespace IL2CPP::Func 6 | { 7 | /* Just a functions of our Utils */ 8 | void HookFunctions(); 9 | 10 | /* Pointers to IL2 functions */ 11 | #ifdef UNITY_2019 12 | int (*init)(const char* domain_name); 13 | int (*init_utf16)(const IL2Char * domain_name); 14 | #else 15 | void (*init)(const char* domain_name); 16 | void (*init_utf16)(const IL2Char * domain_name); 17 | #endif 18 | void (*shutdown)(); 19 | void (*set_config_dir)(const char *config_path); 20 | void (*set_data_dir)(const char *data_path); 21 | void (*set_temp_dir)(const char *temp_path); 22 | void (*set_commandline_arguments)(int argc, const char* const argv[], const char* basedir); 23 | void (*set_commandline_arguments_utf16)(int argc, const IL2Char * const argv[], const char* basedir); 24 | void (*set_config_utf16)(const IL2Char * executablePath); 25 | void (*set_config)(const char* executablePath); 26 | void (*set_memory_callbacks)(IL2MemoryCallbacks * callbacks); 27 | const IL2Image* (*get_corlib)(); 28 | void (*add_internal_call)(const char* name, IL2MethodPointer method); 29 | IL2MethodPointer (*resolve_icall)(const char* name); 30 | void* (*alloc)(size_t size); 31 | void (*free)(void* ptr); 32 | IL2Class* (*array_class_get)(IL2Class * element_class, uint32_t rank); 33 | uint32_t (*array_length)(IL2Array * array); 34 | uint32_t (*array_get_byte_length)(IL2Array * array); 35 | IL2Array* (*array_new)(IL2Class * elementTypeInfo, IL2ArraySize_t length); 36 | IL2Array* (*array_new_specific)(IL2Class * arrayTypeInfo, IL2ArraySize_t length); 37 | IL2Array* (*array_new_full)(IL2Class * array_class, IL2ArraySize_t * lengths, IL2ArraySize_t * lower_bounds); 38 | IL2Class* (*bounded_array_class_get)(IL2Class * element_class, uint32_t rank, bool bounded); 39 | int (*array_element_size)(const IL2Class * array_class); 40 | const IL2Image* (*assembly_get_image)(const IL2Assembly * assembly); 41 | #ifdef UNITY_2019 42 | void (*class_for_each)(void(*klassReportFunc)(IL2Class* klass, void* userData), void* userData); 43 | #endif 44 | const IL2Type* (*class_enum_basetype)(IL2Class * klass); 45 | bool (*class_is_generic)(const IL2Class * klass); 46 | bool (*class_is_inflated)(const IL2Class * klass); 47 | bool (*class_is_assignable_from)(IL2Class * klass, IL2Class * oklass); 48 | bool (*class_is_subclass_of)(IL2Class * klass, IL2Class * klassc, bool check_interfaces); 49 | bool (*class_has_parent)(IL2Class * klass, IL2Class * klassc); 50 | IL2Class* (*class_from_IL2_type)(const IL2Type * type); 51 | IL2Class* (*class_from_name)(const IL2Image * image, const char* namespaze, const char *name); 52 | IL2Class* (*class_from_system_type)(IL2ReflectionType * type); 53 | IL2Class* (*class_get_element_class)(IL2Class * klass); 54 | const EventInfo* (*class_get_events)(IL2Class * klass, void* *iter); 55 | FieldInfo* (*class_get_fields)(IL2Class * klass, void* *iter); 56 | IL2Class* (*class_get_nested_types)(IL2Class * klass, void* *iter); 57 | IL2Class* (*class_get_interfaces)(IL2Class * klass, void* *iter); 58 | const PropertyInfo* (*class_get_properties)(IL2Class * klass, void* *iter); 59 | const PropertyInfo* (*class_get_property_from_name)(IL2Class * klass, const char *name); 60 | FieldInfo* (*class_get_field_from_name)(IL2Class * klass, const char *name); 61 | const MethodInfo* (*class_get_methods)(IL2Class * klass, void* *iter); 62 | const MethodInfo* (*class_get_method_from_name)(const IL2Class * klass, const char* name, int argsCount); 63 | const char* (*class_get_name)(const IL2Class * klass); 64 | #ifdef UNITY_2019 65 | void (*type_get_name_chunked)(const IL2Type * type, void(*chunkReportFunc)(void* data, void* userData), void* userData); 66 | #endif 67 | const char* (*class_get_namespace)(const IL2Class * klass); 68 | IL2Class* (*class_get_parent)(IL2Class * klass); 69 | IL2Class* (*class_get_declaring_type)(const IL2Class * klass); 70 | int32_t (*class_instance_size)(IL2Class * klass); 71 | size_t (*class_num_fields)(const IL2Class * enumKlass); 72 | bool (*class_is_valuetype)(const IL2Class * klass); 73 | int32_t (*class_value_size)(IL2Class * klass, uint32_t * align); 74 | bool (*class_is_blittable)(const IL2Class * klass); 75 | int (*class_get_flags)(const IL2Class * klass); 76 | bool (*class_is_abstract)(const IL2Class * klass); 77 | bool (*class_is_interface)(const IL2Class * klass); 78 | int (*class_array_element_size)(const IL2Class * klass); 79 | IL2Class* (*class_from_type)(const IL2Type * type); 80 | const IL2Type* (*class_get_type)(IL2Class * klass); 81 | uint32_t (*class_get_type_token)(IL2Class * klass); 82 | bool (*class_has_attribute)(IL2Class * klass, IL2Class * attr_class); 83 | bool (*class_has_references)(IL2Class * klass); 84 | bool (*class_is_enum)(const IL2Class * klass); 85 | const IL2Image* (*class_get_image)(IL2Class * klass); 86 | const char* (*class_get_assemblyname)(const IL2Class * klass); 87 | int (*class_get_rank)(const IL2Class * klass); 88 | #ifdef UNITY_2019 89 | uint32_t (*class_get_data_size)(const IL2Class * klass); 90 | void* (*class_get_static_field_data)(const IL2Class * klass); 91 | #endif 92 | size_t (*class_get_bitmap_size)(const IL2Class * klass); 93 | void (*class_get_bitmap)(IL2Class * klass, size_t * bitmap); 94 | bool (*stats_dump_to_file)(const char *path); 95 | uint64_t (*stats_get_value)(IL2Stat stat); 96 | IL2Domain* (*domain_get)(); 97 | const IL2Assembly* (*domain_assembly_open)(IL2Domain * domain, const char* name); 98 | const IL2Assembly** (*domain_get_assemblies)(const IL2Domain * domain, size_t * size); 99 | #ifdef UNITY_2019 100 | void (*raise_exception)(IL2Exception*); 101 | #endif 102 | IL2Exception* (*exception_from_name_msg)(const IL2Image * image, const char *name_space, const char *name, const char *msg); 103 | IL2Exception* (*get_exception_argument_null)(const char *arg); 104 | void (*format_exception)(const IL2Exception * ex, char* message, int message_size); 105 | void (*format_stack_trace)(const IL2Exception * ex, char* output, int output_size); 106 | void (*unhandled_exception)(IL2Exception*); 107 | int (*field_get_flags)(FieldInfo * field); 108 | const char* (*field_get_name)(FieldInfo * field); 109 | IL2Class* (*field_get_parent)(FieldInfo * field); 110 | size_t (*field_get_offset)(FieldInfo * field); 111 | const IL2Type* (*field_get_type)(FieldInfo * field); 112 | void (*field_get_value)(IL2Object * obj, FieldInfo * field, void *value); 113 | IL2Object* (*field_get_value_object)(FieldInfo * field, IL2Object * obj); 114 | bool (*field_has_attribute)(FieldInfo * field, IL2Class * attr_class); 115 | void (*field_set_value)(IL2Object * obj, FieldInfo * field, void *value); 116 | void (*field_static_get_value)(FieldInfo * field, void *value); 117 | void (*field_static_set_value)(FieldInfo * field, void *value); 118 | void (*field_set_value_object)(IL2Object * instance, FieldInfo * field, IL2Object * value); 119 | #ifdef UNITY_2019 120 | bool (*field_is_literal)(FieldInfo * field); 121 | #endif 122 | void (*gc_collect)(int maxGenerations); 123 | int32_t (*gc_collect_a_little)(); 124 | void (*gc_disable)(); 125 | void (*gc_enable)(); 126 | bool (*gc_is_disabled)(); 127 | #ifdef UNITY_2019 128 | int64_t (*gc_get_max_time_slice_ns)(); 129 | void (*gc_set_max_time_slice_ns)(int64_t maxTimeSlice); 130 | bool (*gc_is_incremental)(); 131 | #endif 132 | int64_t (*gc_get_used_size)(); 133 | int64_t (*gc_get_heap_size)(); 134 | void (*gc_wbarrier_set_field)(IL2Object * obj, void **targetAddress, void *object); 135 | #ifdef UNITY_2019 136 | bool (*gc_has_strict_wbarriers)(); 137 | void (*gc_set_external_allocation_tracker)(void(*func)(void*, size_t, int)); 138 | void (*gc_set_external_wbarrier_tracker)(void(*func)(void**)); 139 | void (*gc_foreach_heap)(void(*func)(void* data, void* userData), void* userData); 140 | void (*stop_gc_world)(); 141 | void (*start_gc_world)(); 142 | #endif 143 | uint32_t (*gchandle_new)(IL2Object * obj, bool pinned); 144 | uint32_t (*gchandle_new_weakref)(IL2Object * obj, bool track_resurrection); 145 | IL2Object* (*gchandle_get_target)(uint32_t gchandle); 146 | void (*gchandle_free)(uint32_t gchandle); 147 | #ifdef UNITY_2019 148 | void (*gchandle_foreach_get_target)(void(*func)(void* data, void* userData), void* userData); 149 | uint32_t (*object_header_size)(); 150 | uint32_t (*array_object_header_size)(); 151 | uint32_t (*offset_of_array_length_in_array_object_header)(); 152 | uint32_t (*offset_of_array_bounds_in_array_object_header)(); 153 | uint32_t (*allocation_granularity)(); 154 | #endif 155 | void* (*unity_liveness_calculation_begin)(IL2Class * filter, int max_object_count, IL2RegisterObjectCB callback, void* userdata, IL2WorldChangedCB onWorldStarted, IL2WorldChangedCB onWorldStopped); 156 | void (*unity_liveness_calculation_end)(void* state); 157 | void (*unity_liveness_calculation_from_root)(IL2Object * root, void* state); 158 | void (*unity_liveness_calculation_from_statics)(void* state); 159 | const IL2Type* (*method_get_return_type)(const MethodInfo * method); 160 | IL2Class* (*method_get_declaring_type)(const MethodInfo * method); 161 | const char* (*method_get_name)(const MethodInfo * method); 162 | const MethodInfo* (*method_get_from_reflection)(const IL2ReflectionMethod * method); 163 | IL2ReflectionMethod* (*method_get_object)(const MethodInfo * method, IL2Class * refclass); 164 | bool (*method_is_generic)(const MethodInfo * method); 165 | bool (*method_is_inflated)(const MethodInfo * method); 166 | bool (*method_is_instance)(const MethodInfo * method); 167 | uint32_t (*method_get_param_count)(const MethodInfo * method); 168 | const IL2Type* (*method_get_param)(const MethodInfo * method, uint32_t index); 169 | IL2Class* (*method_get_class)(const MethodInfo * method); 170 | bool (*method_has_attribute)(const MethodInfo * method, IL2Class * attr_class); 171 | uint32_t (*method_get_flags)(const MethodInfo * method, uint32_t * iflags); 172 | uint32_t (*method_get_token)(const MethodInfo * method); 173 | const char* (*method_get_param_name)(const MethodInfo * method, uint32_t index); 174 | 175 | // ONLY IF THE PROFILER EXISTS FOR UNITY_2019 176 | void (*profiler_install)(IL2Profiler * prof, IL2ProfileFunc shutdown_callback); 177 | void (*profiler_set_events)(IL2ProfileFlags events); 178 | void (*profiler_install_enter_leave)(IL2ProfileMethodFunc enter, IL2ProfileMethodFunc fleave); 179 | void (*profiler_install_allocation)(IL2ProfileAllocFunc callback); 180 | void (*profiler_install_gc)(IL2ProfileGCFunc callback, IL2ProfileGCResizeFunc heap_resize_callback); 181 | void (*profiler_install_fileio)(IL2ProfileFileIOFunc callback); 182 | void (*profiler_install_thread)(IL2ProfileThreadFunc start, IL2ProfileThreadFunc end); 183 | 184 | uint32_t (*property_get_flags)(const PropertyInfo * prop); 185 | const MethodInfo* (*property_get_get_method)(const PropertyInfo * prop); 186 | const MethodInfo* (*property_get_set_method)(const PropertyInfo * prop); 187 | const char* (*property_get_name)(const PropertyInfo * prop); 188 | IL2Class* (*property_get_parent)(const PropertyInfo * prop); 189 | IL2Class* (*object_get_class)(IL2Object * obj); 190 | uint32_t (*object_get_size)(IL2Object * obj); 191 | const MethodInfo* (*object_get_virtual_method)(IL2Object * obj, const MethodInfo * method); 192 | IL2Object* (*object_new)(const IL2Class * klass); 193 | void* (*object_unbox)(IL2Object * obj); 194 | IL2Object* (*value_box)(IL2Class * klass, void* data); 195 | void (*monitor_enter)(IL2Object * obj); 196 | bool (*monitor_try_enter)(IL2Object * obj, uint32_t timeout); 197 | void (*monitor_exit)(IL2Object * obj); 198 | void (*monitor_pulse)(IL2Object * obj); 199 | void (*monitor_pulse_all)(IL2Object * obj); 200 | void (*monitor_wait)(IL2Object * obj); 201 | bool (*monitor_try_wait)(IL2Object * obj, uint32_t timeout); 202 | IL2Object* (*runtime_invoke)(const MethodInfo * method, void *obj, void **params, IL2Exception **exc); 203 | IL2Object* (*runtime_invoke_convert_args)(const MethodInfo * method, void *obj, IL2Object **params, int paramCount, IL2Exception **exc); 204 | void (*runtime_class_init)(IL2Class * klass); 205 | void (*runtime_object_init)(IL2Object * obj); 206 | void (*runtime_object_init_exception)(IL2Object * obj, IL2Exception** exc); 207 | void (*runtime_unhandled_exception_policy_set)(IL2RuntimeUnhandledExceptionPolicy value); 208 | int32_t (*string_length)(IL2String * str); 209 | IL2Char* (*string_chars)(IL2String * str); 210 | IL2String* (*string_new)(const char* str); 211 | IL2String* (*string_new_len)(const char* str, uint32_t length); 212 | IL2String* (*string_new_utf16)(const IL2Char * text, int32_t len); 213 | IL2String* (*string_new_wrapper)(const char* str); 214 | IL2String* (*string_intern)(IL2String * str); 215 | IL2String* (*string_is_interned)(IL2String * str); 216 | IL2Thread* (*thread_current)(); 217 | IL2Thread* (*thread_attach)(IL2Domain * domain); 218 | void (*thread_detach)(IL2Thread * thread); 219 | IL2Thread** (*thread_get_all_attached_threads)(size_t * size); 220 | bool (*is_vm_thread)(IL2Thread * thread); 221 | void (*current_thread_walk_frame_stack)(IL2FrameWalkFunc func, void* user_data); 222 | void (*thread_walk_frame_stack)(IL2Thread * thread, IL2FrameWalkFunc func, void* user_data); 223 | bool (*current_thread_get_top_frame)(IL2StackFrameInfo * frame); 224 | bool (*thread_get_top_frame)(IL2Thread * thread, IL2StackFrameInfo * frame); 225 | bool (*current_thread_get_frame_at)(int32_t offset, IL2StackFrameInfo * frame); 226 | bool (*thread_get_frame_at)(IL2Thread * thread, int32_t offset, IL2StackFrameInfo * frame); 227 | int32_t (*current_thread_get_stack_depth)(); 228 | int32_t (*thread_get_stack_depth)(IL2Thread * thread); 229 | #ifdef UNITY_2019 230 | void (*override_stack_backtrace)(IL2BacktraceFunc stackBacktraceFunc); 231 | #endif 232 | IL2Object* (*type_get_object)(const IL2Type * type); 233 | int (*type_get_type)(const IL2Type * type); 234 | IL2Class* (*type_get_class_or_element_class)(const IL2Type * type); 235 | char* (*type_get_name)(const IL2Type * type); 236 | bool (*type_is_byref)(const IL2Type * type); 237 | uint32_t (*type_get_attrs)(const IL2Type * type); 238 | bool (*type_equals)(const IL2Type * type, const IL2Type * otherType); 239 | char* (*type_get_assembly_qualified_name)(const IL2Type * type); 240 | #ifdef UNITY_2019 241 | bool (*type_is_static)(const IL2Type * type); 242 | bool (*type_is_pointer_type)(const IL2Type * type); 243 | #endif 244 | const IL2Assembly* (*image_get_assembly)(const IL2Image * image); 245 | const char* (*image_get_name)(const IL2Image * image); 246 | const char* (*image_get_filename)(const IL2Image * image); 247 | const MethodInfo* (*image_get_entry_point)(const IL2Image * image); 248 | size_t (*image_get_class_count)(const IL2Image * image); 249 | const IL2Class* (*image_get_class)(const IL2Image * image, size_t index); 250 | IL2ManagedMemorySnapshot* (*capture_memory_snapshot)(); 251 | void (*free_captured_memory_snapshot)(IL2ManagedMemorySnapshot * snapshot); 252 | void (*set_find_plugin_callback)(IL2SetFindPlugInCallback method); 253 | void (*register_log_callback)(IL2LogCallback method); 254 | void (*debugger_set_agent_options)(const char* options); 255 | bool (*is_debugger_attached)(); 256 | #ifdef UNITY_2019 257 | void (*register_debugger_agent_transport)(IL2DebuggerTransport * debuggerTransport); 258 | bool (*debug_get_method_info)(const MethodInfo*, IL2MethodDebugInfo * methodDebugInfo); 259 | #endif 260 | void (*unity_install_unitytls_interface)(const void* unitytlsInterfaceStruct); 261 | IL2CustomAttrInfo* (*custom_attrs_from_class)(IL2Class * klass); 262 | IL2CustomAttrInfo* (*custom_attrs_from_method)(const MethodInfo * method); 263 | IL2Object* (*custom_attrs_get_attr)(IL2CustomAttrInfo * ainfo, IL2Class * attr_klass); 264 | bool (*custom_attrs_has_attr)(IL2CustomAttrInfo * ainfo, IL2Class * attr_klass); 265 | IL2Array* (*custom_attrs_construct)(IL2CustomAttrInfo * cinfo); 266 | void (*custom_attrs_free)(IL2CustomAttrInfo * ainfo); 267 | #ifdef UNITY_2019 268 | void (*class_set_userdata)(IL2Class * klass, void* userdata); 269 | int (*class_get_userdata_offset)(); 270 | #endif 271 | } -------------------------------------------------------------------------------- /il2cpp/gc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace IL2CPP::GC 5 | { 6 | void Free(void* ptr) 7 | { 8 | 9 | } 10 | void* Alloc(size_t size) 11 | { 12 | void* ptr; 13 | 14 | return ptr; 15 | } 16 | void* Realloc(void* ptr, size_t size) 17 | { 18 | void* ptr_new; 19 | memcpy(ptr_new, ptr, size); 20 | Free(ptr); 21 | return ptr_new; 22 | } 23 | } -------------------------------------------------------------------------------- /il2cpp/typedefs.h: -------------------------------------------------------------------------------- 1 | typedef size_t il2cpp_array_size_t; -------------------------------------------------------------------------------- /il2cpp/types.h: -------------------------------------------------------------------------------- 1 | struct IL2Assembly; 2 | struct IL2Object; 3 | struct IL2Class; 4 | struct IL2Image; 5 | struct IL2Array; 6 | struct IL2Type; 7 | struct IL2Char; 8 | struct IL2Domain; 9 | struct IL2ReflectionType; 10 | struct IL2Exception; 11 | struct IL2Profiler; 12 | struct IL2String; 13 | struct IL2ProfileFunc; 14 | struct IL2Thread; 15 | struct IL2ReflectionMethod; 16 | struct IL2ManagedMemorySnapshot; 17 | struct IL2StackFrameInfo; 18 | struct IL2CustomAttrInfo; 19 | struct IL2GenericClass; 20 | struct IL2Defaults; 21 | struct IL2MemoryCallbacks; 22 | struct IL2MethodPointer; 23 | struct IL2TypeDefinition; 24 | struct IL2GenericParameter; 25 | struct IL2GenericContainer; 26 | struct Il2CppDomain; 27 | struct IL2ProfileFlags; 28 | struct IL2ProfileMethodFunc; 29 | struct IL2ProfileAllocFunc; 30 | struct IL2ProfileGCFunc; 31 | struct IL2ProfileFileIOFunc; 32 | struct IL2ProfileThreadFunc; 33 | struct IL2RegisterObjectCB; 34 | struct IL2WorldChangedCB; 35 | 36 | struct IL2LogCallback; 37 | struct IL2SetFindPlugInCallback; 38 | struct IL2FrameWalkFunc; 39 | struct IL2RuntimeUnhandledExceptionPolicy; 40 | struct IL2ProfileGCResizeFunc; 41 | struct IL2Stat; 42 | struct IL2ArraySize_t; 43 | 44 | struct MethodInfo; 45 | struct FieldInfo; 46 | struct PropertyInfo; 47 | struct EventInfo; -------------------------------------------------------------------------------- /include/aml.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class AML : public IAML 4 | { 5 | public: 6 | /* AML 1.0.0.0 */ 7 | const char* GetCurrentGame(); 8 | const char* GetConfigPath(); 9 | bool HasMod(const char* szGUID); 10 | bool HasModOfVersion(const char* szGUID, const char* szVersion); 11 | uintptr_t GetLib(const char* szLib); 12 | uintptr_t GetSym(void* handle, const char* sym); 13 | bool Hook(void* handle, void* fnAddress, void** orgFnAddress = NULL); 14 | bool HookPLT(void* handle, void* fnAddress, void** orgFnAddress = NULL); 15 | int Unprot(uintptr_t handle, size_t len = PAGE_SIZE); 16 | void Write(uintptr_t dest, uintptr_t src, size_t size); 17 | void Read(uintptr_t src, uintptr_t dest, size_t size); 18 | int PlaceNOP(uintptr_t addr, size_t count = 1); 19 | int PlaceJMP(uintptr_t addr, uintptr_t dest); 20 | int PlaceRET(uintptr_t addr); 21 | /* AML 1.0.0.4 */ 22 | const char* GetDataPath(); 23 | /* AML 1.0.0.5 */ 24 | const char* GetAndroidDataPath(); 25 | uintptr_t GetSym(uintptr_t libAddr, const char* sym); 26 | /* AML 1.0.0.6 */ 27 | uintptr_t GetLibLength(const char* szLib); 28 | int Redirect(uintptr_t addr, uintptr_t to); 29 | void PlaceBL(uintptr_t addr, uintptr_t dest); 30 | void PlaceBLX(uintptr_t addr, uintptr_t dest); 31 | uintptr_t PatternScan(const char* pattern, const char* soLib); 32 | uintptr_t PatternScan(const char* pattern, uintptr_t libStart, uintptr_t scanLen); 33 | /* AML 1.0.1 */ 34 | void PatchForThumb(bool forThumb); 35 | const char* GetFeatures(); 36 | void AddFeature(const char* feature); // Not in interface 37 | void HookVtableFunc(void* ptr, unsigned int funcNum, void* fnAddress, void** orgFnAddress = NULL, bool instantiate = false); 38 | bool IsGameFaked(); 39 | const char* GetRealCurrentGame(); 40 | void* GetLibHandle(const char* soLib); 41 | void* GetLibHandle(uintptr_t addr); 42 | // xDL 43 | bool IsCorrectXDLHandle(void* ptr); 44 | uintptr_t GetLibXDL(void* ptr); 45 | uintptr_t GetAddrBaseXDL(uintptr_t addr); 46 | size_t GetSymSizeXDL(void* ptr); 47 | const char* GetSymNameXDL(void* ptr); 48 | /* AML 1.0.2 */ 49 | void ShowToast(bool longerDuration, const char* fmt, ...); 50 | bool DownloadFile(const char* url, const char* saveto); 51 | bool DownloadFileToData(const char* url, char* out, size_t outLen); 52 | void FileMD5(const char* path, char* out, size_t out_len); 53 | int GetModsLoadedCount(); 54 | JNIEnv* GetJNIEnvironment(); 55 | jobject GetAppContextObject(); 56 | /* AML 1.0.2.1 */ 57 | bool HasModOfBiggerVersion(const char* szGUID, const char* szVersion); 58 | /* AML 1.0.4 */ 59 | void HookVtableFunc(void* ptr, unsigned int funcNum, unsigned int count, void* fnAddress, void** orgFnAddress = NULL, bool instantiate = false); 60 | int PlaceNOP4(uintptr_t addr, size_t count = 1); 61 | const char* GetAndroidDataRootPath(); 62 | // GlossHook 63 | bool HookB(void* handle, void* fnAddress, void** orgFnAddress = NULL); 64 | bool HookBL(void* handle, void* fnAddress, void** orgFnAddress = NULL); 65 | bool HookBLX(void* handle, void* fnAddress, void** orgFnAddress = NULL); 66 | /* AML 1.2 */ 67 | void MLSSaveFile(); 68 | bool MLSHasValue(const char* key); 69 | void MLSDeleteValue(const char* key); 70 | void MLSSetInt(const char* key, int32_t val); 71 | void MLSSetFloat(const char* key, float val); 72 | void MLSSetInt64(const char* key, int64_t val); 73 | void MLSSetStr(const char* key, const char *val); 74 | bool MLSGetInt(const char* key, int32_t *val); 75 | bool MLSGetFloat(const char* key, float *val); 76 | bool MLSGetInt64(const char* key, int64_t *val); 77 | bool MLSGetStr(const char* key, char *val, size_t len); 78 | /* AML 1.2.1 */ 79 | bool IsThumbAddr(uintptr_t addr); 80 | uintptr_t GetBranchDest(uintptr_t addr); 81 | /* AML 1.2.2 */ 82 | int GetAndroidVersion(); 83 | bool CopyFile(const char* file, const char* dest); 84 | void RedirectReg(uintptr_t addr, uintptr_t to, bool doShortHook, GlossRegisters::e_reg targetReg); 85 | bool HasAddrExecFlag(uintptr_t addr); 86 | void ToggleHook(PHookHandle hook, bool enable); 87 | void DeHook(PHookHandle hook); 88 | PHookHandle HookInline(void* fnAddress, HookWithRegistersFn newFn, bool doShortHook = false); 89 | /* AML 1.2.3 */ 90 | bool HasFastmanAPKModified(); 91 | const char* GetInternalPath(); 92 | const char* GetInternalModsPath(); 93 | /* AML 1.3.0 */ 94 | JavaVM* GetJavaVM(); 95 | jobject GetCurrentContext(); 96 | void DoVibro(int msTime); 97 | void DoVibro(jlong* pattern, int patternItems); 98 | void CancelVibro(); 99 | float GetBatteryLevel(); 100 | }; 101 | 102 | extern char g_szAMLFeatures[2048]; 103 | extern AML* g_pAML; 104 | extern int g_nAndroidSDKVersion; -------------------------------------------------------------------------------- /include/defines.h: -------------------------------------------------------------------------------- 1 | #define CONVERT_THIS_MACRO_CONTENTS_TO_STRING(_macro) #_macro 2 | #define MACROSTRING(_macro) CONVERT_THIS_MACRO_CONTENTS_TO_STRING(_macro) // Use this. -------------------------------------------------------------------------------- /include/interfaces.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class InterfaceSys 4 | { 5 | public: 6 | void Register(const char* szInterfaceName, void* pInterfacePointer); 7 | void* Get(const char* szInterfaceName); 8 | }; 9 | 10 | extern InterfaceSys* interfaces; -------------------------------------------------------------------------------- /include/jnifn.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern JavaVM *g_pJavaVM; 4 | 5 | inline jobject GetGlobalContext(JNIEnv *env) 6 | { 7 | jclass activityThread = env->FindClass("android/app/ActivityThread"); 8 | jmethodID currentActivityThread = env->GetStaticMethodID(activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;"); 9 | jobject at = env->CallStaticObjectMethod(activityThread, currentActivityThread); 10 | jmethodID getApplication = env->GetMethodID(activityThread, "getApplication", "()Landroid/app/Application;"); 11 | jobject context = env->CallObjectMethod(at, getApplication); 12 | if (env->ExceptionCheck()) env->ExceptionClear(); 13 | return context; 14 | } 15 | 16 | inline jobject GetGlobalActivity(JNIEnv *env) 17 | { 18 | jclass activityThread = env->FindClass("android/app/ActivityThread"); 19 | jmethodID currentActivityThread = env->GetStaticMethodID(activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;"); 20 | jobject at = env->CallStaticObjectMethod(activityThread, currentActivityThread); 21 | jmethodID getApplication = env->GetMethodID(activityThread, "getApplication", "()Landroid/app/Application;"); 22 | jobject context = env->CallObjectMethod(at, getApplication); 23 | if (env->ExceptionCheck()) env->ExceptionClear(); 24 | return context; 25 | } 26 | 27 | inline jstring GetPackageName(JNIEnv *env, jobject jActivity) 28 | { 29 | jmethodID method = env->GetMethodID(env->GetObjectClass(jActivity), "getPackageName", "()Ljava/lang/String;"); 30 | jstring ret = (jstring)env->CallObjectMethod(jActivity, method); 31 | if (env->ExceptionCheck()) env->ExceptionClear(); 32 | return ret; 33 | } 34 | 35 | inline jobject GetFilesDir(JNIEnv *env, jobject jActivity) 36 | { 37 | jmethodID method = env->GetMethodID(env->GetObjectClass(jActivity), "getFilesDir", "()Ljava/io/File;"); 38 | jstring ret = (jstring)env->CallObjectMethod(jActivity, method); 39 | if (env->ExceptionCheck()) env->ExceptionClear(); 40 | return ret; 41 | } 42 | 43 | inline jstring GetAbsolutePath(JNIEnv *env, jobject jFile) 44 | { 45 | jmethodID method = env->GetMethodID(env->GetObjectClass(jFile), "getAbsolutePath", "()Ljava/lang/String;"); 46 | jstring ret = (jstring)env->CallObjectMethod(jFile, method); 47 | if (env->ExceptionCheck()) env->ExceptionClear(); 48 | return ret; 49 | } 50 | 51 | inline jstring GetAndroidPermission(JNIEnv* env, const char* szPermissionName) 52 | { 53 | jclass ClassManifestPermission = env->FindClass("android/Manifest$permission"); 54 | jfieldID lid_PERM = env->GetStaticFieldID(ClassManifestPermission, szPermissionName, "Ljava/lang/String;"); 55 | jstring ret = (jstring)env->GetStaticObjectField(ClassManifestPermission, lid_PERM); 56 | if (env->ExceptionCheck()) env->ExceptionClear(); 57 | return ret; 58 | } 59 | 60 | inline bool HasPermissionGranted(JNIEnv* env, jobject jActivity, const char* szPermissionName) 61 | { 62 | jclass ClassPackageManager = env->FindClass("android/content/pm/PackageManager"); 63 | //bool result = false; 64 | jstring ls_PERM = GetAndroidPermission(env, szPermissionName); 65 | jfieldID lid_PERMISSION_GRANTED = env->GetStaticFieldID(ClassPackageManager, "PERMISSION_GRANTED", "I"); 66 | jint PERMISSION_GRANTED = jint(-1); 67 | 68 | PERMISSION_GRANTED = env->GetStaticIntField(ClassPackageManager, lid_PERMISSION_GRANTED); 69 | jint int_result = env->CallIntMethod(jActivity, env->GetMethodID(env->FindClass("android/content/Context"), "checkSelfPermission", "(Ljava/lang/String;)I"), ls_PERM); 70 | if (env->ExceptionCheck()) env->ExceptionClear(); 71 | return (int_result == PERMISSION_GRANTED); 72 | } 73 | 74 | /*inline void RequestPermissions(JNIEnv* env, jobject jActivity) 75 | { 76 | jobjectArray perm_array = env->NewObjectArray(2, env->FindClass("java/lang/String"), env->NewStringUTF("")); 77 | env->SetObjectArrayElement(perm_array, 0, GetAndroidPermission(env, "READ_EXTERNAL_STORAGE")); 78 | env->SetObjectArrayElement(perm_array, 1, GetAndroidPermission(env, "WRITE_EXTERNAL_STORAGE")); 79 | env->CallVoidMethod(jActivity, env->GetMethodID(env->FindClass("android/app/Activity"), "requestPermissions", "([Ljava/lang/String;I)V"), perm_array, 0); 80 | }*/ 81 | 82 | inline jobject GetExternalFilesDir(JNIEnv* env, jobject jActivity) // getExternalFilesDir creates directory in Android/data, lol 83 | { 84 | jmethodID method = env->GetMethodID(env->GetObjectClass(jActivity), "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); 85 | jstring ret = (jstring)env->CallObjectMethod(jActivity, method, NULL); 86 | if (env->ExceptionCheck()) env->ExceptionClear(); 87 | return ret; 88 | } 89 | 90 | // fastman92 91 | #ifdef FASTMAN92_CODE 92 | inline bool GetExternalFilesDir_FLA(JNIEnv* env, jobject context, char* strPath, size_t bufferSize) 93 | { 94 | jobject objectFile; 95 | bool bReadFromF92launcher = false; 96 | jmethodID methodIDgetExternalFilesDir; 97 | 98 | jclass classF92launcherSettings = env->FindClass("com/fastman92/main_activity_launcher/Settings"); 99 | 100 | if (classF92launcherSettings) 101 | { 102 | methodIDgetExternalFilesDir = env->GetStaticMethodID(classF92launcherSettings, "getExternalFilesDir", "(Landroid/content/Context;)Ljava/io/File;"); 103 | 104 | if (methodIDgetExternalFilesDir) 105 | { 106 | objectFile = env->CallStaticObjectMethod(classF92launcherSettings, methodIDgetExternalFilesDir, context); 107 | bReadFromF92launcher = true; 108 | } 109 | } 110 | 111 | if (!bReadFromF92launcher) 112 | { 113 | if (env->ExceptionCheck()) env->ExceptionClear(); 114 | 115 | jclass android_content_Context = env->GetObjectClass(context); 116 | 117 | methodIDgetExternalFilesDir = env->GetMethodID(android_content_Context, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); 118 | 119 | objectFile = (jstring)env->CallObjectMethod(context, methodIDgetExternalFilesDir, nullptr); 120 | } 121 | 122 | jclass classFile = env->GetObjectClass(objectFile); 123 | 124 | jmethodID methodIDgetAbsolutePath = env->GetMethodID(classFile, "getAbsolutePath", "()Ljava/lang/String;"); 125 | jstring stringPath = (jstring)env->CallObjectMethod(objectFile, methodIDgetAbsolutePath); 126 | 127 | if (stringPath) 128 | { 129 | const char* strPathValueStr = env->GetStringUTFChars(stringPath, NULL); 130 | 131 | strxcpy(strPath, strPathValueStr, bufferSize); 132 | env->ReleaseStringUTFChars(stringPath, strPathValueStr); 133 | } 134 | return bReadFromF92launcher; 135 | } 136 | #endif 137 | 138 | inline jobject GetStorageDir(JNIEnv* env) // /storage/emulated/0 instead of /sdcard (example) 139 | { 140 | jclass classEnvironment = env->FindClass("android/os/Environment"); 141 | jstring ret = (jstring)env->CallStaticObjectMethod(classEnvironment, env->GetStaticMethodID(classEnvironment, "getExternalStorageDirectory", "()Ljava/io/File;")); 142 | if (env->ExceptionCheck()) env->ExceptionClear(); 143 | return ret; 144 | } 145 | 146 | inline void ShowToastMessage(JNIEnv* env, jobject jActivity, const char* txt, int msDuration) 147 | { 148 | jclass ToastClass = env->FindClass("android/widget/Toast"); 149 | jmethodID makeTextMethodID = env->GetStaticMethodID(ToastClass, "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;"); 150 | jmethodID showMethodID = env->GetMethodID(ToastClass, "show", "()V"); 151 | 152 | jstring message = env->NewStringUTF(txt); 153 | jint duration = msDuration; // can be Toast.LENGTH_SHORT or Toast.LENGTH_LONG 154 | 155 | jobject toast = env->CallStaticObjectMethod(ToastClass, makeTextMethodID, jActivity, message, duration); 156 | env->CallVoidMethod(toast, showMethodID); 157 | 158 | env->DeleteLocalRef(message); 159 | 160 | if (env->ExceptionCheck()) env->ExceptionClear(); 161 | } 162 | 163 | inline void ShowToastMessage2(JNIEnv* env, jobject jActivity, const char* txt, jint duration) 164 | { 165 | jclass ToastClass = env->FindClass("android/widget/Toast"); 166 | jmethodID makeTextMethodID = env->GetStaticMethodID(ToastClass, "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;"); 167 | jmethodID showMethodID = env->GetMethodID(ToastClass, "show", "()V"); 168 | jmethodID setDurationMethodID = env->GetMethodID(ToastClass, "setDuration", "(I)V"); 169 | 170 | jstring message = env->NewStringUTF(txt); 171 | jobject toast = env->CallStaticObjectMethod(ToastClass, makeTextMethodID, jActivity, message, duration); 172 | env->CallVoidMethod(toast, setDurationMethodID, duration); 173 | env->CallVoidMethod(toast, showMethodID); 174 | 175 | env->DeleteLocalRef(message); 176 | 177 | if (env->ExceptionCheck()) env->ExceptionClear(); 178 | } -------------------------------------------------------------------------------- /include/mls.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define MAX_KEY_LEN 12 // Maximum KEY NAME length! 4 | #define MAX_VAL_LEN 24 // Maximum STR VALUE length! 5 | 6 | class MLS 7 | { 8 | public: 9 | 10 | // Generic 11 | static void LoadFile(); 12 | static void SaveFile(); 13 | static bool HasValue(const char* key); 14 | static void DeleteValue(const char* key); 15 | 16 | // Set 17 | static void SetInt(const char* key, int32_t val); 18 | static void SetFloat(const char* key, float val); 19 | static void SetInt64(const char* key, int64_t val); 20 | static void SetStr(const char* key, const char *val); 21 | 22 | // Get 23 | static bool GetInt(const char* key, int32_t *val); 24 | static bool GetFloat(const char* key, float *val); 25 | static bool GetInt64(const char* key, int64_t *val); 26 | static bool GetStr(const char* key, char *val, size_t len); 27 | }; -------------------------------------------------------------------------------- /include/modpaks.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FILE_DATA_SIZE 8192 5 | 6 | extern CURL* curl; 7 | extern char szFileData[FILE_DATA_SIZE]; 8 | 9 | void InitCURL(); 10 | CURLcode DownloadFile(const char* url, const char* path); 11 | CURLcode DownloadFileToData(const char* url); 12 | void ProcessData(ModDesc* d); 13 | -------------------------------------------------------------------------------- /include/modslist.h: -------------------------------------------------------------------------------- 1 | #ifndef __MODSLIST_H 2 | #define __MODSLIST_H 3 | 4 | #include 5 | #include 6 | 7 | class Mods; 8 | extern Mods* listMods; 9 | 10 | typedef void (*OnInterfaceAddedFn)(const char*, const void*); 11 | typedef const char* (*GetUpdaterURLFn)(); 12 | typedef void (*OnModLoadFn)(); 13 | typedef ModInfoDependency* (*GetDependenciesListFn)(); 14 | typedef void (*OnGameCrashedFn)(const char*, int, int, uintptr_t, mcontext_t*); 15 | struct ModDesc 16 | { 17 | ModInfo* m_pInfo; 18 | void* m_pHandle; 19 | ModInfoDependency* m_aDependencies; 20 | char m_szLibPath[256]; 21 | 22 | OnModLoadFn m_fnOnModLoaded; 23 | OnModLoadFn m_fnOnModUnloaded; 24 | OnModLoadFn m_fnOnAllModsLoaded; 25 | GetUpdaterURLFn m_fnRequestUpdaterURL; 26 | OnInterfaceAddedFn m_fnInterfaceAddedCB; 27 | OnGameCrashedFn m_fnGameCrashedCB; 28 | 29 | ModDesc() 30 | { 31 | m_szLibPath[0] = 0; 32 | m_fnOnModLoaded = NULL; 33 | m_fnOnModUnloaded = NULL; 34 | m_fnOnAllModsLoaded = NULL; 35 | m_fnRequestUpdaterURL = NULL; 36 | m_fnInterfaceAddedCB = NULL; 37 | m_fnGameCrashedCB = NULL; 38 | } 39 | }; 40 | 41 | class ModsList 42 | { 43 | // Functions 44 | public: 45 | bool AddMod(ModInfo* modinfo, void* modhandle, const char* path); 46 | bool RemoveMod(ModInfo* modinfo); 47 | bool RemoveMod(const char* szGUID); 48 | bool HasMod(const char* szGUID); 49 | bool HasModOfVersion(const char* szGUID, const char* szVersion); 50 | bool HasModOfBiggerVersion(const char* szGUID, const char* szVersion); 51 | void ProcessDependencies(); 52 | void ProcessPreLoading(); 53 | void ProcessLoading(); 54 | void ProcessUnloading(); 55 | void ProcessUpdater(); 56 | void ProcessCrash(const char* szLibName, int sig, int code, uintptr_t libaddr, mcontext_t* mcontext); 57 | int GetModsNum(); 58 | void PrintModsList(std::ofstream& logfile); 59 | 60 | // Callbacks 61 | public: 62 | void OnInterfaceAdded(const char* name, const void* ptr); 63 | void OnAllModsLoaded(); 64 | }; 65 | 66 | extern ModsList* modlist; 67 | 68 | #endif // __MODSLIST_H 69 | -------------------------------------------------------------------------------- /interface.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "interfaces.h" 3 | #include "mod/logger.h" 4 | #define _IAML // Do not include "interface" twice! 5 | #include "modslist.h" 6 | #include "mod/listitem.h" 7 | 8 | class Interfaces; 9 | Interfaces* listInterfaces = NULL; 10 | LIST_START(Interfaces) 11 | 12 | LIST_INITSTART(Interfaces) 13 | pInterface = NULL; 14 | szName[0] = 0; 15 | LIST_INITEND() 16 | 17 | static void AddNew(const char* name, void* interface) 18 | { 19 | Interfaces* newItem = new Interfaces; 20 | newItem->pInterface = interface; 21 | strxcpy(newItem->szName, name, 48); 22 | newItem->Push(&listInterfaces); 23 | } 24 | static void* Get(const char* name) 25 | { 26 | LIST_FOR_FAST(listInterfaces) 27 | { 28 | if (!strcmp(item->szName, name)) return item->pInterface; 29 | } 30 | return NULL; 31 | } 32 | 33 | void* pInterface; 34 | char szName[48]; 35 | LIST_END() 36 | 37 | void InterfaceSys::Register(const char* szInterfaceName, void* pInterfacePointer) 38 | { 39 | if(szInterfaceName == NULL) 40 | { 41 | logger->Error("Failed to add unknown interface to the list because it`s NULL!"); 42 | return; 43 | } 44 | if(pInterfacePointer == NULL) 45 | { 46 | logger->Error("Failed to add interface %s to the list because it`s NULL!", szInterfaceName); 47 | return; 48 | } 49 | if(Interfaces::Get(szInterfaceName) != NULL) 50 | { 51 | logger->Error("Failed to add interface %s to the list because it`s already registered!", szInterfaceName); 52 | return; 53 | } 54 | Interfaces::AddNew(szInterfaceName, pInterfacePointer); 55 | modlist->OnInterfaceAdded(szInterfaceName, pInterfacePointer); 56 | } 57 | 58 | void* InterfaceSys::Get(const char* szInterfaceName) 59 | { 60 | return Interfaces::Get(szInterfaceName); 61 | } 62 | 63 | static InterfaceSys interfacesLocal; 64 | InterfaceSys* interfaces = &interfacesLocal; 65 | 66 | extern "C" 67 | { 68 | JNIEXPORT void* GetInterface(const char* szInterfaceName) 69 | { 70 | return interfacesLocal.Get(szInterfaceName); 71 | } 72 | JNIEXPORT void CreateInterface(const char* szInterfaceName, void* pInterface) 73 | { 74 | return interfacesLocal.Register(szInterfaceName, pInterface); 75 | } 76 | } -------------------------------------------------------------------------------- /mls.cpp: -------------------------------------------------------------------------------- 1 | /* MLS - Mod Loader`s Settings */ 2 | /* A functionality to store game/mods settings in a better way */ 3 | /* (for those who doesn`t like 1000 config files) */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "mls.h" 13 | 14 | extern bool g_bMLSOnlyManualSaves; 15 | 16 | class MLSKeychain; 17 | 18 | struct MLSStorage 19 | { 20 | char szKey[MAX_KEY_LEN]; 21 | char szValue[MAX_VAL_LEN]; 22 | }; 23 | 24 | MLSKeychain* listSets = NULL; 25 | LIST_START(MLSKeychain) 26 | LIST_INITSTART(MLSKeychain) 27 | memset(storage.szKey, 0, sizeof(storage.szKey)); 28 | memset(storage.szValue, 0, sizeof(storage.szValue)); 29 | LIST_INITEND() 30 | 31 | MLSStorage storage; 32 | LIST_END() 33 | 34 | void MLS::LoadFile() 35 | { 36 | char path[256]; 37 | snprintf(path, sizeof(path), "%s/gamesave.mls", aml->GetAndroidDataPath()); 38 | FILE* f = fopen(path, "rb"); 39 | if(!f) 40 | { 41 | logger->Error("An error (%d) opening MLS file!", errno, strerror(errno)); 42 | return; 43 | } 44 | 45 | logger->Info("MLS file is opened, reading sets..."); 46 | MLSKeychain* item; 47 | while(true) 48 | { 49 | item = new MLSKeychain; 50 | fread(&item->storage, sizeof(MLSStorage), 1, f); 51 | if(!feof(f)) 52 | { 53 | item->Push(&listSets); 54 | } 55 | else 56 | { 57 | fclose(f); 58 | logger->Info("MLS file has been readed. Sets: %d", item->Count()); 59 | return; 60 | } 61 | } 62 | } 63 | void MLS::SaveFile() 64 | { 65 | char path[256]; 66 | snprintf(path, sizeof(path), "%s/gamesave.mls", aml->GetAndroidDataPath()); 67 | FILE* f = fopen(path, "wb"); 68 | if(!f) return; 69 | 70 | LIST_FOR_FAST(listSets) 71 | { 72 | fwrite(&item->storage, sizeof(MLSStorage), 1, f); 73 | } 74 | fclose(f); 75 | } 76 | bool MLS::HasValue(const char* key) 77 | { 78 | LIST_FOR_FAST(listSets) 79 | { 80 | if(!strcmp(item->storage.szKey, key)) return true; 81 | } 82 | return false; 83 | } 84 | void MLS::DeleteValue(const char* key) 85 | { 86 | LIST_FOR(listSets) 87 | { 88 | if(!strcmp(item->storage.szKey, key)) 89 | { 90 | item->Remove(&listSets); 91 | delete item; 92 | if(!g_bMLSOnlyManualSaves) SaveFile(); 93 | } 94 | } 95 | } 96 | 97 | void MLS::SetInt(const char* key, int32_t val) 98 | { 99 | LIST_FOR_FAST(listSets) 100 | { 101 | if(!strcmp(item->storage.szKey, key)) 102 | { 103 | memset(item->storage.szValue, 0, sizeof(MLSStorage::szValue)); 104 | snprintf(item->storage.szValue, sizeof(MLSStorage::szValue), "%d", val); 105 | if(!g_bMLSOnlyManualSaves) SaveFile(); 106 | return; 107 | } 108 | } 109 | 110 | MLSKeychain* newitem = new MLSKeychain; 111 | snprintf(newitem->storage.szKey, sizeof(MLSStorage::szKey), "%s", key); 112 | snprintf(newitem->storage.szValue, sizeof(MLSStorage::szValue), "%d", val); 113 | newitem->Push(&listSets); 114 | 115 | if(!g_bMLSOnlyManualSaves) SaveFile(); 116 | } 117 | void MLS::SetFloat(const char* key, float val) 118 | { 119 | LIST_FOR_FAST(listSets) 120 | { 121 | if(!strcmp(item->storage.szKey, key)) 122 | { 123 | memset(item->storage.szValue, 0, sizeof(MLSStorage::szValue)); 124 | snprintf(item->storage.szValue, sizeof(MLSStorage::szValue), "%8.6f", val); 125 | if(!g_bMLSOnlyManualSaves) SaveFile(); 126 | return; 127 | } 128 | } 129 | 130 | MLSKeychain* newitem = new MLSKeychain; 131 | snprintf(newitem->storage.szKey, sizeof(MLSStorage::szKey), "%s", key); 132 | snprintf(newitem->storage.szValue, sizeof(MLSStorage::szValue), "%8.6f", val); 133 | newitem->Push(&listSets); 134 | 135 | if(!g_bMLSOnlyManualSaves) SaveFile(); 136 | } 137 | #pragma clang diagnostic push 138 | #pragma clang diagnostic ignored "-Wformat" // dumb ass clang cries about "ld needs to be lld" and "lld needs to be ld" at the SAME TIME 139 | void MLS::SetInt64(const char* key, int64_t val) 140 | { 141 | LIST_FOR_FAST(listSets) 142 | { 143 | if(!strcmp(item->storage.szKey, key)) 144 | { 145 | memset(item->storage.szValue, 0, sizeof(MLSStorage::szValue)); 146 | snprintf(item->storage.szValue, sizeof(MLSStorage::szValue), "%lld", val); 147 | if(!g_bMLSOnlyManualSaves) SaveFile(); 148 | return; 149 | } 150 | } 151 | 152 | MLSKeychain* newitem = new MLSKeychain; 153 | snprintf(newitem->storage.szKey, sizeof(MLSStorage::szKey), "%s", key); 154 | snprintf(newitem->storage.szValue, sizeof(MLSStorage::szValue), "%lld", val); 155 | newitem->Push(&listSets); 156 | 157 | if(!g_bMLSOnlyManualSaves) SaveFile(); 158 | } 159 | #pragma clang diagnostic pop 160 | void MLS::SetStr(const char* key, const char *val) 161 | { 162 | LIST_FOR_FAST(listSets) 163 | { 164 | if(!strcmp(item->storage.szKey, key)) 165 | { 166 | memset(item->storage.szValue, 0, sizeof(MLSStorage::szValue)); 167 | snprintf(item->storage.szValue, sizeof(MLSStorage::szValue), "%s", val); 168 | if(!g_bMLSOnlyManualSaves) SaveFile(); 169 | return; 170 | } 171 | } 172 | 173 | MLSKeychain* newitem = new MLSKeychain; 174 | snprintf(newitem->storage.szKey, sizeof(MLSStorage::szKey), "%s", key); 175 | snprintf(newitem->storage.szValue, sizeof(MLSStorage::szValue), "%s", val); 176 | newitem->Push(&listSets); 177 | 178 | if(!g_bMLSOnlyManualSaves) SaveFile(); 179 | } 180 | 181 | bool MLS::GetInt(const char* key, int32_t *val) 182 | { 183 | LIST_FOR_FAST(listSets) 184 | { 185 | if(!strcmp(item->storage.szKey, key)) 186 | { 187 | *val = atoi(item->storage.szValue); 188 | return true; 189 | } 190 | } 191 | return false; 192 | } 193 | bool MLS::GetFloat(const char* key, float *val) 194 | { 195 | LIST_FOR_FAST(listSets) 196 | { 197 | if(!strcmp(item->storage.szKey, key)) 198 | { 199 | *val = atof(item->storage.szValue); 200 | return true; 201 | } 202 | } 203 | return false; 204 | } 205 | bool MLS::GetInt64(const char* key, int64_t *val) 206 | { 207 | LIST_FOR_FAST(listSets) 208 | { 209 | if(!strcmp(item->storage.szKey, key)) 210 | { 211 | *val = atoll(item->storage.szValue); 212 | return true; 213 | } 214 | } 215 | return false; 216 | } 217 | bool MLS::GetStr(const char* key, char *val, size_t len) 218 | { 219 | LIST_FOR_FAST(listSets) 220 | { 221 | if(!strcmp(item->storage.szKey, key)) 222 | { 223 | memset(val, 0, len); 224 | snprintf(val, len, "%s", item->storage.szValue); 225 | return true; 226 | } 227 | } 228 | return false; 229 | } -------------------------------------------------------------------------------- /mod/amlmod.h: -------------------------------------------------------------------------------- 1 | #ifndef _AMLMOD 2 | #define _AMLMOD 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __arm__ 11 | #define AML32 12 | #define BYBIT(__32val, __64val) (__32val) 13 | #elif defined __aarch64__ 14 | #define AML64 15 | #define BYBIT(__32val, __64val) (__64val) 16 | #else 17 | #error This lib is supposed to work on ARM only! 18 | #endif 19 | 20 | #ifdef __clang__ 21 | #define TARGET_ARM __attribute__((target("no-thumb-mode"))) 22 | #define TARGET_THUMB __attribute__((target("thumb-mode"))) 23 | #endif 24 | 25 | #ifdef __GNUC__ 26 | #define ASM_NAKED __attribute__((naked)) 27 | #define EXPORT __attribute__((visibility("default"))) 28 | #else 29 | #define ASM_NAKED __declspec(naked) 30 | #define EXPORT 31 | #endif 32 | 33 | #define MYMOD(_guid, _name, _version, _author) \ 34 | static ModInfo modinfoLocal(#_guid, #_name, #_version, #_author); \ 35 | ModInfo* modinfo = &modinfoLocal; \ 36 | extern "C" ModInfo* __GetModInfo() { return modinfo; } \ 37 | IAML* aml = (IAML*)GetInterface("AMLInterface"); 38 | 39 | #define MYMODCFG(_guid, _name, _version, _author) \ 40 | MYMOD(_guid, _name, _version, _author); \ 41 | static Config cfgLocal(#_guid); \ 42 | Config* cfg = &cfgLocal; 43 | 44 | #define NEEDGAME(_pkg_name) \ 45 | extern "C" const char* __INeedASpecificGame() {return #_pkg_name;} 46 | 47 | #define MYMODDECL() \ 48 | extern ModInfo* modinfo; // Just in case if you need to use that somewhere else in your mod 49 | 50 | /* Dependencies! */ 51 | #define BEGIN_DEPLIST() \ 52 | static ModInfoDependency g_listDependencies[] = { 53 | 54 | #define ADD_DEPENDENCY(_guid) \ 55 | {#_guid, ""}, 56 | 57 | #define ADD_DEPENDENCY_VER(_guid, _version) \ 58 | {#_guid, #_version}, 59 | 60 | #define END_DEPLIST() \ 61 | {"", ""} }; \ 62 | extern "C" ModInfoDependency* __GetDepsList() { return &g_listDependencies[0]; } 63 | 64 | 65 | 66 | #define MINIMUM_MD5_BUF_SIZE 33 67 | 68 | struct MemChunk_t 69 | { 70 | char* out; 71 | size_t out_len; 72 | }; 73 | 74 | struct ModInfoDependency 75 | { 76 | const char* szGUID; 77 | const char* szVersion; 78 | }; 79 | 80 | struct ModVersion 81 | { 82 | unsigned short major; 83 | unsigned short minor; 84 | unsigned short revision; 85 | unsigned short build; 86 | }; 87 | 88 | // Should be faster than strncpy? 89 | inline char *strxcpy(char* __restrict__ dst, const char* __restrict__ src, int len) 90 | { 91 | if (!len) return NULL; 92 | while (--len && (*dst++ = *src++)); 93 | if (!len) 94 | { 95 | *dst++ = '\0'; 96 | return *src ? NULL : dst; 97 | } 98 | else 99 | { 100 | return dst; 101 | } 102 | } 103 | 104 | inline int clampint(int min, int max, int v) 105 | { 106 | if(v < min) return min; 107 | else if(v > max) return max; 108 | return v; 109 | } 110 | inline void clampint(int min, int max, int* v) 111 | { 112 | if(*v < min) *v = min; 113 | else if(*v > max) *v = max; 114 | } 115 | inline float clampfloat(float min, float max, float v) 116 | { 117 | if(v < min) return min; 118 | else if(v > max) return max; 119 | return v; 120 | } 121 | inline void clampfloat(float min, float max, float* v) 122 | { 123 | if(*v < min) *v = min; 124 | else if(*v > max) *v = max; 125 | } 126 | 127 | class ModInfo 128 | { 129 | public: 130 | ModInfo(const char* szGUID, const char* szName, const char* szVersion, const char* szAuthor) 131 | { 132 | /* No buffer overflow! */ 133 | strxcpy(this->szGUID, szGUID, sizeof(ModInfo::szGUID)); this->szGUID[sizeof(ModInfo::szGUID) - 1] = '\0'; 134 | strxcpy(this->szName, szName, sizeof(ModInfo::szName)); this->szName[sizeof(ModInfo::szName) - 1] = '\0'; 135 | strxcpy(this->szVersion, szVersion, sizeof(ModInfo::szVersion)); this->szVersion[sizeof(ModInfo::szVersion) - 1] = '\0'; 136 | strxcpy(this->szAuthor, szAuthor, sizeof(ModInfo::szAuthor)); this->szAuthor[sizeof(ModInfo::szAuthor) - 1] = '\0'; 137 | 138 | /* GUID should be lowcase */ 139 | for(int i = 0; this->szGUID[i] != '\0'; ++i) 140 | { 141 | this->szGUID[i] = tolower((int)(this->szGUID[i])); 142 | } 143 | 144 | /* Parse version string */ 145 | if(sscanf(this->szVersion, "%hu.%hu.%hu.%hu", &version.major, &version.minor, &version.revision, &version.build) < 4) 146 | { 147 | if(sscanf(this->szVersion, "%hu.%hu.%hu", &version.major, &version.minor, &version.revision) < 3) 148 | { 149 | if(sscanf(this->szVersion, "%hu.%hu", &version.major, &version.minor) < 2) 150 | { 151 | version.major = (unsigned short)atoi(this->szVersion); 152 | } 153 | version.revision = 0; 154 | } 155 | version.build = 0; 156 | } 157 | } 158 | inline const char* GUID() { return szGUID; } 159 | inline const char* Name() { return szName; } 160 | inline const char* VersionString() { return szVersion; } 161 | inline const char* Author() { return szAuthor; } 162 | inline unsigned short Major() { return version.major; } 163 | inline unsigned short Minor() { return version.minor; } 164 | inline unsigned short Revision() { return version.revision; } 165 | inline unsigned short Build() { return version.build; } 166 | 167 | private: 168 | char szGUID[48]; 169 | char szName[48]; 170 | char szVersion[24]; 171 | char szAuthor[48]; 172 | ModVersion version; 173 | 174 | friend class ModsList; 175 | friend class Mods; 176 | }; 177 | 178 | typedef ModInfo* (*GetModInfoFn)(); 179 | 180 | 181 | 182 | #include "iaml.h" 183 | 184 | #endif // _AMLMOD -------------------------------------------------------------------------------- /mod/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG 2 | #define _CONFIG 3 | 4 | #define KEY_SECTION_BUFFER_C 64 5 | #define VALUE_BUFFER_C 384 6 | 7 | /* Is not required. Can be used only for a smaller size of mod (~480kb savings) */ 8 | #include "icfg.h" 9 | #include 10 | 11 | class ConfigEntry; 12 | 13 | struct rgba_t 14 | { 15 | union { 16 | struct { unsigned char r, g, b, a; }; 17 | struct { unsigned char x, y, z, w; }; 18 | unsigned char v[4]; 19 | unsigned int value; 20 | }; 21 | 22 | rgba_t() : r(0), g(0), b(0), a(0) {} 23 | rgba_t(unsigned char v) : r(v), g(v), b(v), a(255) {} 24 | rgba_t(unsigned char _r, unsigned char _g, unsigned char _b) : r(_r), g(_g), b(_b), a(255) {} 25 | rgba_t(unsigned char _r, unsigned char _g, unsigned char _b, unsigned char _a) : r(_r), g(_g), b(_b), a(_a) {} 26 | }; 27 | 28 | class Config 29 | { 30 | public: 31 | Config(const char* szName); 32 | void Init(); 33 | void Save(); 34 | // Allocated, needs to be manually deleted 35 | ConfigEntry* Bind(const char* szKey, const char* szDefaultValue, const char* szSection = "Preferences"); 36 | ConfigEntry* Bind(const char* szKey, int nDefaultValue, const char* szSection = "Preferences"); 37 | ConfigEntry* Bind(const char* szKey, float flDefaultValue, const char* szSection = "Preferences"); 38 | ConfigEntry* Bind(const char* szKey, bool bDefaultValue, const char* szSection = "Preferences"); 39 | ConfigEntry* Bind(const char* szKey, rgba_t clrDefaultValue, const char* szSection = "Preferences"); 40 | 41 | // FAST GET. NO NEED TO CLEAN THE MEMORY. 42 | const char* GetString(const char* szKey, const char* szDefaultValue, const char* szSection = "Preferences"); 43 | int GetInt(const char* szKey, int nDefaultValue, const char* szSection = "Preferences"); 44 | float GetFloat(const char* szKey, float flDefaultValue, const char* szSection = "Preferences"); 45 | bool GetBool(const char* szKey, bool bDefaultValue, const char* szSection = "Preferences"); 46 | rgba_t GetColor(const char* szKey, rgba_t clrDefaultValue, const char* szSection = "Preferences"); 47 | 48 | // Self-explained 49 | inline bool IsValueChanged() { return m_bValueChanged; } 50 | inline void ClearLast(); 51 | 52 | static Config* GetConfig(); 53 | static ConfigEntry* pLastEntry; 54 | 55 | private: 56 | bool m_bInitialized; 57 | bool m_bValueChanged; 58 | const char* m_szName; 59 | void* m_iniMyConfig; 60 | 61 | #ifdef _ICFG 62 | /* Built-in optimizer thinks he's the best! Ha-ha... Not funny. It's 3AM... */ 63 | ICFG* m_pICFG; 64 | #endif 65 | 66 | friend class ConfigEntry; 67 | }; 68 | 69 | class ConfigEntry 70 | { 71 | public: 72 | ConfigEntry() : m_bLoadedData(false), m_szValue(""), m_szDefaultValue("") {} 73 | void SetString(const char* newValue); 74 | inline const char* GetString() { return m_szValue; } 75 | void GetString(char* str, size_t len); 76 | void SetFloat(float newValue); 77 | inline float GetFloat() { return m_fFloatValue; } 78 | void SetBool(bool newValue); 79 | inline bool GetBool() { return m_nIntegerValue; } 80 | void SetInt(int newValue); 81 | inline int GetInt() { return m_nIntegerValue; } 82 | inline void Reset() { SetString(m_szDefaultValue); } 83 | rgba_t ParseColor(); 84 | void SetColor(rgba_t clr, bool asFloat = false); 85 | 86 | inline bool LoadedUndefault() { return m_bNotDefaultValue; } 87 | inline int Clamp(int min, int max) 88 | { 89 | if(m_nIntegerValue < min) 90 | { 91 | m_pBoundCfg->m_bValueChanged = true; 92 | int ret = m_nIntegerValue - min; 93 | m_nIntegerValue = min; 94 | m_fFloatValue = (float)min; 95 | m_szValue[0] = 0; 96 | return ret; 97 | } 98 | if(m_nIntegerValue > max) 99 | { 100 | m_pBoundCfg->m_bValueChanged = true; 101 | int ret = m_nIntegerValue - max; 102 | m_nIntegerValue = max; 103 | m_fFloatValue = (float)max; 104 | m_szValue[0] = 0; 105 | return ret; 106 | } 107 | return 0; 108 | } 109 | inline float Clamp(float min, float max) 110 | { 111 | if(m_fFloatValue < min) 112 | { 113 | m_pBoundCfg->m_bValueChanged = true; 114 | float ret = m_fFloatValue - min; 115 | m_nIntegerValue = (int)min; 116 | m_fFloatValue = min; 117 | m_szValue[0] = 0; 118 | return ret; 119 | } 120 | if(m_fFloatValue > max) 121 | { 122 | m_pBoundCfg->m_bValueChanged = true; 123 | float ret = m_fFloatValue - max; 124 | m_nIntegerValue = (int)max; 125 | m_fFloatValue = max; 126 | m_szValue[0] = 0; 127 | return ret; 128 | } 129 | return 0.0f; 130 | } 131 | 132 | private: 133 | Config* m_pBoundCfg; 134 | bool m_bLoadedData; 135 | bool m_bNotDefaultValue; 136 | char m_szMySection[KEY_SECTION_BUFFER_C]; 137 | char m_szMyKey[KEY_SECTION_BUFFER_C]; 138 | float m_fFloatValue; 139 | union 140 | { 141 | int m_nIntegerValue; 142 | rgba_t m_ColorValue; 143 | }; 144 | char m_szValue[VALUE_BUFFER_C]; 145 | char m_szDefaultValue[VALUE_BUFFER_C]; 146 | 147 | friend class Config; 148 | }; 149 | inline void Config::ClearLast() { if(pLastEntry) { delete pLastEntry; pLastEntry = NULL; } } 150 | extern Config* cfg; 151 | 152 | #endif // _CONFIG 153 | -------------------------------------------------------------------------------- /mod/config_inipp.cpp: -------------------------------------------------------------------------------- 1 | #ifndef DONT_USE_STB 2 | #include 3 | #define sprintf stbsp_sprintf 4 | #define snprintf stbsp_snprintf 5 | #endif 6 | #include "config.h" 7 | #include 8 | 9 | #include "amlmod.h" 10 | #include "iaml.h" 11 | #if !defined(__AML) && defined(_ICFG) 12 | ICFG* icfg; 13 | #else 14 | #include 15 | #include "thirdparty/inipp.h" 16 | #endif 17 | #ifdef __AML 18 | extern char g_szCfgPath[0xFF]; 19 | #endif 20 | 21 | inline bool str_equal(const char* str1, const char* str2) { 22 | for ( ; *str1 == *str2 && *str1 != 0; ++str1, ++str2 ); 23 | return *str2 == *str1; 24 | } 25 | 26 | extern ModInfo* modinfo; 27 | ConfigEntry* Config::pLastEntry = NULL; 28 | 29 | Config::Config(const char* szName) 30 | { 31 | #if !defined(__AML) && defined(_ICFG) 32 | m_pICFG = (ICFG*)GetInterface("AMLConfig"); 33 | m_iniMyConfig = m_pICFG->InitIniPointer(); 34 | #else 35 | m_iniMyConfig = new inipp::Ini(); 36 | logger->Info("inipp 0x%16X, 0x%16X", m_iniMyConfig, *(void**)m_iniMyConfig); 37 | #endif 38 | m_bInitialized = false; 39 | m_bValueChanged = false; 40 | m_szName = szName; 41 | 42 | #ifndef __AML 43 | Init(); 44 | #endif 45 | } 46 | 47 | void Config::Init() 48 | { 49 | if(m_bInitialized) return; 50 | m_bInitialized = true; 51 | 52 | #if !defined(__AML) && defined(_ICFG) 53 | m_pICFG->ParseInputStream(m_iniMyConfig, m_szName); 54 | #else 55 | char path[0xFF]; 56 | #ifdef __AML 57 | snprintf(path, sizeof(path), "%s/%s.ini", g_szCfgPath, m_szName); 58 | std::ifstream cfgStream(path); 59 | #else 60 | snprintf(path, sizeof(path), "%s/%s.ini", aml->GetConfigPath(), m_szName); 61 | std::ifstream cfgStream(path); 62 | #endif 63 | if(cfgStream.is_open()) 64 | { 65 | ((inipp::Ini*)m_iniMyConfig)->parse(cfgStream); 66 | } 67 | cfgStream.close(); 68 | #endif 69 | } 70 | 71 | void Config::Save() 72 | { 73 | if(!m_bInitialized || !m_bValueChanged) return; 74 | 75 | m_bValueChanged = false; 76 | #if !defined(__AML) && defined(_ICFG) 77 | m_pICFG->GenerateToOutputStream(m_iniMyConfig, m_szName); 78 | #else 79 | char path[0xFF]; 80 | #ifdef __AML 81 | snprintf(path, sizeof(path), "%s/%s.ini", g_szCfgPath, m_szName); 82 | std::ofstream cfgStream(path); 83 | #else 84 | snprintf(path, sizeof(path), "%s/%s.ini", aml->GetConfigPath(), m_szName); 85 | std::ofstream cfgStream(path); 86 | #endif 87 | if(cfgStream.is_open()) 88 | { 89 | ((inipp::Ini*)m_iniMyConfig)->generate(cfgStream); 90 | } 91 | cfgStream << ""; 92 | cfgStream.close(); 93 | #endif 94 | } 95 | 96 | ConfigEntry* Config::Bind(const char* szKey, const char* szDefaultValue, const char* szSection) 97 | { 98 | if(!m_bInitialized) return NULL; 99 | ConfigEntry* pRet = new ConfigEntry; 100 | pRet->m_pBoundCfg = this; 101 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 102 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 103 | strncpy(pRet->m_szDefaultValue, szDefaultValue, sizeof(pRet->m_szDefaultValue)); 104 | const char* tryToGetValue; 105 | #if !defined(__AML) && defined(_ICFG) 106 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 107 | #else 108 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 109 | #endif 110 | if(tryToGetValue[0] == '\0') 111 | pRet->SetString(szDefaultValue); 112 | else 113 | { 114 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 115 | pRet->SetString(tryToGetValue); 116 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 117 | } 118 | Save(); 119 | pLastEntry = pRet; 120 | return pRet; 121 | } 122 | 123 | ConfigEntry* Config::Bind(const char* szKey, int nDefaultValue, const char* szSection) 124 | { 125 | if(!m_bInitialized) return NULL; 126 | ConfigEntry* pRet = new ConfigEntry; 127 | pRet->m_pBoundCfg = this; 128 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 129 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 130 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%d", nDefaultValue); 131 | const char* tryToGetValue; 132 | #if !defined(__AML) && defined(_ICFG) 133 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 134 | #else 135 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 136 | #endif 137 | if(tryToGetValue[0] == '\0') 138 | pRet->SetInt(nDefaultValue); 139 | else 140 | { 141 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 142 | pRet->SetString(tryToGetValue); 143 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 144 | } 145 | Save(); 146 | pLastEntry = pRet; 147 | return pRet; 148 | } 149 | 150 | ConfigEntry* Config::Bind(const char* szKey, float flDefaultValue, const char* szSection) 151 | { 152 | if(!m_bInitialized) return NULL; 153 | ConfigEntry* pRet = new ConfigEntry; 154 | pRet->m_pBoundCfg = this; 155 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 156 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 157 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%f", flDefaultValue); 158 | const char* tryToGetValue; 159 | #if !defined(__AML) && defined(_ICFG) 160 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 161 | #else 162 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 163 | #endif 164 | if(tryToGetValue[0] == '\0') 165 | pRet->SetFloat(flDefaultValue); 166 | else 167 | { 168 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 169 | pRet->SetString(tryToGetValue); 170 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 171 | } 172 | Save(); 173 | pLastEntry = pRet; 174 | return pRet; 175 | } 176 | 177 | ConfigEntry* Config::Bind(const char* szKey, bool bDefaultValue, const char* szSection) 178 | { 179 | if(!m_bInitialized) return NULL; 180 | ConfigEntry* pRet = new ConfigEntry; 181 | pRet->m_pBoundCfg = this; 182 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 183 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 184 | pRet->m_szDefaultValue[0] = bDefaultValue ? '1' : '0'; pRet->m_szDefaultValue[1] = 0; 185 | const char* tryToGetValue; 186 | #if !defined(__AML) && defined(_ICFG) 187 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 188 | #else 189 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 190 | #endif 191 | if(tryToGetValue[0] == '\0') 192 | pRet->SetBool(bDefaultValue); 193 | else 194 | { 195 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 196 | pRet->SetString(tryToGetValue); 197 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 198 | } 199 | Save(); 200 | pLastEntry = pRet; 201 | return pRet; 202 | } 203 | 204 | ConfigEntry* Config::BindOnce(const char* szKey, const char* szDefaultValue, const char* szSection) 205 | { 206 | if(!m_bInitialized) return NULL; 207 | ConfigEntry entry; ConfigEntry* pRet = &entry; 208 | pRet->m_pBoundCfg = this; 209 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 210 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 211 | strncpy(pRet->m_szDefaultValue, szDefaultValue, sizeof(pRet->m_szDefaultValue)); 212 | const char* tryToGetValue; 213 | #if !defined(__AML) && defined(_ICFG) 214 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 215 | #else 216 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 217 | #endif 218 | if(tryToGetValue[0] == '\0') 219 | pRet->SetString(szDefaultValue); 220 | else 221 | { 222 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 223 | pRet->SetString(tryToGetValue); 224 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 225 | } 226 | Save(); 227 | pLastEntry = pRet; // Unsafe! 228 | return pRet; 229 | } 230 | 231 | ConfigEntry* Config::BindOnce(const char* szKey, int nDefaultValue, const char* szSection) 232 | { 233 | if(!m_bInitialized) return NULL; 234 | ConfigEntry entry; ConfigEntry* pRet = &entry; 235 | pRet->m_pBoundCfg = this; 236 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 237 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 238 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%d", nDefaultValue); 239 | const char* tryToGetValue; 240 | #if !defined(__AML) && defined(_ICFG) 241 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 242 | #else 243 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 244 | #endif 245 | if(tryToGetValue[0] == '\0') 246 | pRet->SetInt(nDefaultValue); 247 | else 248 | { 249 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 250 | pRet->SetString(tryToGetValue); 251 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 252 | } 253 | Save(); 254 | pLastEntry = pRet; // Unsafe! 255 | return pRet; 256 | } 257 | 258 | ConfigEntry* Config::BindOnce(const char* szKey, float flDefaultValue, const char* szSection) 259 | { 260 | if(!m_bInitialized) return NULL; 261 | ConfigEntry entry; ConfigEntry* pRet = &entry; 262 | pRet->m_pBoundCfg = this; 263 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 264 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 265 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%f", flDefaultValue); 266 | const char* tryToGetValue; 267 | #if !defined(__AML) && defined(_ICFG) 268 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 269 | #else 270 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 271 | #endif 272 | if(tryToGetValue[0] == '\0') 273 | pRet->SetFloat(flDefaultValue); 274 | else 275 | { 276 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 277 | pRet->SetString(tryToGetValue); 278 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 279 | } 280 | Save(); 281 | pLastEntry = pRet; // Unsafe! 282 | return pRet; 283 | } 284 | 285 | ConfigEntry* Config::BindOnce(const char* szKey, bool bDefaultValue, const char* szSection) 286 | { 287 | if(!m_bInitialized) return NULL; 288 | ConfigEntry entry; ConfigEntry* pRet = &entry; 289 | pRet->m_pBoundCfg = this; 290 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 291 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 292 | pRet->m_szDefaultValue[0] = bDefaultValue ? '1' : '0'; pRet->m_szDefaultValue[1] = 0; 293 | const char* tryToGetValue; 294 | #if !defined(__AML) && defined(_ICFG) 295 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 296 | #else 297 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 298 | #endif 299 | if(tryToGetValue[0] == '\0') 300 | { 301 | pRet->SetBool(bDefaultValue); 302 | } 303 | else 304 | { 305 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 306 | pRet->SetString(tryToGetValue); 307 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 308 | } 309 | Save(); 310 | pLastEntry = pRet; // Unsafe! 311 | return pRet; 312 | } 313 | 314 | void ConfigEntry::SetString(const char* newValue) 315 | { 316 | if(m_bLoadedData && str_equal(newValue, m_szValue)) return; 317 | 318 | strncpy(m_szValue, newValue, sizeof(m_szValue)-1); m_szValue[sizeof(m_szValue)-1] = 0; 319 | m_nIntegerValue = atoi(m_szValue); 320 | m_fFloatValue = (float)atof(m_szValue); 321 | 322 | m_pBoundCfg->m_bValueChanged = true; 323 | m_bLoadedData = true; 324 | 325 | #if !defined(__AML) && defined(_ICFG) 326 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 327 | #else 328 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 329 | #endif 330 | } 331 | 332 | void ConfigEntry::GetString(char* str, size_t len) 333 | { 334 | strncpy(str, GetString(), len); 335 | } 336 | 337 | void ConfigEntry::SetFloat(float newValue) 338 | { 339 | if(m_bLoadedData && m_fFloatValue == newValue) return; 340 | 341 | m_fFloatValue = newValue; 342 | m_nIntegerValue = (int)newValue; 343 | snprintf(m_szValue, sizeof(m_szValue), "%f", newValue); 344 | 345 | m_pBoundCfg->m_bValueChanged = true; 346 | m_bLoadedData = true; 347 | 348 | #if !defined(__AML) && defined(_ICFG) 349 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 350 | #else 351 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 352 | #endif 353 | } 354 | 355 | void ConfigEntry::SetInt(int newValue) 356 | { 357 | if(m_bLoadedData && m_nIntegerValue == newValue) return; 358 | 359 | m_fFloatValue = (float)newValue; 360 | m_nIntegerValue = newValue; 361 | snprintf(m_szValue, sizeof(m_szValue), "%d", newValue); 362 | 363 | m_pBoundCfg->m_bValueChanged = true; 364 | m_bLoadedData = true; 365 | 366 | #if !defined(__AML) && defined(_ICFG) 367 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 368 | #else 369 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 370 | #endif 371 | } 372 | 373 | void ConfigEntry::SetBool(bool newValue) 374 | { 375 | if(m_bLoadedData && m_nIntegerValue == newValue?1:0) return; 376 | 377 | m_fFloatValue = newValue?1.0f:0.0f; 378 | m_nIntegerValue = newValue?1:0; 379 | m_szValue[0] = newValue ? '1' : '0'; m_szValue[1] = 0; 380 | 381 | m_pBoundCfg->m_bValueChanged = true; 382 | m_bLoadedData = true; 383 | 384 | #if !defined(__AML) && defined(_ICFG) 385 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 386 | #else 387 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 388 | #endif 389 | } 390 | 391 | inline bool IsRGBValue(int value) { return value >= 0 && value <= 255; } 392 | inline bool IsRGBFloatValue(float value) { return value >= 0 && value <= 1; } 393 | rgba_t ConfigEntry::ParseColor() 394 | { 395 | int r, g, b, a, sscanfed = sscanf(m_szValue, "%d %d %d %d", &r, &g, &b, &a); 396 | if(sscanfed == 4 && IsRGBValue(r) && IsRGBValue(g) && IsRGBValue(b) && IsRGBValue(a)) 397 | { 398 | return rgba_t{(unsigned char)r,(unsigned char)g,(unsigned char)b,(unsigned char)a}; 399 | } 400 | else if(sscanfed == 3 && IsRGBValue(r) && IsRGBValue(g) && IsRGBValue(b)) 401 | { 402 | return rgba_t{(unsigned char)r,(unsigned char)g,(unsigned char)b,255}; 403 | } 404 | else 405 | { 406 | float fr, fg, fb, fa; 407 | sscanfed = sscanf(m_szValue, "%f %f %f %f", &fr, &fg, &fb, &fa); 408 | if(sscanfed == 4 && IsRGBFloatValue(r) && IsRGBFloatValue(g) && IsRGBFloatValue(b) && IsRGBFloatValue(a)) 409 | { 410 | return rgba_t{(unsigned char)(255*fr),(unsigned char)(255*fg),(unsigned char)(255*fb),(unsigned char)(255*fa)}; 411 | } 412 | else if(sscanfed == 3 && IsRGBFloatValue(r) && IsRGBFloatValue(g) && IsRGBFloatValue(b)) 413 | { 414 | return rgba_t{(unsigned char)(255*fr),(unsigned char)(255*fg),(unsigned char)(255*fb),255}; 415 | } 416 | } 417 | return rgba_t{255,255,255,255}; 418 | } 419 | 420 | void ConfigEntry::SetColor(rgba_t clr, bool asFloat) 421 | { 422 | m_nIntegerValue = (int)clr.r; 423 | m_fFloatValue = (float)clr.r; 424 | if(asFloat) snprintf(m_szValue, sizeof(m_szValue), "%.3f %.3f %.3f %.3f", (float)(clr.r/255.0f), (float)(clr.g/255.0f), (float)(clr.b/255.0f), (float)(clr.a/255.0f)); 425 | else snprintf(m_szValue, sizeof(m_szValue), "%d %d %d %d", (int)clr.r, (int)clr.g, (int)clr.b, (int)clr.a); 426 | 427 | // Kinda expensive to parse the color every time 428 | // Why do you may want it to be changed automatically anyway? 429 | m_pBoundCfg->m_bValueChanged = true; 430 | m_bLoadedData = true; 431 | 432 | #if !defined(__AML) && defined(_ICFG) 433 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 434 | #else 435 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 436 | #endif 437 | } 438 | -------------------------------------------------------------------------------- /mod/iaml.h: -------------------------------------------------------------------------------- 1 | #ifndef _IAML 2 | #define _IAML 3 | 4 | // Usage: place 3 lines somewhere in the code AFTER #include 5 | // #if !defined(IAML_VER) && IAML_VER < 01030000 6 | // #error "You need to update your MOD folder to 1.3.0!" 7 | // #endif 8 | #define IAML_VER 01030000 9 | 10 | #include "interface.h" 11 | #include 12 | #include 13 | 14 | // Because the name was changed to be more understandable 15 | #define PlaceB PlaceJMP 16 | 17 | #ifndef PAGE_SIZE 18 | #define PAGE_SIZE 4096 19 | #endif 20 | 21 | enum eManifestPermissions 22 | { 23 | P_READ_EXTERNAL_STORAGE = 0, 24 | P_WRITE_EXTERNAL_STORAGE, 25 | }; // Unused 26 | 27 | // AML 1.3.0 stuff (Vibration patterns, examples) 28 | static jlong DEFAULT_VIBRATE_PATTERN[4] = {0, 250, 250, 250}; 29 | static jlong g_VibroPattern_Weak[7] = { 0, 20, 80, 20, 80, 20, 80 }; 30 | static jlong g_VibroPattern_Alert[6] = { 0, 200, 100, 200, 100, 400 }; 31 | 32 | // I`m redoing this because i dont want to include additional file 33 | // Thanks @XMDS, maybe someone will use it 34 | struct GlossRegisters 35 | { 36 | #ifdef AML32 37 | enum e_reg 38 | { 39 | R0 = 0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP = R11, R12, IP = R12, R13, SP = R13, R14, LR = R14, R15, PC = R15, CPSR 40 | }; 41 | 42 | union 43 | { 44 | uint32_t reg[17]; 45 | struct 46 | { 47 | uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr, pc, cpsr; 48 | } regs; 49 | }; 50 | #else 51 | enum e_reg 52 | { 53 | X0 = 0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, FP = X29, 54 | Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, 55 | X30, LR = X30, X31, SP = X31, PC, CPSR 56 | }; 57 | 58 | union 59 | { 60 | uint64_t reg[66]; 61 | struct 62 | { 63 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29; 64 | double q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, q30, q31; 65 | uint64_t lr, sp, pc, cpsr; 66 | } regs; 67 | }; 68 | #endif 69 | }; 70 | typedef void* PHookHandle; 71 | typedef void (*HookWithRegistersFn)(GlossRegisters* regs, PHookHandle hook); 72 | 73 | #if defined(__cplusplus) 74 | extern "C" 75 | #endif 76 | size_t strlen(char const*); 77 | 78 | class IAML 79 | { 80 | public: 81 | /* AML 1.0.0.0 */ 82 | virtual const char* GetCurrentGame(); 83 | virtual const char* GetConfigPath(); 84 | virtual bool HasMod(const char* szGUID); 85 | virtual bool HasModOfVersion(const char* szGUID, const char* szVersion); 86 | virtual uintptr_t GetLib(const char* szLib); 87 | virtual uintptr_t GetSym(void* handle, const char* sym); 88 | virtual bool Hook(void* handle, void* fnAddress, void** orgFnAddress = NULL); 89 | virtual bool HookPLT(void* handle, void* fnAddress, void** orgFnAddress = NULL); 90 | virtual int Unprot(uintptr_t handle, size_t len = PAGE_SIZE); 91 | virtual void Write(uintptr_t dest, uintptr_t src, size_t size); 92 | virtual void Read(uintptr_t src, uintptr_t dest, size_t size); 93 | virtual int PlaceNOP(uintptr_t addr, size_t count = 1); 94 | virtual int PlaceJMP(uintptr_t addr, uintptr_t dest); 95 | virtual int PlaceRET(uintptr_t addr); 96 | 97 | /* AML 1.0.0.4 */ 98 | virtual const char* GetDataPath(); // /data/data/.../* 99 | 100 | /* AML 1.0.0.5 */ 101 | virtual const char* GetAndroidDataPath(); // /sdcard/Android/data/.../files/* 102 | virtual uintptr_t GetSym(uintptr_t libAddr, const char* sym); // An additional func but it uses ADDRESS instead of a HANDLE 103 | 104 | /* AML 1.0.0.6 */ 105 | virtual uintptr_t GetLibLength(const char* szLib); 106 | virtual int Redirect(uintptr_t addr, uintptr_t to); // Move directly to "to" from "addr" with the same stack and registers 107 | virtual void PlaceBL(uintptr_t addr, uintptr_t dest); 108 | virtual void PlaceBLX(uintptr_t addr, uintptr_t dest); 109 | virtual uintptr_t PatternScan(const char* pattern, const char* soLib); 110 | virtual uintptr_t PatternScan(const char* pattern, uintptr_t libStart, uintptr_t scanLen); 111 | 112 | /* AML 1.0.1 */ 113 | virtual void PatchForThumb(bool forThumb); 114 | virtual const char* GetFeatures(); 115 | virtual void HookVtableFunc(void* ptr, unsigned int funcNum, void* fnAddress, void** orgFnAddress = NULL, bool instantiate = false); // unsafe 116 | virtual bool IsGameFaked(); 117 | virtual const char* GetRealCurrentGame(); 118 | virtual void* GetLibHandle(const char* soLib); 119 | virtual void* GetLibHandle(uintptr_t addr); 120 | // xDL (will return 0 if xDL is not used) 121 | // These functions always exists 122 | // So no need to check for their availability 123 | virtual bool IsCorrectXDLHandle(void* ptr); 124 | virtual uintptr_t GetLibXDL(void* ptr); 125 | virtual uintptr_t GetAddrBaseXDL(uintptr_t addr); 126 | virtual size_t GetSymSizeXDL(void* ptr); 127 | virtual const char* GetSymNameXDL(void* ptr); 128 | 129 | /* AML 1.0.2 */ 130 | virtual void ShowToast(bool longerDuration, const char* fmt, ...); 131 | virtual bool DownloadFile(const char* url, const char* saveto); 132 | virtual bool DownloadFileToData(const char* url, char* out, size_t outLen); 133 | virtual void FileMD5(const char* path, char* out, size_t out_len); 134 | virtual int GetModsLoadedCount(); 135 | virtual JNIEnv* GetJNIEnvironment(); 136 | virtual jobject GetAppContextObject(); 137 | 138 | /* AML 1.0.2.1 */ 139 | virtual bool HasModOfBiggerVersion(const char* szGUID, const char* szVersion); 140 | 141 | /* AML 1.0.4 */ 142 | virtual void HookVtableFunc(void* ptr, unsigned int funcNum, unsigned int count, void* fnAddress, void** orgFnAddress = NULL, bool instantiate = false); 143 | virtual int PlaceNOP4(uintptr_t addr, size_t count = 1); 144 | virtual const char* GetAndroidDataRootPath(); // /sdcard/Android/data/.../* (not /files/ !!!) 145 | virtual bool HookB(void* handle, void* fnAddress, void** orgFnAddress = NULL); 146 | virtual bool HookBL(void* handle, void* fnAddress, void** orgFnAddress = NULL); 147 | virtual bool HookBLX(void* handle, void* fnAddress, void** orgFnAddress = NULL); 148 | 149 | /* AML 1.2 */ 150 | virtual void MLSSaveFile(); 151 | virtual bool MLSHasValue(const char* key); 152 | virtual void MLSDeleteValue(const char* key); 153 | virtual void MLSSetInt(const char* key, int32_t val); 154 | virtual void MLSSetFloat(const char* key, float val); 155 | virtual void MLSSetInt64(const char* key, int64_t val); 156 | virtual void MLSSetStr(const char* key, const char *val); 157 | virtual bool MLSGetInt(const char* key, int32_t *val); 158 | virtual bool MLSGetFloat(const char* key, float *val); 159 | virtual bool MLSGetInt64(const char* key, int64_t *val); 160 | virtual bool MLSGetStr(const char* key, char *val, size_t len); 161 | 162 | /* AML 1.2.1 */ 163 | virtual bool IsThumbAddr(uintptr_t addr); 164 | virtual uintptr_t GetBranchDest(uintptr_t addr); 165 | 166 | /* AML 1.2.2 */ 167 | virtual int GetAndroidVersion(); 168 | virtual bool CopyFile(const char* file, const char* dest); 169 | // Gloss things 170 | #ifdef AML32 171 | virtual void RedirectReg(...); 172 | #else 173 | virtual void RedirectReg(uintptr_t addr, uintptr_t to, bool doShortHook = false, GlossRegisters::e_reg targetReg = GlossRegisters::e_reg::X16); // Move directly to "to" from "addr" with the same stack and registers (X16 is the same as "Redirect") 174 | #endif 175 | virtual bool HasAddrExecFlag(uintptr_t addr); 176 | virtual void ToggleHook(PHookHandle hook, bool enable); 177 | virtual void DeHook(PHookHandle hook); 178 | virtual PHookHandle HookInline(void* fnAddress, HookWithRegistersFn newFn, bool doShortHook = false); 179 | 180 | /* AML 1.2.3 */ 181 | virtual bool HasFastmanAPKModified(); 182 | virtual const char* GetInternalPath(); // /sdcard/ 183 | virtual const char* GetInternalModsPath(); // /sdcard/AMLMods/*game*/ (by default) 184 | 185 | /* AML 1.3.0 */ 186 | virtual JavaVM* GetJavaVM(); 187 | virtual jobject GetCurrentContext(); 188 | virtual void DoVibro(int msTime); // Pretty strong feedback... If you need a small vibro, do it for like ~20ms, it's gonna be enough 189 | virtual void DoVibro(jlong* pattern, int patternItems); // Patterns might give you more control 190 | virtual void CancelVibro(); 191 | virtual float GetBatteryLevel(); // returns a float from 0.0 to 100.0 192 | 193 | 194 | // Inlines (shortcuts for you!) 195 | inline void Write(uintptr_t dest, const char* str, size_t size) { Write(dest, (uintptr_t)str, size); } // Inline 196 | inline void Write(uintptr_t dest, const char* str) { Write(dest, (uintptr_t)str, strlen(str)); } // Inline 197 | inline void Write8(uintptr_t dest, uint8_t v) { uint8_t vPtr = v; Write(dest, (uintptr_t)&vPtr, 1); } // Inline 198 | inline void Write16(uintptr_t dest, uint16_t v) { uint16_t vPtr = v; Write(dest, (uintptr_t)&vPtr, 2); } // Inline 199 | inline void Write32(uintptr_t dest, uint32_t v) { uint32_t vPtr = v; Write(dest, (uintptr_t)&vPtr, 4); } // Inline 200 | inline void WriteFloat(uintptr_t dest, float v) { float vPtr = v; Write(dest, (uintptr_t)&vPtr, 4); } // Inline 201 | inline void WriteAddr(uintptr_t dest, uintptr_t addr) { uintptr_t addrPtr = addr; Write(dest, (uintptr_t)&addrPtr, sizeof(uintptr_t)); } // Inline 202 | inline void WriteAddr(uintptr_t dest, void* addr) { uintptr_t addrPtr = (uintptr_t)addr; Write(dest, (uintptr_t)&addrPtr, sizeof(uintptr_t)); } // Inline 203 | // Can be used with HookVtableFunc to not to instantiate vtable for 1000 times! 204 | inline void** GetVtable(void* ptr) { return *(void***)ptr; } 205 | inline void SetVtable(void* ptr, void** vtable) { *(void***)ptr = vtable; } 206 | }; 207 | 208 | extern IAML* aml; 209 | inline IAML* GetAMLInterface() { return aml; } 210 | 211 | /* Do not use big conversions */ 212 | #define SET_TO(__a1, __a2) *(void**)&(__a1) = (void*)(__a2) 213 | #define SET_TO_PTR(__a1, __a2) *(void**)&(__a1) = *(void**)(__a2) 214 | #define SETSYM_TO(__a1, __a2, __a3) *(void**)&(__a1) = (void*)(aml->GetSym(__a2, __a3)) 215 | #define SETSYM_TO_PTR(__a1, __a2, __a3) *(void**)&(__a1) = *(void**)(aml->GetSym(__a2, __a3)) 216 | #define AS_ADDR(__a1) *(uintptr_t*)&(__a1) 217 | 218 | /* Unprotect that memory chunk for making changes */ 219 | #define UNPROT(_addr, _count) \ 220 | aml->Unprot((uintptr_t)(_addr), ( _count )); 221 | /* Just write own info to the memory */ 222 | #define WRITE(_addr, _whatToWrite, _size) \ 223 | aml->Write(_addr, _whatToWrite, _size); 224 | 225 | /* Just a hook declaration */ 226 | #define DECL_HOOK(_ret, _name, ...) \ 227 | _ret (*_name)(__VA_ARGS__); \ 228 | _ret HookOf_##_name(__VA_ARGS__) 229 | /* Just a hook declaration with return type = void */ 230 | #define DECL_HOOKv(_name, ...) \ 231 | void (*_name)(__VA_ARGS__); \ 232 | void HookOf_##_name(__VA_ARGS__) 233 | /* Just a hook declaration with return type = bool */ 234 | #define DECL_HOOKb(_name, ...) \ 235 | bool (*_name)(__VA_ARGS__); \ 236 | bool HookOf_##_name(__VA_ARGS__) 237 | /* Just a hook declaration with return type = int */ 238 | #define DECL_HOOKi(_name, ...) \ 239 | int (*_name)(__VA_ARGS__); \ 240 | int HookOf_##_name(__VA_ARGS__) 241 | /* Just a hook declaration with return type = void* */ 242 | #define DECL_HOOKp(_name, ...) \ 243 | void* (*_name)(__VA_ARGS__); \ 244 | void* HookOf_##_name(__VA_ARGS__) 245 | 246 | /* Just a hook of a function */ 247 | #define HOOK(_name, _fnAddr) \ 248 | aml->Hook((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 249 | /* Just a hook of a function (but simpler usage) */ 250 | #define HOOKSYM(_name, _libHndl, _fnSym) \ 251 | aml->Hook((void*)(aml->GetSym(_libHndl, _fnSym)), (void*)(&HookOf_##_name), (void**)(&_name)); 252 | /* Just a hook of a function located in PLT section (by address!) */ 253 | #define HOOKPLT(_name, _fnAddr) \ 254 | aml->HookPLT((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 255 | /* Just a hook of a branch */ 256 | #define HOOKB(_name, _fnAddr) \ 257 | aml->HookB((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 258 | /* Just a hook of a branch with link */ 259 | #define HOOKBL(_name, _fnAddr) \ 260 | aml->HookBL((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 261 | /* Just a hook of a branch with link (and registers exchange) */ 262 | #define HOOKBLX(_name, _fnAddr) \ 263 | aml->HookBLX((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 264 | /* Just a hook of a function hidden behind IL2CPP */ 265 | #define HOOK_IL2CPP(_name, _methodInfo) \ 266 | aml->Hook((void*)_methodInfo->methodPointer, (void*)(&HookOf_##_name), (void**)(&_name)) 267 | 268 | #endif // _IAML -------------------------------------------------------------------------------- /mod/icfg.h: -------------------------------------------------------------------------------- 1 | /* Is not required. Can be used only for a smaller size of mod (~370kb savings) */ 2 | /* because of fstream include (it has a lot of templates & not only) */ 3 | /* There's no reason of using this feature if you're already using fstream */ 4 | 5 | #ifndef _ICFG 6 | #define _ICFG 7 | 8 | class ICFG 9 | { 10 | public: 11 | virtual void* InitIniPointer() = 0; 12 | virtual void ParseInputStream(void* iniPointer, const char* szFilename) = 0; 13 | virtual void GenerateToOutputStream(void* iniPointer, const char* szFilename) = 0; 14 | virtual const char* GetValueFrom(void* iniPointer, const char* szSection, const char* szKey) = 0; 15 | virtual void SetValueTo(void* iniPointer, const char* szSection, const char* szKey, const char* szValue) = 0; 16 | }; 17 | 18 | extern ICFG* icfg; 19 | inline ICFG* GetCFGInterface() 20 | { 21 | return icfg; 22 | } 23 | 24 | #endif // _ICFG -------------------------------------------------------------------------------- /mod/il2cpp.h: -------------------------------------------------------------------------------- 1 | struct IL2Assembly; 2 | struct IL2Object; 3 | struct IL2Class; 4 | struct IL2Image; 5 | struct IL2Array; 6 | struct IL2Type; 7 | 8 | struct IL2Domain; 9 | struct IL2ReflectionType; 10 | struct IL2Exception; 11 | struct IL2Profiler; 12 | struct IL2Thread; 13 | struct IL2ReflectionMethod; 14 | struct IL2ManagedMemorySnapshot; 15 | struct IL2StackFrameInfo; 16 | struct IL2CustomAttrInfo; 17 | struct IL2GenericClass; 18 | struct IL2Defaults; 19 | 20 | struct IL2TypeDefinition; 21 | struct IL2GenericParameter; 22 | struct IL2GenericContainer; 23 | 24 | struct MethodInfo; 25 | struct FieldInfo; 26 | struct PropertyInfo; 27 | struct EventInfo; -------------------------------------------------------------------------------- /mod/interface.h: -------------------------------------------------------------------------------- 1 | /* DO NOT CHANGE IT */ 2 | 3 | #ifndef __GETINTERFACE_H 4 | #define __GETINTERFACE_H 5 | 6 | #if defined(_WIN32) || defined(_WIN64) 7 | #define WIN32_LEAN_AND_MEAN 8 | #include 9 | #else 10 | #include 11 | #endif 12 | #define DEFAULT_LIB_NAME "AML" 13 | 14 | #define WRAP_INTERFACE(__interface_name, __interface_var) RegisterInterface(#__interface_name, __interface_var) 15 | 16 | typedef void* (*GetInterfaceFn)(const char*); 17 | typedef void* (*RegInterfaceFn)(const char*, void*); 18 | 19 | inline void* GetInterface(const char* szInterfaceName) 20 | { 21 | #if defined(_WIN32) || defined(_WIN64) 22 | GetInterfaceFn _GetInterface = (GetInterfaceFn)GetProcAddress(GetModuleHandleA(DEFAULT_LIB_NAME ".dll"), "GetInterface"); 23 | #else 24 | GetInterfaceFn _GetInterface = (GetInterfaceFn)dlsym((void*)dlopen("lib" DEFAULT_LIB_NAME ".so", RTLD_NOW), "GetInterface"); 25 | #endif 26 | return _GetInterface(szInterfaceName); 27 | } 28 | 29 | inline void RegisterInterface(const char* szInterfaceName, void* pInterface) 30 | { 31 | #if defined(_WIN32) || defined(_WIN64) 32 | RegInterfaceFn _RegInterface = (RegInterfaceFn)GetProcAddress(GetModuleHandleA(DEFAULT_LIB_NAME ".dll"), "CreateInterface"); 33 | #else 34 | RegInterfaceFn _RegInterface = (RegInterfaceFn)dlsym((void*)dlopen("lib" DEFAULT_LIB_NAME ".so", RTLD_NOW), "CreateInterface"); 35 | #endif 36 | _RegInterface(szInterfaceName, pInterface); 37 | } 38 | 39 | #endif // __GETINTERFACE_H -------------------------------------------------------------------------------- /mod/listitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // use of undeclared identifier 'NULL' 4 | 5 | #define LIST_START(__cls_name) struct __cls_name { \ 6 | __cls_name *pPrev; \ 7 | __cls_name *pNext; \ 8 | __cls_name *pLast; \ 9 | unsigned int nCount; \ 10 | typedef __cls_name MyClass; \ 11 | \ 12 | inline unsigned int Count() { return !this ? 0 : First()->nCount; } \ 13 | inline __cls_name *First() \ 14 | { \ 15 | if(!this) return NULL; \ 16 | __cls_name *first = this; \ 17 | if(first->pPrev == this) { first->pPrev = NULL; return this; } \ 18 | while(first->pPrev != NULL) first = first->pPrev; \ 19 | return first; \ 20 | } \ 21 | inline __cls_name *CalcLast() \ 22 | { \ 23 | if(!this) return NULL; \ 24 | __cls_name *last = this; \ 25 | while(last->pNext != NULL) last = last->pNext; \ 26 | return last; \ 27 | } \ 28 | inline __cls_name *Last() \ 29 | { \ 30 | return pLast; \ 31 | } \ 32 | inline void Push(__cls_name **listPtr) \ 33 | { \ 34 | __cls_name*& list = *listPtr; \ 35 | pPrev = NULL; \ 36 | if(list == NULL) { \ 37 | pNext = NULL; \ 38 | pLast = this; \ 39 | nCount = 1; \ 40 | } else { \ 41 | pNext = list; \ 42 | pLast = list->pLast; \ 43 | list->pPrev = this; \ 44 | nCount = list->nCount + 1; \ 45 | } \ 46 | list = this; \ 47 | } \ 48 | inline bool Remove(__cls_name **listPtr) { \ 49 | if(!listPtr || !*listPtr || !pLast) return false; \ 50 | __cls_name*& list = *listPtr; \ 51 | if(list == this) { \ 52 | if(pNext) { \ 53 | list = pNext; \ 54 | list->nCount = nCount - 1; \ 55 | list->pPrev = NULL; \ 56 | list->pLast = pLast; \ 57 | } else { \ 58 | list = NULL; \ 59 | } \ 60 | } \ 61 | else if(list->pLast == this) { \ 62 | list->pLast = pPrev; \ 63 | pPrev->pNext = NULL; \ 64 | --(list->nCount); \ 65 | } else { \ 66 | pPrev->pNext = pNext; \ 67 | if(pNext) pNext->pPrev = pPrev; \ 68 | --(list->nCount); \ 69 | } \ 70 | pNext = NULL; pPrev = NULL; pLast = NULL; \ 71 | return true; \ 72 | } \ 73 | inline bool InList(__cls_name **listPtr) \ 74 | { \ 75 | LIST_FOR(*listPtr) { \ 76 | if(item == this) return true; \ 77 | } \ 78 | return false; \ 79 | } 80 | 81 | #define LIST_END() \ 82 | }; 83 | 84 | #define LIST_INITSTART(__cls_name) \ 85 | __cls_name() { 86 | 87 | #define LIST_INITEND() \ 88 | pPrev = NULL; \ 89 | pNext = NULL; \ 90 | pLast = NULL; \ 91 | nCount = 1; \ 92 | } 93 | 94 | // Never use FAST versions if you do "Remove" or "Push" in a loop! Or maintain it by yourself! 95 | 96 | #define LIST_FOR(__list) for(auto item = __list, itemNext = item ? item->pNext : NULL; item != NULL; item = itemNext, itemNext = item ? item->pNext : NULL) 97 | #define LIST_FOR_FAST(__list) for(auto item = __list; item != NULL; item = item->pNext) 98 | #define LIST_FOR2(__list, __itemname) for(auto __itemname = __list, itemNext = __itemname ? __itemname->pNext : NULL; __itemname != NULL; __itemname = itemNext, itemNext = __itemname ? __itemname->pNext : NULL) 99 | #define LIST_FOR2_FAST(__list, __itemname) for(auto __itemname = __list; __itemname != NULL; __itemname = __itemname->pNext) 100 | #define LIST_FOR_REVERSE(__list) for(auto item = __list ? __list->pLast : NULL, itemPrev = item ? item->pPrev : NULL; item != NULL; item = itemPrev, itemPrev = item ? item->pPrev : NULL) 101 | #define LIST_FOR_REVERSE_FAST(__list) for(auto item = __list ? __list->pLast : NULL; item != NULL; item = item->pPrev) 102 | #define LIST_RESET(__list, __resetFunc) LIST_FOR(__list) { __resetFunc(); item->Remove(&__list); } -------------------------------------------------------------------------------- /mod/logger.cpp: -------------------------------------------------------------------------------- 1 | #ifndef DONT_USE_STB 2 | #ifndef DONT_IMPLEMENT_STB 3 | #define STB_SPRINTF_IMPLEMENTATION 4 | #endif 5 | #include 6 | 7 | #define vsnprintf stbsp_vsnprintf 8 | #endif 9 | #include "logger.h" 10 | #include 11 | #include 12 | 13 | Logger::Logger() 14 | { 15 | strncpy(m_szTag, "AML Mod", sizeof(m_szTag)); 16 | m_bEnabled = true; 17 | m_fnLogCallback = NULL; 18 | m_fnNewTagCallback = NULL; 19 | m_fnToggledCallback = NULL; 20 | } 21 | 22 | void Logger::ToggleOutput(bool enabled) 23 | { 24 | if(m_bEnabled != enabled) 25 | { 26 | m_bEnabled = enabled; 27 | if(m_fnToggledCallback) m_fnToggledCallback(enabled); 28 | } 29 | } 30 | 31 | void Logger::SetTag(const char* szTag) 32 | { 33 | if(m_fnNewTagCallback) m_fnNewTagCallback(m_szTag, szTag); 34 | strncpy(m_szTag, szTag, sizeof(m_szTag)-1); 35 | m_szTag[sizeof(m_szTag)-1] = 0; 36 | } 37 | 38 | void Logger::Print(eLogPrio prio, const char* szMessage, ...) 39 | { 40 | #ifndef NOLOGGING 41 | if(!m_bEnabled) return; 42 | 43 | char buffer[TMPBUF_SIZE]; 44 | va_list args; 45 | va_start(args, szMessage); 46 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 47 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 48 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 49 | va_end(args); 50 | #endif 51 | } 52 | 53 | void Logger::PrintV(eLogPrio prio, const char* szMessage, va_list args) 54 | { 55 | #ifndef NOLOGGING 56 | if(!m_bEnabled) return; 57 | 58 | char buffer[TMPBUF_SIZE]; 59 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 60 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 61 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 62 | #endif 63 | } 64 | 65 | void Logger::PrintTag(eLogPrio prio, const char* szTag, const char* szMessage, ...) 66 | { 67 | #ifndef NOLOGGING 68 | if(!m_bEnabled) return; 69 | 70 | char buffer[TMPBUF_SIZE]; 71 | va_list args; 72 | va_start(args, szMessage); 73 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 74 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 75 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 76 | va_end(args); 77 | #endif 78 | } 79 | 80 | void Logger::PrintTagV(eLogPrio prio, const char* szTag, const char* szMessage, va_list args) 81 | { 82 | #ifndef NOLOGGING 83 | if(!m_bEnabled) return; 84 | 85 | char buffer[TMPBUF_SIZE]; 86 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 87 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 88 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 89 | #endif 90 | } 91 | 92 | void Logger::Info(const char* szMessage, ...) 93 | { 94 | #ifndef NOLOGGING 95 | if(!m_bEnabled) return; 96 | 97 | char buffer[TMPBUF_SIZE]; 98 | va_list args; 99 | va_start(args, szMessage); 100 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 101 | if(m_fnLogCallback) m_fnLogCallback(LogP_Info, buffer); 102 | __android_log_write(ANDROID_LOG_INFO, m_szTag, buffer); 103 | va_end(args); 104 | #endif 105 | } 106 | 107 | void Logger::InfoV(const char* szMessage, va_list args) 108 | { 109 | #ifndef NOLOGGING 110 | if(!m_bEnabled) return; 111 | 112 | char buffer[TMPBUF_SIZE]; 113 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 114 | if(m_fnLogCallback) m_fnLogCallback(LogP_Info, buffer); 115 | __android_log_write(ANDROID_LOG_INFO, m_szTag, buffer); 116 | #endif 117 | } 118 | 119 | void Logger::Error(const char* szMessage, ...) 120 | { 121 | #ifndef NOLOGGING 122 | if(!m_bEnabled) return; 123 | 124 | char buffer[TMPBUF_SIZE]; 125 | va_list args; 126 | va_start(args, szMessage); 127 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 128 | if(m_fnLogCallback) m_fnLogCallback(LogP_Error, buffer); 129 | __android_log_write(ANDROID_LOG_ERROR, m_szTag, buffer); 130 | va_end(args); 131 | #endif 132 | } 133 | 134 | void Logger::ErrorV(const char* szMessage, va_list args) 135 | { 136 | #ifndef NOLOGGING 137 | if(!m_bEnabled) return; 138 | 139 | char buffer[TMPBUF_SIZE]; 140 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 141 | if(m_fnLogCallback) m_fnLogCallback(LogP_Error, buffer); 142 | __android_log_write(ANDROID_LOG_ERROR, m_szTag, buffer); 143 | #endif 144 | } 145 | 146 | static Logger loggerLocal; 147 | Logger* logger = &loggerLocal; -------------------------------------------------------------------------------- /mod/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOGGER_H 2 | #define _LOGGER_H 3 | 4 | #include 5 | #define TMPBUF_SIZE 2048 // Max logging buf is 4096 btw 6 | 7 | /* Define NOLOGGING if you DONT need logs in any form */ 8 | /* You can do it like that in Android.mk: LOCAL_CXXFLAGS += -DNOLOGGING */ 9 | 10 | enum eLogPrio 11 | { 12 | LogP_Unk = 0, 13 | LogP_Default, 14 | LogP_Verbose, 15 | LogP_Debug, 16 | LogP_Info, 17 | LogP_Warn, 18 | LogP_Error, 19 | LogP_Fatal, 20 | LogP_Silent, 21 | }; 22 | 23 | class Logger; 24 | extern Logger* logger; 25 | 26 | class Logger 27 | { 28 | public: 29 | typedef void (*LoggerMessageCB)(eLogPrio prio, const char* msg); 30 | typedef void (*LoggerSetTagCB)(const char* oldTag, const char* newTag); 31 | typedef void (*LoggerToggledCB)(bool isEnabled); 32 | 33 | inline static Logger* GetLogger() { return logger; } 34 | Logger(); 35 | 36 | void ToggleOutput(bool enabled); 37 | void SetTag(const char* szTag); 38 | void Print(eLogPrio prio, const char* szMessage, ...); 39 | void PrintV(eLogPrio prio, const char* szMessage, va_list args); 40 | void PrintTag(eLogPrio prio, const char* szTag, const char* szMessage, ...); 41 | void PrintTagV(eLogPrio prio, const char* szTag, const char* szMessage, va_list args); 42 | void Info(const char* szMessage, ...); 43 | void InfoV(const char* szMessage, va_list args); 44 | void Error(const char* szMessage, ...); 45 | void ErrorV(const char* szMessage, va_list args); 46 | #ifdef NOLOGGING 47 | inline bool HasOutput() { return false; } 48 | #else 49 | inline bool HasOutput() { return m_bEnabled; } 50 | #endif 51 | 52 | inline void SetMessageCB(LoggerMessageCB fnCB) { m_fnLogCallback = fnCB; } 53 | inline void SetTagCB(LoggerSetTagCB fnCB) { m_fnNewTagCallback = fnCB; } 54 | inline void SetToggleCB(LoggerToggledCB fnCB) { m_fnToggledCallback = fnCB; } 55 | 56 | private: 57 | char m_szTag[31]; 58 | bool m_bEnabled; 59 | LoggerMessageCB m_fnLogCallback; 60 | LoggerSetTagCB m_fnNewTagCallback; 61 | LoggerToggledCB m_fnToggledCallback; 62 | }; 63 | 64 | #endif // _LOGGER_H -------------------------------------------------------------------------------- /mod/thirdparty/INICPP_LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Fabian Meyer 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 | -------------------------------------------------------------------------------- /mod/thirdparty/STB_LICENSE: -------------------------------------------------------------------------------- 1 | This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /modpaks.cpp: -------------------------------------------------------------------------------- 1 | #include "modpaks.h" 2 | #include 3 | #include 4 | #include 5 | 6 | extern int g_nDownloadTimeout; 7 | 8 | CURL* curl = NULL; 9 | char szFileData[FILE_DATA_SIZE] = {0}; 10 | extern char g_szUserAgent[256]; 11 | size_t nReadedBytes = 0; 12 | 13 | void InitCURL() 14 | { 15 | curl_global_init(CURL_GLOBAL_ALL); 16 | curl = curl_easy_init(); 17 | } 18 | 19 | static size_t WriteToFileCB(void* buffer, size_t size, size_t nmemb, void* userdata) 20 | { 21 | FILE* file = fopen((char*)userdata, "wb"); 22 | if(!file) return 0; 23 | 24 | size_t written = fwrite(buffer, size, nmemb, file); 25 | fclose(file); 26 | return written; 27 | } 28 | static size_t WriteToDataCB(void* buffer, size_t size, size_t nmemb, void* userdata) 29 | { 30 | szFileData[0] = 0; 31 | nReadedBytes = size * nmemb; 32 | return snprintf(szFileData, FILE_DATA_SIZE, "%s", (const char*)buffer); 33 | } 34 | 35 | CURLcode DownloadFile(const char* url, const char* path) 36 | { 37 | if(!curl) return CURLE_FAILED_INIT; 38 | curl_easy_reset(curl); 39 | 40 | // Dont delete file contents at first try 41 | FILE* file = fopen(path, "a"); 42 | if(!file) return CURLE_WRITE_ERROR; 43 | fclose(file); 44 | 45 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // cURL fails at SSL/TLS here, for some reason 46 | curl_easy_setopt(curl, CURLOPT_URL, url); 47 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteToFileCB); 48 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, path); 49 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, g_nDownloadTimeout); 50 | curl_easy_setopt(curl, CURLOPT_USERAGENT, g_szUserAgent); 51 | 52 | CURLcode res = curl_easy_perform(curl); 53 | return res; 54 | } 55 | 56 | CURLcode DownloadFileToData(const char* url) 57 | { 58 | if(!curl) return CURLE_FAILED_INIT; 59 | curl_easy_reset(curl); 60 | 61 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); // cURL fails at SSL/TLS here, for some reason 62 | curl_easy_setopt(curl, CURLOPT_URL, url); 63 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteToDataCB); 64 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, url); 65 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, g_nDownloadTimeout); 66 | curl_easy_setopt(curl, CURLOPT_USERAGENT, g_szUserAgent); 67 | 68 | CURLcode res = curl_easy_perform(curl); 69 | return res; 70 | } 71 | 72 | inline bool str_equal(const char* str1, const char* str2) { 73 | for ( ; *str1 == *str2 && *str1 != 0; ++str1, ++str2 ) {} 74 | return *str2 == *str1; 75 | } 76 | extern bool g_bShowUpdatedToast, g_bShowUpdateFailedToast; 77 | static inline void ProcessLine(ModDesc* d, char* data) 78 | { 79 | char left[64], middle[64], right[128]; 80 | int scanned = sscanf(data, "%[^:]:%[^:]:%[^\n]", left, middle, right); 81 | if(scanned < 3) return; 82 | else if(!strncmp(left, "myself", 6) || !strcmp(left, d->m_pInfo->GUID())) 83 | { 84 | if(!modlist->HasModOfVersion(d->m_pInfo->GUID(), middle)) 85 | { 86 | CURLcode res = DownloadFile(right, d->m_szLibPath); 87 | if(res == CURLE_OK) 88 | { 89 | if(g_bShowUpdatedToast) aml->ShowToast(true, "Mod %s has been updated!\nRestart the game to load new mod.", d->m_pInfo->Name()); 90 | } 91 | else 92 | { 93 | if(g_bShowUpdateFailedToast) aml->ShowToast(true, "Mod %s has failed to update!\nIs this located in internal folder..?", d->m_pInfo->Name()); 94 | } 95 | } 96 | } 97 | else 98 | { 99 | // files 100 | // 1: filepath (relative to files folder) 101 | // 2: checksum (MD5?) 102 | // 3: URL 103 | 104 | char md5[MINIMUM_MD5_BUF_SIZE] {0}; 105 | char filepath[256], filepathTmp[256], filepathOld[256]; 106 | snprintf(filepath, sizeof(filepath), "%s/%s", aml->GetAndroidDataPath(), left); 107 | snprintf(filepathOld, sizeof(filepathOld), "%s/%s.old", aml->GetAndroidDataPath(), left); 108 | aml->FileMD5(filepath, md5, sizeof(md5)); 109 | 110 | //if(!md5[0]) return; 111 | 112 | if(md5[0] == 0 || !str_equal(md5, middle)) 113 | { 114 | DownloadFile(right, filepath); 115 | } 116 | } 117 | } 118 | void ProcessData(ModDesc* d) 119 | { 120 | if(szFileData[0] == 0) return; // bruh 121 | 122 | char* newlinePtr = &szFileData[0], *data; 123 | do 124 | { 125 | data = newlinePtr; 126 | newlinePtr = strstr(data, "\n"); 127 | if(newlinePtr != NULL) 128 | { 129 | newlinePtr[0] = 0; 130 | ++newlinePtr; 131 | } 132 | if(data[0] != 0 && data[0] != '/' && data[1] != '/') ProcessLine(d, data); 133 | if(newlinePtr == NULL) break; 134 | } 135 | while(true); 136 | 137 | // End 138 | szFileData[0] = 0; 139 | } 140 | -------------------------------------------------------------------------------- /modslist.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern ModDesc* pLastModProcessed; 7 | 8 | Mods* listMods = NULL; 9 | LIST_START(Mods) 10 | 11 | LIST_INITSTART(Mods) 12 | pModInfo = NULL; 13 | pModDesc = NULL; 14 | pHandle = NULL; 15 | LIST_INITEND() 16 | 17 | static void AddNew(ModInfo* info, void* libhandle, const char* path) 18 | { 19 | Mods* newItem = new Mods; 20 | newItem->pModInfo = info; 21 | newItem->pHandle = libhandle; 22 | 23 | ModDesc* d = new ModDesc(); 24 | d->m_pInfo = info; 25 | d->m_pHandle = libhandle; 26 | d->m_aDependencies = NULL; 27 | if(path) snprintf(d->m_szLibPath, 256, "%s", path); 28 | else d->m_szLibPath[0] = 0; 29 | if(libhandle != NULL) 30 | { 31 | GetDependenciesListFn getDepList = (GetDependenciesListFn)dlsym(libhandle, "__GetDepsList"); 32 | if(getDepList != NULL) d->m_aDependencies = getDepList(); 33 | } 34 | newItem->pModDesc = d; 35 | 36 | newItem->Push(&listMods); 37 | } 38 | static Mods* Get(const char* guid) 39 | { 40 | LIST_FOR_FAST(listMods) 41 | { 42 | if (!strcmp(item->pModInfo->szGUID, guid)) return item; 43 | } 44 | return NULL; 45 | } 46 | 47 | ModInfo* pModInfo; 48 | ModDesc* pModDesc; 49 | void* pHandle; 50 | LIST_END() 51 | 52 | bool ModsList::AddMod(ModInfo* modinfo, void* modhandle, const char* path) 53 | { 54 | if(Mods::Get(modinfo->szGUID) != NULL) return false; 55 | Mods::AddNew(modinfo, modhandle, path); 56 | return true; 57 | } 58 | 59 | bool ModsList::RemoveMod(ModInfo* modinfo) 60 | { 61 | LIST_FOR(listMods) 62 | { 63 | if(item->pModInfo == modinfo) 64 | { 65 | dlclose(item->pHandle); 66 | if(item->Remove(&listMods)) 67 | { 68 | delete item->pModDesc; 69 | delete item; 70 | } 71 | return true; 72 | } 73 | } 74 | return false; 75 | } 76 | 77 | bool ModsList::RemoveMod(const char* szGUID) 78 | { 79 | LIST_FOR(listMods) 80 | { 81 | if(!strcmp(item->pModInfo->szGUID, szGUID)) 82 | { 83 | dlclose(item->pHandle); 84 | if(item->Remove(&listMods)) 85 | { 86 | delete item->pModDesc; 87 | delete item; 88 | } 89 | return true; 90 | } 91 | } 92 | return false; 93 | } 94 | 95 | bool ModsList::HasMod(const char* szGUID) 96 | { 97 | LIST_FOR_FAST(listMods) 98 | { 99 | if(!strcmp(item->pModInfo->szGUID, szGUID)) 100 | { 101 | return true; 102 | } 103 | } 104 | return false; 105 | } 106 | 107 | bool ModsList::HasModOfVersion(const char* szGUID, const char* szVersion) 108 | { 109 | if(szVersion[0] == '\0') return HasMod(szGUID); 110 | unsigned short major, minor, revision, build; 111 | if(sscanf(szVersion, "%hu.%hu.%hu.%hu", &major, &minor, &revision, &build) < 4) 112 | { 113 | if(sscanf(szVersion, "%hu.%hu.%hu", &major, &minor, &revision) < 3) 114 | { 115 | if(sscanf(szVersion, "%hu.%hu", &major, &minor) < 2) 116 | { 117 | major = (unsigned short)atoi(szVersion); 118 | } 119 | revision = 0; 120 | } 121 | build = 0; 122 | } 123 | 124 | ModInfo* pInfo = NULL; 125 | LIST_FOR_FAST(listMods) 126 | { 127 | pInfo = item->pModInfo; 128 | if(!strcmp(pInfo->szGUID, szGUID)) 129 | { 130 | if(pInfo->version.major > major) return true; 131 | if(pInfo->version.major == major) 132 | { 133 | if(pInfo->version.minor > minor) return true; 134 | if(pInfo->version.minor == minor) 135 | { 136 | if(pInfo->version.revision > revision) return true; 137 | if(pInfo->version.revision == revision && pInfo->version.build >= build) return true; 138 | } 139 | } 140 | return false; 141 | } 142 | } 143 | return false; 144 | } 145 | 146 | bool ModsList::HasModOfBiggerVersion(const char* szGUID, const char* szVersion) 147 | { 148 | if(szVersion[0] == '\0') return HasMod(szGUID); 149 | unsigned short major, minor, revision, build; 150 | if(sscanf(szVersion, "%hu.%hu.%hu.%hu", &major, &minor, &revision, &build) < 4) 151 | { 152 | if(sscanf(szVersion, "%hu.%hu.%hu", &major, &minor, &revision) < 3) 153 | { 154 | if(sscanf(szVersion, "%hu.%hu", &major, &minor) < 2) 155 | { 156 | major = (unsigned short)atoi(szVersion); 157 | } 158 | revision = 0; 159 | } 160 | build = 0; 161 | } 162 | 163 | ModInfo* pInfo = NULL; 164 | LIST_FOR_FAST(listMods) 165 | { 166 | pInfo = item->pModInfo; 167 | if(!strcmp(pInfo->szGUID, szGUID)) 168 | { 169 | if(pInfo->version.major > major) return true; 170 | if(pInfo->version.major == major) 171 | { 172 | if(pInfo->version.minor > minor) return true; 173 | if(pInfo->version.minor == minor) 174 | { 175 | if(pInfo->version.revision > revision) return true; 176 | if(pInfo->version.revision == revision && pInfo->version.build > build) return true; 177 | } 178 | } 179 | return false; 180 | } 181 | } 182 | return false; 183 | } 184 | 185 | void ModsList::ProcessDependencies() 186 | { 187 | ModInfoDependency* depList; 188 | ModInfo* info; 189 | 190 | label_run_dependencies_check: 191 | //logger->Info("Checking dependencies from the start! Mods count: %d", modlist->GetModsNum()); 192 | LIST_FOR_FAST(listMods) 193 | { 194 | // If the mod is already ok or doesnt require check, depList = NULL 195 | depList = item->pModDesc->m_aDependencies; 196 | if(depList) 197 | { 198 | info = item->pModInfo; 199 | for(int i = 0; depList[i].szGUID && depList[i].szGUID[0] != 0; ++i) 200 | { 201 | if(depList[i].szVersion) 202 | { 203 | if(!HasModOfVersion(depList[i].szGUID, depList[i].szVersion)) 204 | { 205 | logger->Error("Mod (GUID %s) requires a mod %s of version %s and newer", info->szGUID, depList[i].szGUID, depList[i].szVersion); 206 | ModsList::RemoveMod(info); 207 | goto label_run_dependencies_check; 208 | } 209 | } 210 | else 211 | { 212 | if(!HasMod(depList[i].szGUID)) 213 | { 214 | logger->Error("Mod (GUID %s) requires a mod %s of any version", info->szGUID, depList[i].szGUID); 215 | ModsList::RemoveMod(info); 216 | goto label_run_dependencies_check; 217 | } 218 | } 219 | } 220 | 221 | // Everything is okay, we dont need to check it again! 222 | item->pModDesc->m_aDependencies = NULL; 223 | } 224 | } 225 | } 226 | 227 | void ModsList::ProcessPreLoading() 228 | { 229 | OnModLoadFn onModPreLoadFn; 230 | ModDesc* desc; 231 | void* handle; 232 | LIST_FOR_FAST(listMods) 233 | { 234 | handle = item->pHandle; 235 | if(handle != NULL) 236 | { 237 | desc = item->pModDesc; 238 | pLastModProcessed = desc; 239 | 240 | onModPreLoadFn = (OnModLoadFn)dlsym(handle, "OnModPreLoad"); 241 | //if(onModPreLoadFn == NULL) onModPreLoadFn = (OnModLoadFn)dlsym(handle, "_Z12OnModPreLoadv"); 242 | if(onModPreLoadFn != NULL) onModPreLoadFn(); 243 | 244 | desc->m_fnOnModLoaded = (OnModLoadFn)dlsym(handle, "OnModLoad"); 245 | //if(desc->m_fnOnModLoaded == NULL) desc->m_fnOnModLoaded = (OnModLoadFn)dlsym(handle, "_Z9OnModLoadv"); 246 | 247 | desc->m_fnOnModUnloaded = (OnModLoadFn)dlsym(handle, "OnModUnload"); 248 | //if(desc->m_fnOnModUnloaded == NULL) desc->m_fnOnModUnloaded = (OnModLoadFn)dlsym(handle, "_Z11OnModUnloadv"); 249 | 250 | desc->m_fnRequestUpdaterURL = (GetUpdaterURLFn)dlsym(handle, "OnUpdaterURLRequested"); 251 | //if(desc->m_fnRequestUpdaterURL == NULL) desc->m_fnRequestUpdaterURL = (GetUpdaterURLFn)dlsym(handle, "_Z21OnUpdaterURLRequestedv"); 252 | 253 | desc->m_fnInterfaceAddedCB = (OnInterfaceAddedFn)dlsym(handle, "OnInterfaceAdded"); 254 | //if(desc->m_fnInterfaceAddedCB == NULL) desc->m_fnInterfaceAddedCB = (OnInterfaceAddedFn)dlsym(handle, "_Z16OnInterfaceAddedPKcPKv"); 255 | 256 | desc->m_fnOnAllModsLoaded = (OnModLoadFn)dlsym(handle, "OnAllModsLoaded"); 257 | //if(desc->m_fnOnAllModsLoaded == NULL) desc->m_fnOnAllModsLoaded = (OnModLoadFn)dlsym(handle, "_Z15OnAllModsLoadedv"); 258 | 259 | desc->m_fnGameCrashedCB = (OnGameCrashedFn)dlsym(handle, "OnGameCrash"); 260 | //if(desc->m_fnGameCrashedCB == NULL) desc->m_fnGameCrashedCB = (OnGameCrashedFn)dlsym(handle, "_Z11OnGameCrashv"); 261 | } 262 | } 263 | logger->Info("Mods were preloaded!"); 264 | } 265 | 266 | void ModsList::ProcessLoading() 267 | { 268 | ModDesc* desc = NULL; 269 | LIST_FOR_FAST(listMods) 270 | { 271 | desc = item->pModDesc; 272 | pLastModProcessed = desc; 273 | if(desc->m_fnOnModLoaded) desc->m_fnOnModLoaded(); 274 | } 275 | logger->Info("Mods were loaded!"); 276 | } 277 | 278 | void ModsList::ProcessUnloading() 279 | { 280 | ModDesc* desc = NULL; 281 | LIST_FOR_FAST(listMods) 282 | { 283 | desc = item->pModDesc; 284 | pLastModProcessed = desc; 285 | if(desc->m_fnOnModUnloaded) desc->m_fnOnModUnloaded(); 286 | } 287 | } 288 | 289 | void ModsList::ProcessUpdater() 290 | { 291 | ModDesc* desc = NULL; 292 | LIST_FOR_FAST(listMods) 293 | { 294 | desc = item->pModDesc; 295 | pLastModProcessed = desc; 296 | if(desc->m_fnRequestUpdaterURL) 297 | { 298 | const char* url = desc->m_fnRequestUpdaterURL(); 299 | CURLcode res = DownloadFileToData(url); 300 | if(res != CURLE_OK) 301 | { 302 | logger->Error("Updater failed to determine an update info for %s, err %d", desc->m_pInfo->GUID(), res); 303 | } 304 | else 305 | { 306 | ProcessData(desc); 307 | } 308 | } 309 | } 310 | } 311 | 312 | void ModsList::ProcessCrash(const char* szLibName, int sig, int code, uintptr_t libaddr, mcontext_t* mcontext) 313 | { 314 | ModDesc* desc = NULL; 315 | LIST_FOR_FAST(listMods) 316 | { 317 | desc = item->pModDesc; 318 | pLastModProcessed = desc; 319 | if(desc->m_fnGameCrashedCB) desc->m_fnGameCrashedCB(szLibName, sig, code, libaddr, mcontext); 320 | } 321 | } 322 | 323 | int ModsList::GetModsNum() 324 | { 325 | return listMods->Count(); 326 | } 327 | 328 | void ModsList::PrintModsList(std::ofstream& logfile) 329 | { 330 | logfile << "\n----------------------------------------------------\nList of loaded mods (count=" << std::dec << listMods->Count() << "):\n"; 331 | 332 | ModInfo* info = NULL; 333 | ModDesc* desc = NULL; 334 | LIST_FOR_REVERSE_FAST(listMods) 335 | { 336 | info = item->pModInfo; 337 | desc = item->pModDesc; 338 | 339 | logfile << info->Name() << " (" << info->Author() << ", version " << info->VersionString() << ")\n"; 340 | logfile << " - GUID: " << info->GUID() << " | Base: 0x" << std::hex << std::uppercase << (uintptr_t)desc->m_pHandle << " | Path: " << desc->m_szLibPath << "\n"; 341 | } 342 | } 343 | 344 | void ModsList::OnInterfaceAdded(const char* name, const void* ptr) 345 | { 346 | ModDesc* desc = NULL; 347 | LIST_FOR_FAST(listMods) 348 | { 349 | desc = item->pModDesc; 350 | pLastModProcessed = desc; 351 | if(desc->m_fnInterfaceAddedCB) desc->m_fnInterfaceAddedCB(name, ptr); 352 | } 353 | } 354 | 355 | void ModsList::OnAllModsLoaded() 356 | { 357 | ModDesc* desc = NULL; 358 | LIST_FOR_FAST(listMods) 359 | { 360 | desc = item->pModDesc; 361 | pLastModProcessed = desc; 362 | if(desc->m_fnOnAllModsLoaded) desc->m_fnOnAllModsLoaded(); 363 | } 364 | logger->Info("Mods were postloaded!"); 365 | } 366 | 367 | static ModsList modlistLocal; 368 | ModsList* modlist = &modlistLocal; -------------------------------------------------------------------------------- /ndkpath.txt: -------------------------------------------------------------------------------- 1 | D:\android-ndk -------------------------------------------------------------------------------- /news.txt: -------------------------------------------------------------------------------- 1 | A new version of SkyGFX is coming out soon! Yippee! -------------------------------------------------------------------------------- /template_of_mod/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_CPP_EXTENSION := .cpp .cc 5 | LOCAL_MODULE := modtemplate 6 | LOCAL_SRC_FILES := main.cpp mod/logger.cpp mod/config.cpp 7 | LOCAL_CFLAGS += -O2 -mfloat-abi=softfp -DNDEBUG -std=c++17 8 | LOCAL_C_INCLUDES += ./include 9 | LOCAL_LDLIBS += -llog 10 | include $(BUILD_SHARED_LIBRARY) -------------------------------------------------------------------------------- /template_of_mod/Application.mk: -------------------------------------------------------------------------------- 1 | APP_STL := c++_static 2 | APP_ABI := armeabi-v7a 3 | APP_OPTIM := release -------------------------------------------------------------------------------- /template_of_mod/build.ps1: -------------------------------------------------------------------------------- 1 | $NDKPath = Get-Content $PSScriptRoot/NDKPath.txt 2 | Write-Output "NDK located at: $NDKPath" 3 | 4 | $buildScript = "$NDKPath/build/ndk-build" 5 | if (-not ($PSVersionTable.PSEdition -eq "Core")) { 6 | $buildScript += ".cmd" 7 | } 8 | 9 | Write-Output "[BUILD] Starting NDK..." 10 | & $buildScript NDK_PROJECT_PATH=$PSScriptRoot APP_BUILD_SCRIPT=$PSScriptRoot/Android.mk NDK_APPLICATION_MK=$PSScriptRoot/Application.mk NDK_DEBUG=0 11 | Write-Output "[BUILD] Done!" 12 | 13 | Exit $LASTEXITCODE -------------------------------------------------------------------------------- /template_of_mod/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | MYMODCFG(net.rusjj.mymod.guid, AML Mod Template, 1.0, RusJJ) 6 | 7 | //MYMOD(net.rusjj.mymod.guid, AML Mod Template Without Config, 1.0, RusJJ) 8 | 9 | //NEEDGAME(net.rusjj.mygame) 10 | 11 | //BEGIN_DEPLIST() 12 | // ADD_DEPENDENCY_VER(net.rusjj.aml, 1.0) 13 | //END_DEPLIST() 14 | 15 | uintptr_t pGameLibrary = 0; 16 | ConfigEntry* pCfgMyBestEntry; 17 | 18 | extern "C" void OnModLoad() 19 | { 20 | logger->SetTag("Mod Template"); 21 | 22 | pGameLibrary = aml->GetLib("libMyGame.so"); 23 | if(pGameLibrary) 24 | { 25 | logger->Info("MyGame mod is loaded!"); 26 | } 27 | else 28 | { 29 | logger->Error("MyGame mod is not loaded :("); 30 | return; // Do not load our mod? 31 | } 32 | 33 | pCfgMyBestEntry = cfg->Bind("mySetting", "DefaultValue is 0?", "MyUniqueSection"); 34 | pCfgMyBestEntry->SetString("DefaultValue is unchanged"); 35 | pCfgMyBestEntry->SetInt(1); 36 | pCfgMyBestEntry->Reset(); 37 | delete pCfgMyBestEntry; // Clean-up memory 38 | 39 | bool bEnabled = cfg->Bind("Enable", true)->GetBool(); 40 | delete Config::pLastEntry; // Clean-up of the latest ConfigEntry* 41 | 42 | cfg->Save(); // Will only save if something was changed 43 | } 44 | -------------------------------------------------------------------------------- /template_of_mod/mod/amlmod.h: -------------------------------------------------------------------------------- 1 | #ifndef _AMLMOD 2 | #define _AMLMOD 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __arm__ 11 | #define AML32 12 | #define BYBIT(__32val, __64val) (__32val) 13 | #elif defined __aarch64__ 14 | #define AML64 15 | #define BYBIT(__32val, __64val) (__64val) 16 | #else 17 | #error This lib is supposed to work on ARM only! 18 | #endif 19 | 20 | #ifdef __clang__ 21 | #define TARGET_ARM __attribute__((target("no-thumb-mode"))) 22 | #define TARGET_THUMB __attribute__((target("thumb-mode"))) 23 | #endif 24 | 25 | #ifdef __GNUC__ 26 | #define ASM_NAKED __attribute__((naked)) 27 | #define EXPORT __attribute__((visibility("default"))) 28 | #else 29 | #define ASM_NAKED __declspec(naked) 30 | #define EXPORT 31 | #endif 32 | 33 | #define MYMOD(_guid, _name, _version, _author) \ 34 | static ModInfo modinfoLocal(#_guid, #_name, #_version, #_author); \ 35 | ModInfo* modinfo = &modinfoLocal; \ 36 | extern "C" ModInfo* __GetModInfo() { return modinfo; } \ 37 | IAML* aml = (IAML*)GetInterface("AMLInterface"); 38 | 39 | #define MYMODCFG(_guid, _name, _version, _author) \ 40 | MYMOD(_guid, _name, _version, _author); \ 41 | static Config cfgLocal(#_guid); \ 42 | Config* cfg = &cfgLocal; 43 | 44 | #define NEEDGAME(_pkg_name) \ 45 | extern "C" const char* __INeedASpecificGame() {return #_pkg_name;} 46 | 47 | #define MYMODDECL() \ 48 | extern ModInfo* modinfo; // Just in case if you need to use that somewhere else in your mod 49 | 50 | /* Dependencies! */ 51 | #define BEGIN_DEPLIST() \ 52 | static ModInfoDependency g_listDependencies[] = { 53 | 54 | #define ADD_DEPENDENCY(_guid) \ 55 | {#_guid, ""}, 56 | 57 | #define ADD_DEPENDENCY_VER(_guid, _version) \ 58 | {#_guid, #_version}, 59 | 60 | #define END_DEPLIST() \ 61 | {"", ""} }; \ 62 | extern "C" ModInfoDependency* __GetDepsList() { return &g_listDependencies[0]; } 63 | 64 | 65 | 66 | #define MINIMUM_MD5_BUF_SIZE 33 67 | 68 | struct MemChunk_t 69 | { 70 | char* out; 71 | size_t out_len; 72 | }; 73 | 74 | struct ModInfoDependency 75 | { 76 | const char* szGUID; 77 | const char* szVersion; 78 | }; 79 | 80 | struct ModVersion 81 | { 82 | unsigned short major; 83 | unsigned short minor; 84 | unsigned short revision; 85 | unsigned short build; 86 | }; 87 | 88 | // Should be faster than strncpy? 89 | inline char *strxcpy(char* __restrict__ dst, const char* __restrict__ src, int len) 90 | { 91 | if (!len) return NULL; 92 | while (--len && (*dst++ = *src++)); 93 | if (!len) 94 | { 95 | *dst++ = '\0'; 96 | return *src ? NULL : dst; 97 | } 98 | else 99 | { 100 | return dst; 101 | } 102 | } 103 | 104 | inline int clampint(int min, int max, int v) 105 | { 106 | if(v < min) return min; 107 | else if(v > max) return max; 108 | return v; 109 | } 110 | inline void clampint(int min, int max, int* v) 111 | { 112 | if(*v < min) *v = min; 113 | else if(*v > max) *v = max; 114 | } 115 | inline float clampfloat(float min, float max, float v) 116 | { 117 | if(v < min) return min; 118 | else if(v > max) return max; 119 | return v; 120 | } 121 | inline void clampfloat(float min, float max, float* v) 122 | { 123 | if(*v < min) *v = min; 124 | else if(*v > max) *v = max; 125 | } 126 | 127 | class ModInfo 128 | { 129 | public: 130 | ModInfo(const char* szGUID, const char* szName, const char* szVersion, const char* szAuthor) 131 | { 132 | /* No buffer overflow! */ 133 | strxcpy(this->szGUID, szGUID, sizeof(ModInfo::szGUID)); this->szGUID[sizeof(ModInfo::szGUID) - 1] = '\0'; 134 | strxcpy(this->szName, szName, sizeof(ModInfo::szName)); this->szName[sizeof(ModInfo::szName) - 1] = '\0'; 135 | strxcpy(this->szVersion, szVersion, sizeof(ModInfo::szVersion)); this->szVersion[sizeof(ModInfo::szVersion) - 1] = '\0'; 136 | strxcpy(this->szAuthor, szAuthor, sizeof(ModInfo::szAuthor)); this->szAuthor[sizeof(ModInfo::szAuthor) - 1] = '\0'; 137 | 138 | /* GUID should be lowcase */ 139 | for(int i = 0; this->szGUID[i] != '\0'; ++i) 140 | { 141 | this->szGUID[i] = tolower((int)(this->szGUID[i])); 142 | } 143 | 144 | /* Parse version string */ 145 | if(sscanf(this->szVersion, "%hu.%hu.%hu.%hu", &version.major, &version.minor, &version.revision, &version.build) < 4) 146 | { 147 | if(sscanf(this->szVersion, "%hu.%hu.%hu", &version.major, &version.minor, &version.revision) < 3) 148 | { 149 | if(sscanf(this->szVersion, "%hu.%hu", &version.major, &version.minor) < 2) 150 | { 151 | version.major = (unsigned short)atoi(this->szVersion); 152 | } 153 | version.revision = 0; 154 | } 155 | version.build = 0; 156 | } 157 | } 158 | inline const char* GUID() { return szGUID; } 159 | inline const char* Name() { return szName; } 160 | inline const char* VersionString() { return szVersion; } 161 | inline const char* Author() { return szAuthor; } 162 | inline unsigned short Major() { return version.major; } 163 | inline unsigned short Minor() { return version.minor; } 164 | inline unsigned short Revision() { return version.revision; } 165 | inline unsigned short Build() { return version.build; } 166 | 167 | private: 168 | char szGUID[48]; 169 | char szName[48]; 170 | char szVersion[24]; 171 | char szAuthor[48]; 172 | ModVersion version; 173 | 174 | friend class ModsList; 175 | friend class Mods; 176 | }; 177 | 178 | typedef ModInfo* (*GetModInfoFn)(); 179 | 180 | 181 | 182 | #include "iaml.h" 183 | 184 | #endif // _AMLMOD -------------------------------------------------------------------------------- /template_of_mod/mod/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG 2 | #define _CONFIG 3 | 4 | #define KEY_SECTION_BUFFER_C 64 5 | #define VALUE_BUFFER_C 384 6 | 7 | /* Is not required. Can be used only for a smaller size of mod (~480kb savings) */ 8 | #include "icfg.h" 9 | #include 10 | 11 | class ConfigEntry; 12 | 13 | struct rgba_t 14 | { 15 | union { 16 | struct { unsigned char r, g, b, a; }; 17 | struct { unsigned char x, y, z, w; }; 18 | unsigned char v[4]; 19 | unsigned int value; 20 | }; 21 | 22 | rgba_t() : r(0), g(0), b(0), a(0) {} 23 | rgba_t(unsigned char v) : r(v), g(v), b(v), a(255) {} 24 | rgba_t(unsigned char _r, unsigned char _g, unsigned char _b) : r(_r), g(_g), b(_b), a(255) {} 25 | rgba_t(unsigned char _r, unsigned char _g, unsigned char _b, unsigned char _a) : r(_r), g(_g), b(_b), a(_a) {} 26 | }; 27 | 28 | class Config 29 | { 30 | public: 31 | Config(const char* szName); 32 | void Init(); 33 | void Save(); 34 | // Allocated, needs to be manually deleted 35 | ConfigEntry* Bind(const char* szKey, const char* szDefaultValue, const char* szSection = "Preferences"); 36 | ConfigEntry* Bind(const char* szKey, int nDefaultValue, const char* szSection = "Preferences"); 37 | ConfigEntry* Bind(const char* szKey, float flDefaultValue, const char* szSection = "Preferences"); 38 | ConfigEntry* Bind(const char* szKey, bool bDefaultValue, const char* szSection = "Preferences"); 39 | ConfigEntry* Bind(const char* szKey, rgba_t clrDefaultValue, const char* szSection = "Preferences"); 40 | 41 | // FAST GET. NO NEED TO CLEAN THE MEMORY. 42 | const char* GetString(const char* szKey, const char* szDefaultValue, const char* szSection = "Preferences"); 43 | int GetInt(const char* szKey, int nDefaultValue, const char* szSection = "Preferences"); 44 | float GetFloat(const char* szKey, float flDefaultValue, const char* szSection = "Preferences"); 45 | bool GetBool(const char* szKey, bool bDefaultValue, const char* szSection = "Preferences"); 46 | rgba_t GetColor(const char* szKey, rgba_t clrDefaultValue, const char* szSection = "Preferences"); 47 | 48 | // Self-explained 49 | inline bool IsValueChanged() { return m_bValueChanged; } 50 | inline void ClearLast(); 51 | 52 | static Config* GetConfig(); 53 | static ConfigEntry* pLastEntry; 54 | 55 | private: 56 | bool m_bInitialized; 57 | bool m_bValueChanged; 58 | const char* m_szName; 59 | void* m_iniMyConfig; 60 | 61 | #ifdef _ICFG 62 | /* Built-in optimizer thinks he's the best! Ha-ha... Not funny. It's 3AM... */ 63 | ICFG* m_pICFG; 64 | #endif 65 | 66 | friend class ConfigEntry; 67 | }; 68 | 69 | class ConfigEntry 70 | { 71 | public: 72 | ConfigEntry() : m_bLoadedData(false), m_szValue(""), m_szDefaultValue("") {} 73 | void SetString(const char* newValue); 74 | inline const char* GetString() { return m_szValue; } 75 | void GetString(char* str, size_t len); 76 | void SetFloat(float newValue); 77 | inline float GetFloat() { return m_fFloatValue; } 78 | void SetBool(bool newValue); 79 | inline bool GetBool() { return m_nIntegerValue; } 80 | void SetInt(int newValue); 81 | inline int GetInt() { return m_nIntegerValue; } 82 | inline void Reset() { SetString(m_szDefaultValue); } 83 | rgba_t ParseColor(); 84 | void SetColor(rgba_t clr, bool asFloat = false); 85 | 86 | inline bool LoadedUndefault() { return m_bNotDefaultValue; } 87 | inline int Clamp(int min, int max) 88 | { 89 | if(m_nIntegerValue < min) 90 | { 91 | m_pBoundCfg->m_bValueChanged = true; 92 | int ret = m_nIntegerValue - min; 93 | m_nIntegerValue = min; 94 | m_fFloatValue = (float)min; 95 | m_szValue[0] = 0; 96 | return ret; 97 | } 98 | if(m_nIntegerValue > max) 99 | { 100 | m_pBoundCfg->m_bValueChanged = true; 101 | int ret = m_nIntegerValue - max; 102 | m_nIntegerValue = max; 103 | m_fFloatValue = (float)max; 104 | m_szValue[0] = 0; 105 | return ret; 106 | } 107 | return 0; 108 | } 109 | inline float Clamp(float min, float max) 110 | { 111 | if(m_fFloatValue < min) 112 | { 113 | m_pBoundCfg->m_bValueChanged = true; 114 | float ret = m_fFloatValue - min; 115 | m_nIntegerValue = (int)min; 116 | m_fFloatValue = min; 117 | m_szValue[0] = 0; 118 | return ret; 119 | } 120 | if(m_fFloatValue > max) 121 | { 122 | m_pBoundCfg->m_bValueChanged = true; 123 | float ret = m_fFloatValue - max; 124 | m_nIntegerValue = (int)max; 125 | m_fFloatValue = max; 126 | m_szValue[0] = 0; 127 | return ret; 128 | } 129 | return 0.0f; 130 | } 131 | 132 | private: 133 | Config* m_pBoundCfg; 134 | bool m_bLoadedData; 135 | bool m_bNotDefaultValue; 136 | char m_szMySection[KEY_SECTION_BUFFER_C]; 137 | char m_szMyKey[KEY_SECTION_BUFFER_C]; 138 | float m_fFloatValue; 139 | union 140 | { 141 | int m_nIntegerValue; 142 | rgba_t m_ColorValue; 143 | }; 144 | char m_szValue[VALUE_BUFFER_C]; 145 | char m_szDefaultValue[VALUE_BUFFER_C]; 146 | 147 | friend class Config; 148 | }; 149 | inline void Config::ClearLast() { if(pLastEntry) { delete pLastEntry; pLastEntry = NULL; } } 150 | extern Config* cfg; 151 | 152 | #endif // _CONFIG 153 | -------------------------------------------------------------------------------- /template_of_mod/mod/config_inipp.cpp: -------------------------------------------------------------------------------- 1 | #ifndef DONT_USE_STB 2 | #include 3 | #define sprintf stbsp_sprintf 4 | #define snprintf stbsp_snprintf 5 | #endif 6 | #include "config.h" 7 | #include 8 | 9 | #include "amlmod.h" 10 | #include "iaml.h" 11 | #if !defined(__AML) && defined(_ICFG) 12 | ICFG* icfg; 13 | #else 14 | #include 15 | #include "thirdparty/inipp.h" 16 | #endif 17 | #ifdef __AML 18 | extern char g_szCfgPath[0xFF]; 19 | #endif 20 | 21 | inline bool str_equal(const char* str1, const char* str2) { 22 | for ( ; *str1 == *str2 && *str1 != 0; ++str1, ++str2 ); 23 | return *str2 == *str1; 24 | } 25 | 26 | extern ModInfo* modinfo; 27 | ConfigEntry* Config::pLastEntry = NULL; 28 | 29 | Config::Config(const char* szName) 30 | { 31 | #if !defined(__AML) && defined(_ICFG) 32 | m_pICFG = (ICFG*)GetInterface("AMLConfig"); 33 | m_iniMyConfig = m_pICFG->InitIniPointer(); 34 | #else 35 | m_iniMyConfig = new inipp::Ini(); 36 | logger->Info("inipp 0x%16X, 0x%16X", m_iniMyConfig, *(void**)m_iniMyConfig); 37 | #endif 38 | m_bInitialized = false; 39 | m_bValueChanged = false; 40 | m_szName = szName; 41 | 42 | #ifndef __AML 43 | Init(); 44 | #endif 45 | } 46 | 47 | void Config::Init() 48 | { 49 | if(m_bInitialized) return; 50 | m_bInitialized = true; 51 | 52 | #if !defined(__AML) && defined(_ICFG) 53 | m_pICFG->ParseInputStream(m_iniMyConfig, m_szName); 54 | #else 55 | char path[0xFF]; 56 | #ifdef __AML 57 | snprintf(path, sizeof(path), "%s/%s.ini", g_szCfgPath, m_szName); 58 | std::ifstream cfgStream(path); 59 | #else 60 | snprintf(path, sizeof(path), "%s/%s.ini", aml->GetConfigPath(), m_szName); 61 | std::ifstream cfgStream(path); 62 | #endif 63 | if(cfgStream.is_open()) 64 | { 65 | ((inipp::Ini*)m_iniMyConfig)->parse(cfgStream); 66 | } 67 | cfgStream.close(); 68 | #endif 69 | } 70 | 71 | void Config::Save() 72 | { 73 | if(!m_bInitialized || !m_bValueChanged) return; 74 | 75 | m_bValueChanged = false; 76 | #if !defined(__AML) && defined(_ICFG) 77 | m_pICFG->GenerateToOutputStream(m_iniMyConfig, m_szName); 78 | #else 79 | char path[0xFF]; 80 | #ifdef __AML 81 | snprintf(path, sizeof(path), "%s/%s.ini", g_szCfgPath, m_szName); 82 | std::ofstream cfgStream(path); 83 | #else 84 | snprintf(path, sizeof(path), "%s/%s.ini", aml->GetConfigPath(), m_szName); 85 | std::ofstream cfgStream(path); 86 | #endif 87 | if(cfgStream.is_open()) 88 | { 89 | ((inipp::Ini*)m_iniMyConfig)->generate(cfgStream); 90 | } 91 | cfgStream << ""; 92 | cfgStream.close(); 93 | #endif 94 | } 95 | 96 | ConfigEntry* Config::Bind(const char* szKey, const char* szDefaultValue, const char* szSection) 97 | { 98 | if(!m_bInitialized) return NULL; 99 | ConfigEntry* pRet = new ConfigEntry; 100 | pRet->m_pBoundCfg = this; 101 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 102 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 103 | strncpy(pRet->m_szDefaultValue, szDefaultValue, sizeof(pRet->m_szDefaultValue)); 104 | const char* tryToGetValue; 105 | #if !defined(__AML) && defined(_ICFG) 106 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 107 | #else 108 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 109 | #endif 110 | if(tryToGetValue[0] == '\0') 111 | pRet->SetString(szDefaultValue); 112 | else 113 | { 114 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 115 | pRet->SetString(tryToGetValue); 116 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 117 | } 118 | Save(); 119 | pLastEntry = pRet; 120 | return pRet; 121 | } 122 | 123 | ConfigEntry* Config::Bind(const char* szKey, int nDefaultValue, const char* szSection) 124 | { 125 | if(!m_bInitialized) return NULL; 126 | ConfigEntry* pRet = new ConfigEntry; 127 | pRet->m_pBoundCfg = this; 128 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 129 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 130 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%d", nDefaultValue); 131 | const char* tryToGetValue; 132 | #if !defined(__AML) && defined(_ICFG) 133 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 134 | #else 135 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 136 | #endif 137 | if(tryToGetValue[0] == '\0') 138 | pRet->SetInt(nDefaultValue); 139 | else 140 | { 141 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 142 | pRet->SetString(tryToGetValue); 143 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 144 | } 145 | Save(); 146 | pLastEntry = pRet; 147 | return pRet; 148 | } 149 | 150 | ConfigEntry* Config::Bind(const char* szKey, float flDefaultValue, const char* szSection) 151 | { 152 | if(!m_bInitialized) return NULL; 153 | ConfigEntry* pRet = new ConfigEntry; 154 | pRet->m_pBoundCfg = this; 155 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 156 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 157 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%f", flDefaultValue); 158 | const char* tryToGetValue; 159 | #if !defined(__AML) && defined(_ICFG) 160 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 161 | #else 162 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 163 | #endif 164 | if(tryToGetValue[0] == '\0') 165 | pRet->SetFloat(flDefaultValue); 166 | else 167 | { 168 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 169 | pRet->SetString(tryToGetValue); 170 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 171 | } 172 | Save(); 173 | pLastEntry = pRet; 174 | return pRet; 175 | } 176 | 177 | ConfigEntry* Config::Bind(const char* szKey, bool bDefaultValue, const char* szSection) 178 | { 179 | if(!m_bInitialized) return NULL; 180 | ConfigEntry* pRet = new ConfigEntry; 181 | pRet->m_pBoundCfg = this; 182 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 183 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 184 | pRet->m_szDefaultValue[0] = bDefaultValue ? '1' : '0'; pRet->m_szDefaultValue[1] = 0; 185 | const char* tryToGetValue; 186 | #if !defined(__AML) && defined(_ICFG) 187 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 188 | #else 189 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 190 | #endif 191 | if(tryToGetValue[0] == '\0') 192 | pRet->SetBool(bDefaultValue); 193 | else 194 | { 195 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 196 | pRet->SetString(tryToGetValue); 197 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 198 | } 199 | Save(); 200 | pLastEntry = pRet; 201 | return pRet; 202 | } 203 | 204 | ConfigEntry* Config::BindOnce(const char* szKey, const char* szDefaultValue, const char* szSection) 205 | { 206 | if(!m_bInitialized) return NULL; 207 | ConfigEntry entry; ConfigEntry* pRet = &entry; 208 | pRet->m_pBoundCfg = this; 209 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 210 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 211 | strncpy(pRet->m_szDefaultValue, szDefaultValue, sizeof(pRet->m_szDefaultValue)); 212 | const char* tryToGetValue; 213 | #if !defined(__AML) && defined(_ICFG) 214 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 215 | #else 216 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 217 | #endif 218 | if(tryToGetValue[0] == '\0') 219 | pRet->SetString(szDefaultValue); 220 | else 221 | { 222 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 223 | pRet->SetString(tryToGetValue); 224 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 225 | } 226 | Save(); 227 | pLastEntry = pRet; // Unsafe! 228 | return pRet; 229 | } 230 | 231 | ConfigEntry* Config::BindOnce(const char* szKey, int nDefaultValue, const char* szSection) 232 | { 233 | if(!m_bInitialized) return NULL; 234 | ConfigEntry entry; ConfigEntry* pRet = &entry; 235 | pRet->m_pBoundCfg = this; 236 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 237 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 238 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%d", nDefaultValue); 239 | const char* tryToGetValue; 240 | #if !defined(__AML) && defined(_ICFG) 241 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 242 | #else 243 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 244 | #endif 245 | if(tryToGetValue[0] == '\0') 246 | pRet->SetInt(nDefaultValue); 247 | else 248 | { 249 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 250 | pRet->SetString(tryToGetValue); 251 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 252 | } 253 | Save(); 254 | pLastEntry = pRet; // Unsafe! 255 | return pRet; 256 | } 257 | 258 | ConfigEntry* Config::BindOnce(const char* szKey, float flDefaultValue, const char* szSection) 259 | { 260 | if(!m_bInitialized) return NULL; 261 | ConfigEntry entry; ConfigEntry* pRet = &entry; 262 | pRet->m_pBoundCfg = this; 263 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 264 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 265 | snprintf(pRet->m_szDefaultValue, sizeof(pRet->m_szDefaultValue), "%f", flDefaultValue); 266 | const char* tryToGetValue; 267 | #if !defined(__AML) && defined(_ICFG) 268 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 269 | #else 270 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 271 | #endif 272 | if(tryToGetValue[0] == '\0') 273 | pRet->SetFloat(flDefaultValue); 274 | else 275 | { 276 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 277 | pRet->SetString(tryToGetValue); 278 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 279 | } 280 | Save(); 281 | pLastEntry = pRet; // Unsafe! 282 | return pRet; 283 | } 284 | 285 | ConfigEntry* Config::BindOnce(const char* szKey, bool bDefaultValue, const char* szSection) 286 | { 287 | if(!m_bInitialized) return NULL; 288 | ConfigEntry entry; ConfigEntry* pRet = &entry; 289 | pRet->m_pBoundCfg = this; 290 | strncpy(pRet->m_szMySection, szSection, sizeof(pRet->m_szMySection)); 291 | strncpy(pRet->m_szMyKey, szKey, sizeof(pRet->m_szMyKey)); 292 | pRet->m_szDefaultValue[0] = bDefaultValue ? '1' : '0'; pRet->m_szDefaultValue[1] = 0; 293 | const char* tryToGetValue; 294 | #if !defined(__AML) && defined(_ICFG) 295 | tryToGetValue = m_pICFG->GetValueFrom(m_iniMyConfig, szSection, szKey); 296 | #else 297 | tryToGetValue = ((inipp::Ini*)m_iniMyConfig)->sections[szSection][szKey].c_str(); 298 | #endif 299 | if(tryToGetValue[0] == '\0') 300 | { 301 | pRet->SetBool(bDefaultValue); 302 | } 303 | else 304 | { 305 | bool bShouldChange = !pRet->m_pBoundCfg->m_bValueChanged; 306 | pRet->SetString(tryToGetValue); 307 | if(bShouldChange) pRet->m_pBoundCfg->m_bValueChanged = false; 308 | } 309 | Save(); 310 | pLastEntry = pRet; // Unsafe! 311 | return pRet; 312 | } 313 | 314 | void ConfigEntry::SetString(const char* newValue) 315 | { 316 | if(m_bLoadedData && str_equal(newValue, m_szValue)) return; 317 | 318 | strncpy(m_szValue, newValue, sizeof(m_szValue)-1); m_szValue[sizeof(m_szValue)-1] = 0; 319 | m_nIntegerValue = atoi(m_szValue); 320 | m_fFloatValue = (float)atof(m_szValue); 321 | 322 | m_pBoundCfg->m_bValueChanged = true; 323 | m_bLoadedData = true; 324 | 325 | #if !defined(__AML) && defined(_ICFG) 326 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 327 | #else 328 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 329 | #endif 330 | } 331 | 332 | void ConfigEntry::GetString(char* str, size_t len) 333 | { 334 | strncpy(str, GetString(), len); 335 | } 336 | 337 | void ConfigEntry::SetFloat(float newValue) 338 | { 339 | if(m_bLoadedData && m_fFloatValue == newValue) return; 340 | 341 | m_fFloatValue = newValue; 342 | m_nIntegerValue = (int)newValue; 343 | snprintf(m_szValue, sizeof(m_szValue), "%f", newValue); 344 | 345 | m_pBoundCfg->m_bValueChanged = true; 346 | m_bLoadedData = true; 347 | 348 | #if !defined(__AML) && defined(_ICFG) 349 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 350 | #else 351 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 352 | #endif 353 | } 354 | 355 | void ConfigEntry::SetInt(int newValue) 356 | { 357 | if(m_bLoadedData && m_nIntegerValue == newValue) return; 358 | 359 | m_fFloatValue = (float)newValue; 360 | m_nIntegerValue = newValue; 361 | snprintf(m_szValue, sizeof(m_szValue), "%d", newValue); 362 | 363 | m_pBoundCfg->m_bValueChanged = true; 364 | m_bLoadedData = true; 365 | 366 | #if !defined(__AML) && defined(_ICFG) 367 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 368 | #else 369 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 370 | #endif 371 | } 372 | 373 | void ConfigEntry::SetBool(bool newValue) 374 | { 375 | if(m_bLoadedData && m_nIntegerValue == newValue?1:0) return; 376 | 377 | m_fFloatValue = newValue?1.0f:0.0f; 378 | m_nIntegerValue = newValue?1:0; 379 | m_szValue[0] = newValue ? '1' : '0'; m_szValue[1] = 0; 380 | 381 | m_pBoundCfg->m_bValueChanged = true; 382 | m_bLoadedData = true; 383 | 384 | #if !defined(__AML) && defined(_ICFG) 385 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 386 | #else 387 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 388 | #endif 389 | } 390 | 391 | inline bool IsRGBValue(int value) { return value >= 0 && value <= 255; } 392 | inline bool IsRGBFloatValue(float value) { return value >= 0 && value <= 1; } 393 | rgba_t ConfigEntry::ParseColor() 394 | { 395 | int r, g, b, a, sscanfed = sscanf(m_szValue, "%d %d %d %d", &r, &g, &b, &a); 396 | if(sscanfed == 4 && IsRGBValue(r) && IsRGBValue(g) && IsRGBValue(b) && IsRGBValue(a)) 397 | { 398 | return rgba_t{(unsigned char)r,(unsigned char)g,(unsigned char)b,(unsigned char)a}; 399 | } 400 | else if(sscanfed == 3 && IsRGBValue(r) && IsRGBValue(g) && IsRGBValue(b)) 401 | { 402 | return rgba_t{(unsigned char)r,(unsigned char)g,(unsigned char)b,255}; 403 | } 404 | else 405 | { 406 | float fr, fg, fb, fa; 407 | sscanfed = sscanf(m_szValue, "%f %f %f %f", &fr, &fg, &fb, &fa); 408 | if(sscanfed == 4 && IsRGBFloatValue(r) && IsRGBFloatValue(g) && IsRGBFloatValue(b) && IsRGBFloatValue(a)) 409 | { 410 | return rgba_t{(unsigned char)(255*fr),(unsigned char)(255*fg),(unsigned char)(255*fb),(unsigned char)(255*fa)}; 411 | } 412 | else if(sscanfed == 3 && IsRGBFloatValue(r) && IsRGBFloatValue(g) && IsRGBFloatValue(b)) 413 | { 414 | return rgba_t{(unsigned char)(255*fr),(unsigned char)(255*fg),(unsigned char)(255*fb),255}; 415 | } 416 | } 417 | return rgba_t{255,255,255,255}; 418 | } 419 | 420 | void ConfigEntry::SetColor(rgba_t clr, bool asFloat) 421 | { 422 | m_nIntegerValue = (int)clr.r; 423 | m_fFloatValue = (float)clr.r; 424 | if(asFloat) snprintf(m_szValue, sizeof(m_szValue), "%.3f %.3f %.3f %.3f", (float)(clr.r/255.0f), (float)(clr.g/255.0f), (float)(clr.b/255.0f), (float)(clr.a/255.0f)); 425 | else snprintf(m_szValue, sizeof(m_szValue), "%d %d %d %d", (int)clr.r, (int)clr.g, (int)clr.b, (int)clr.a); 426 | 427 | // Kinda expensive to parse the color every time 428 | // Why do you may want it to be changed automatically anyway? 429 | m_pBoundCfg->m_bValueChanged = true; 430 | m_bLoadedData = true; 431 | 432 | #if !defined(__AML) && defined(_ICFG) 433 | m_pBoundCfg->m_pICFG->SetValueTo(m_pBoundCfg->m_iniMyConfig, m_szMySection, m_szMyKey, m_szValue); 434 | #else 435 | ((inipp::Ini*)(m_pBoundCfg->m_iniMyConfig))->sections[m_szMySection][m_szMyKey] = m_szValue; 436 | #endif 437 | } 438 | -------------------------------------------------------------------------------- /template_of_mod/mod/iaml.h: -------------------------------------------------------------------------------- 1 | #ifndef _IAML 2 | #define _IAML 3 | 4 | // Usage: place 3 lines somewhere in the code AFTER #include 5 | // #if !defined(IAML_VER) && IAML_VER < 01030000 6 | // #error "You need to update your MOD folder to 1.3.0!" 7 | // #endif 8 | #define IAML_VER 01030000 9 | 10 | #include "interface.h" 11 | #include 12 | #include 13 | 14 | // Because the name was changed to be more understandable 15 | #define PlaceB PlaceJMP 16 | 17 | #ifndef PAGE_SIZE 18 | #define PAGE_SIZE 4096 19 | #endif 20 | 21 | enum eManifestPermissions 22 | { 23 | P_READ_EXTERNAL_STORAGE = 0, 24 | P_WRITE_EXTERNAL_STORAGE, 25 | }; // Unused 26 | 27 | // AML 1.3.0 stuff (Vibration patterns, examples) 28 | static jlong DEFAULT_VIBRATE_PATTERN[4] = {0, 250, 250, 250}; 29 | static jlong g_VibroPattern_Weak[7] = { 0, 20, 80, 20, 80, 20, 80 }; 30 | static jlong g_VibroPattern_Alert[6] = { 0, 200, 100, 200, 100, 400 }; 31 | 32 | // I`m redoing this because i dont want to include additional file 33 | // Thanks @XMDS, maybe someone will use it 34 | struct GlossRegisters 35 | { 36 | #ifdef AML32 37 | enum e_reg 38 | { 39 | R0 = 0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP = R11, R12, IP = R12, R13, SP = R13, R14, LR = R14, R15, PC = R15, CPSR 40 | }; 41 | 42 | union 43 | { 44 | uint32_t reg[17]; 45 | struct 46 | { 47 | uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr, pc, cpsr; 48 | } regs; 49 | }; 50 | #else 51 | enum e_reg 52 | { 53 | X0 = 0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, FP = X29, 54 | Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, 55 | X30, LR = X30, X31, SP = X31, PC, CPSR 56 | }; 57 | 58 | union 59 | { 60 | uint64_t reg[66]; 61 | struct 62 | { 63 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29; 64 | double q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, q30, q31; 65 | uint64_t lr, sp, pc, cpsr; 66 | } regs; 67 | }; 68 | #endif 69 | }; 70 | typedef void* PHookHandle; 71 | typedef void (*HookWithRegistersFn)(GlossRegisters* regs, PHookHandle hook); 72 | 73 | #if defined(__cplusplus) 74 | extern "C" 75 | #endif 76 | size_t strlen(char const*); 77 | 78 | class IAML 79 | { 80 | public: 81 | /* AML 1.0.0.0 */ 82 | virtual const char* GetCurrentGame(); 83 | virtual const char* GetConfigPath(); 84 | virtual bool HasMod(const char* szGUID); 85 | virtual bool HasModOfVersion(const char* szGUID, const char* szVersion); 86 | virtual uintptr_t GetLib(const char* szLib); 87 | virtual uintptr_t GetSym(void* handle, const char* sym); 88 | virtual bool Hook(void* handle, void* fnAddress, void** orgFnAddress = NULL); 89 | virtual bool HookPLT(void* handle, void* fnAddress, void** orgFnAddress = NULL); 90 | virtual int Unprot(uintptr_t handle, size_t len = PAGE_SIZE); 91 | virtual void Write(uintptr_t dest, uintptr_t src, size_t size); 92 | virtual void Read(uintptr_t src, uintptr_t dest, size_t size); 93 | virtual int PlaceNOP(uintptr_t addr, size_t count = 1); 94 | virtual int PlaceJMP(uintptr_t addr, uintptr_t dest); 95 | virtual int PlaceRET(uintptr_t addr); 96 | 97 | /* AML 1.0.0.4 */ 98 | virtual const char* GetDataPath(); // /data/data/.../* 99 | 100 | /* AML 1.0.0.5 */ 101 | virtual const char* GetAndroidDataPath(); // /sdcard/Android/data/.../files/* 102 | virtual uintptr_t GetSym(uintptr_t libAddr, const char* sym); // An additional func but it uses ADDRESS instead of a HANDLE 103 | 104 | /* AML 1.0.0.6 */ 105 | virtual uintptr_t GetLibLength(const char* szLib); 106 | virtual int Redirect(uintptr_t addr, uintptr_t to); // Move directly to "to" from "addr" with the same stack and registers 107 | virtual void PlaceBL(uintptr_t addr, uintptr_t dest); 108 | virtual void PlaceBLX(uintptr_t addr, uintptr_t dest); 109 | virtual uintptr_t PatternScan(const char* pattern, const char* soLib); 110 | virtual uintptr_t PatternScan(const char* pattern, uintptr_t libStart, uintptr_t scanLen); 111 | 112 | /* AML 1.0.1 */ 113 | virtual void PatchForThumb(bool forThumb); 114 | virtual const char* GetFeatures(); 115 | virtual void HookVtableFunc(void* ptr, unsigned int funcNum, void* fnAddress, void** orgFnAddress = NULL, bool instantiate = false); // unsafe 116 | virtual bool IsGameFaked(); 117 | virtual const char* GetRealCurrentGame(); 118 | virtual void* GetLibHandle(const char* soLib); 119 | virtual void* GetLibHandle(uintptr_t addr); 120 | // xDL (will return 0 if xDL is not used) 121 | // These functions always exists 122 | // So no need to check for their availability 123 | virtual bool IsCorrectXDLHandle(void* ptr); 124 | virtual uintptr_t GetLibXDL(void* ptr); 125 | virtual uintptr_t GetAddrBaseXDL(uintptr_t addr); 126 | virtual size_t GetSymSizeXDL(void* ptr); 127 | virtual const char* GetSymNameXDL(void* ptr); 128 | 129 | /* AML 1.0.2 */ 130 | virtual void ShowToast(bool longerDuration, const char* fmt, ...); 131 | virtual bool DownloadFile(const char* url, const char* saveto); 132 | virtual bool DownloadFileToData(const char* url, char* out, size_t outLen); 133 | virtual void FileMD5(const char* path, char* out, size_t out_len); 134 | virtual int GetModsLoadedCount(); 135 | virtual JNIEnv* GetJNIEnvironment(); 136 | virtual jobject GetAppContextObject(); 137 | 138 | /* AML 1.0.2.1 */ 139 | virtual bool HasModOfBiggerVersion(const char* szGUID, const char* szVersion); 140 | 141 | /* AML 1.0.4 */ 142 | virtual void HookVtableFunc(void* ptr, unsigned int funcNum, unsigned int count, void* fnAddress, void** orgFnAddress = NULL, bool instantiate = false); 143 | virtual int PlaceNOP4(uintptr_t addr, size_t count = 1); 144 | virtual const char* GetAndroidDataRootPath(); // /sdcard/Android/data/.../* (not /files/ !!!) 145 | virtual bool HookB(void* handle, void* fnAddress, void** orgFnAddress = NULL); 146 | virtual bool HookBL(void* handle, void* fnAddress, void** orgFnAddress = NULL); 147 | virtual bool HookBLX(void* handle, void* fnAddress, void** orgFnAddress = NULL); 148 | 149 | /* AML 1.2 */ 150 | virtual void MLSSaveFile(); 151 | virtual bool MLSHasValue(const char* key); 152 | virtual void MLSDeleteValue(const char* key); 153 | virtual void MLSSetInt(const char* key, int32_t val); 154 | virtual void MLSSetFloat(const char* key, float val); 155 | virtual void MLSSetInt64(const char* key, int64_t val); 156 | virtual void MLSSetStr(const char* key, const char *val); 157 | virtual bool MLSGetInt(const char* key, int32_t *val); 158 | virtual bool MLSGetFloat(const char* key, float *val); 159 | virtual bool MLSGetInt64(const char* key, int64_t *val); 160 | virtual bool MLSGetStr(const char* key, char *val, size_t len); 161 | 162 | /* AML 1.2.1 */ 163 | virtual bool IsThumbAddr(uintptr_t addr); 164 | virtual uintptr_t GetBranchDest(uintptr_t addr); 165 | 166 | /* AML 1.2.2 */ 167 | virtual int GetAndroidVersion(); 168 | virtual bool CopyFile(const char* file, const char* dest); 169 | // Gloss things 170 | #ifdef AML32 171 | virtual void RedirectReg(...); 172 | #else 173 | virtual void RedirectReg(uintptr_t addr, uintptr_t to, bool doShortHook = false, GlossRegisters::e_reg targetReg = GlossRegisters::e_reg::X16); // Move directly to "to" from "addr" with the same stack and registers (X16 is the same as "Redirect") 174 | #endif 175 | virtual bool HasAddrExecFlag(uintptr_t addr); 176 | virtual void ToggleHook(PHookHandle hook, bool enable); 177 | virtual void DeHook(PHookHandle hook); 178 | virtual PHookHandle HookInline(void* fnAddress, HookWithRegistersFn newFn, bool doShortHook = false); 179 | 180 | /* AML 1.2.3 */ 181 | virtual bool HasFastmanAPKModified(); 182 | virtual const char* GetInternalPath(); // /sdcard/ 183 | virtual const char* GetInternalModsPath(); // /sdcard/AMLMods/*game*/ (by default) 184 | 185 | /* AML 1.3.0 */ 186 | virtual JavaVM* GetJavaVM(); 187 | virtual jobject GetCurrentContext(); 188 | virtual void DoVibro(int msTime); // Pretty strong feedback... If you need a small vibro, do it for like ~20ms, it's gonna be enough 189 | virtual void DoVibro(jlong* pattern, int patternItems); // Patterns might give you more control 190 | virtual void CancelVibro(); 191 | virtual float GetBatteryLevel(); // returns a float from 0.0 to 100.0 192 | 193 | 194 | // Inlines (shortcuts for you!) 195 | inline void Write(uintptr_t dest, const char* str, size_t size) { Write(dest, (uintptr_t)str, size); } // Inline 196 | inline void Write(uintptr_t dest, const char* str) { Write(dest, (uintptr_t)str, strlen(str)); } // Inline 197 | inline void Write8(uintptr_t dest, uint8_t v) { uint8_t vPtr = v; Write(dest, (uintptr_t)&vPtr, 1); } // Inline 198 | inline void Write16(uintptr_t dest, uint16_t v) { uint16_t vPtr = v; Write(dest, (uintptr_t)&vPtr, 2); } // Inline 199 | inline void Write32(uintptr_t dest, uint32_t v) { uint32_t vPtr = v; Write(dest, (uintptr_t)&vPtr, 4); } // Inline 200 | inline void WriteFloat(uintptr_t dest, float v) { float vPtr = v; Write(dest, (uintptr_t)&vPtr, 4); } // Inline 201 | inline void WriteAddr(uintptr_t dest, uintptr_t addr) { uintptr_t addrPtr = addr; Write(dest, (uintptr_t)&addrPtr, sizeof(uintptr_t)); } // Inline 202 | inline void WriteAddr(uintptr_t dest, void* addr) { uintptr_t addrPtr = (uintptr_t)addr; Write(dest, (uintptr_t)&addrPtr, sizeof(uintptr_t)); } // Inline 203 | // Can be used with HookVtableFunc to not to instantiate vtable for 1000 times! 204 | inline void** GetVtable(void* ptr) { return *(void***)ptr; } 205 | inline void SetVtable(void* ptr, void** vtable) { *(void***)ptr = vtable; } 206 | }; 207 | 208 | extern IAML* aml; 209 | inline IAML* GetAMLInterface() { return aml; } 210 | 211 | /* Do not use big conversions */ 212 | #define SET_TO(__a1, __a2) *(void**)&(__a1) = (void*)(__a2) 213 | #define SET_TO_PTR(__a1, __a2) *(void**)&(__a1) = *(void**)(__a2) 214 | #define SETSYM_TO(__a1, __a2, __a3) *(void**)&(__a1) = (void*)(aml->GetSym(__a2, __a3)) 215 | #define SETSYM_TO_PTR(__a1, __a2, __a3) *(void**)&(__a1) = *(void**)(aml->GetSym(__a2, __a3)) 216 | #define AS_ADDR(__a1) *(uintptr_t*)&(__a1) 217 | 218 | /* Unprotect that memory chunk for making changes */ 219 | #define UNPROT(_addr, _count) \ 220 | aml->Unprot((uintptr_t)(_addr), ( _count )); 221 | /* Just write own info to the memory */ 222 | #define WRITE(_addr, _whatToWrite, _size) \ 223 | aml->Write(_addr, _whatToWrite, _size); 224 | 225 | /* Just a hook declaration */ 226 | #define DECL_HOOK(_ret, _name, ...) \ 227 | _ret (*_name)(__VA_ARGS__); \ 228 | _ret HookOf_##_name(__VA_ARGS__) 229 | /* Just a hook declaration with return type = void */ 230 | #define DECL_HOOKv(_name, ...) \ 231 | void (*_name)(__VA_ARGS__); \ 232 | void HookOf_##_name(__VA_ARGS__) 233 | /* Just a hook declaration with return type = bool */ 234 | #define DECL_HOOKb(_name, ...) \ 235 | bool (*_name)(__VA_ARGS__); \ 236 | bool HookOf_##_name(__VA_ARGS__) 237 | /* Just a hook declaration with return type = int */ 238 | #define DECL_HOOKi(_name, ...) \ 239 | int (*_name)(__VA_ARGS__); \ 240 | int HookOf_##_name(__VA_ARGS__) 241 | /* Just a hook declaration with return type = void* */ 242 | #define DECL_HOOKp(_name, ...) \ 243 | void* (*_name)(__VA_ARGS__); \ 244 | void* HookOf_##_name(__VA_ARGS__) 245 | 246 | /* Just a hook of a function */ 247 | #define HOOK(_name, _fnAddr) \ 248 | aml->Hook((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 249 | /* Just a hook of a function (but simpler usage) */ 250 | #define HOOKSYM(_name, _libHndl, _fnSym) \ 251 | aml->Hook((void*)(aml->GetSym(_libHndl, _fnSym)), (void*)(&HookOf_##_name), (void**)(&_name)); 252 | /* Just a hook of a function located in PLT section (by address!) */ 253 | #define HOOKPLT(_name, _fnAddr) \ 254 | aml->HookPLT((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 255 | /* Just a hook of a branch */ 256 | #define HOOKB(_name, _fnAddr) \ 257 | aml->HookB((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 258 | /* Just a hook of a branch with link */ 259 | #define HOOKBL(_name, _fnAddr) \ 260 | aml->HookBL((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 261 | /* Just a hook of a branch with link (and registers exchange) */ 262 | #define HOOKBLX(_name, _fnAddr) \ 263 | aml->HookBLX((void*)(_fnAddr), (void*)(&HookOf_##_name), (void**)(&_name)) 264 | /* Just a hook of a function hidden behind IL2CPP */ 265 | #define HOOK_IL2CPP(_name, _methodInfo) \ 266 | aml->Hook((void*)_methodInfo->methodPointer, (void*)(&HookOf_##_name), (void**)(&_name)) 267 | 268 | #endif // _IAML -------------------------------------------------------------------------------- /template_of_mod/mod/icfg.h: -------------------------------------------------------------------------------- 1 | /* Is not required. Can be used only for a smaller size of mod (~370kb savings) */ 2 | /* because of fstream include (it has a lot of templates & not only) */ 3 | /* There's no reason of using this feature if you're already using fstream */ 4 | 5 | #ifndef _ICFG 6 | #define _ICFG 7 | 8 | class ICFG 9 | { 10 | public: 11 | virtual void* InitIniPointer() = 0; 12 | virtual void ParseInputStream(void* iniPointer, const char* szFilename) = 0; 13 | virtual void GenerateToOutputStream(void* iniPointer, const char* szFilename) = 0; 14 | virtual const char* GetValueFrom(void* iniPointer, const char* szSection, const char* szKey) = 0; 15 | virtual void SetValueTo(void* iniPointer, const char* szSection, const char* szKey, const char* szValue) = 0; 16 | }; 17 | 18 | extern ICFG* icfg; 19 | inline ICFG* GetCFGInterface() 20 | { 21 | return icfg; 22 | } 23 | 24 | #endif // _ICFG -------------------------------------------------------------------------------- /template_of_mod/mod/il2cpp.h: -------------------------------------------------------------------------------- 1 | struct IL2Assembly; 2 | struct IL2Object; 3 | struct IL2Class; 4 | struct IL2Image; 5 | struct IL2Array; 6 | struct IL2Type; 7 | 8 | struct IL2Domain; 9 | struct IL2ReflectionType; 10 | struct IL2Exception; 11 | struct IL2Profiler; 12 | struct IL2Thread; 13 | struct IL2ReflectionMethod; 14 | struct IL2ManagedMemorySnapshot; 15 | struct IL2StackFrameInfo; 16 | struct IL2CustomAttrInfo; 17 | struct IL2GenericClass; 18 | struct IL2Defaults; 19 | 20 | struct IL2TypeDefinition; 21 | struct IL2GenericParameter; 22 | struct IL2GenericContainer; 23 | 24 | struct MethodInfo; 25 | struct FieldInfo; 26 | struct PropertyInfo; 27 | struct EventInfo; -------------------------------------------------------------------------------- /template_of_mod/mod/interface.h: -------------------------------------------------------------------------------- 1 | /* DO NOT CHANGE IT */ 2 | 3 | #ifndef __GETINTERFACE_H 4 | #define __GETINTERFACE_H 5 | 6 | #if defined(_WIN32) || defined(_WIN64) 7 | #define WIN32_LEAN_AND_MEAN 8 | #include 9 | #else 10 | #include 11 | #endif 12 | #define DEFAULT_LIB_NAME "AML" 13 | 14 | #define WRAP_INTERFACE(__interface_name, __interface_var) RegisterInterface(#__interface_name, __interface_var) 15 | 16 | typedef void* (*GetInterfaceFn)(const char*); 17 | typedef void* (*RegInterfaceFn)(const char*, void*); 18 | 19 | inline void* GetInterface(const char* szInterfaceName) 20 | { 21 | #if defined(_WIN32) || defined(_WIN64) 22 | GetInterfaceFn _GetInterface = (GetInterfaceFn)GetProcAddress(GetModuleHandleA(DEFAULT_LIB_NAME ".dll"), "GetInterface"); 23 | #else 24 | GetInterfaceFn _GetInterface = (GetInterfaceFn)dlsym((void*)dlopen("lib" DEFAULT_LIB_NAME ".so", RTLD_NOW), "GetInterface"); 25 | #endif 26 | return _GetInterface(szInterfaceName); 27 | } 28 | 29 | inline void RegisterInterface(const char* szInterfaceName, void* pInterface) 30 | { 31 | #if defined(_WIN32) || defined(_WIN64) 32 | RegInterfaceFn _RegInterface = (RegInterfaceFn)GetProcAddress(GetModuleHandleA(DEFAULT_LIB_NAME ".dll"), "CreateInterface"); 33 | #else 34 | RegInterfaceFn _RegInterface = (RegInterfaceFn)dlsym((void*)dlopen("lib" DEFAULT_LIB_NAME ".so", RTLD_NOW), "CreateInterface"); 35 | #endif 36 | _RegInterface(szInterfaceName, pInterface); 37 | } 38 | 39 | #endif // __GETINTERFACE_H -------------------------------------------------------------------------------- /template_of_mod/mod/listitem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // use of undeclared identifier 'NULL' 4 | 5 | #define LIST_START(__cls_name) struct __cls_name { \ 6 | __cls_name *pPrev; \ 7 | __cls_name *pNext; \ 8 | __cls_name *pLast; \ 9 | unsigned int nCount; \ 10 | typedef __cls_name MyClass; \ 11 | \ 12 | inline unsigned int Count() { return !this ? 0 : First()->nCount; } \ 13 | inline __cls_name *First() \ 14 | { \ 15 | if(!this) return NULL; \ 16 | __cls_name *first = this; \ 17 | if(first->pPrev == this) { first->pPrev = NULL; return this; } \ 18 | while(first->pPrev != NULL) first = first->pPrev; \ 19 | return first; \ 20 | } \ 21 | inline __cls_name *CalcLast() \ 22 | { \ 23 | if(!this) return NULL; \ 24 | __cls_name *last = this; \ 25 | while(last->pNext != NULL) last = last->pNext; \ 26 | return last; \ 27 | } \ 28 | inline __cls_name *Last() \ 29 | { \ 30 | return pLast; \ 31 | } \ 32 | inline void Push(__cls_name **listPtr) \ 33 | { \ 34 | __cls_name*& list = *listPtr; \ 35 | pPrev = NULL; \ 36 | if(list == NULL) { \ 37 | pNext = NULL; \ 38 | pLast = this; \ 39 | nCount = 1; \ 40 | } else { \ 41 | pNext = list; \ 42 | pLast = list->pLast; \ 43 | list->pPrev = this; \ 44 | nCount = list->nCount + 1; \ 45 | } \ 46 | list = this; \ 47 | } \ 48 | inline bool Remove(__cls_name **listPtr) { \ 49 | if(!listPtr || !*listPtr || !pLast) return false; \ 50 | __cls_name*& list = *listPtr; \ 51 | if(list == this) { \ 52 | if(pNext) { \ 53 | list = pNext; \ 54 | list->nCount = nCount - 1; \ 55 | list->pPrev = NULL; \ 56 | list->pLast = pLast; \ 57 | } else { \ 58 | list = NULL; \ 59 | } \ 60 | } \ 61 | else if(list->pLast == this) { \ 62 | list->pLast = pPrev; \ 63 | pPrev->pNext = NULL; \ 64 | --(list->nCount); \ 65 | } else { \ 66 | pPrev->pNext = pNext; \ 67 | if(pNext) pNext->pPrev = pPrev; \ 68 | --(list->nCount); \ 69 | } \ 70 | pNext = NULL; pPrev = NULL; pLast = NULL; \ 71 | return true; \ 72 | } \ 73 | inline bool InList(__cls_name **listPtr) \ 74 | { \ 75 | LIST_FOR(*listPtr) { \ 76 | if(item == this) return true; \ 77 | } \ 78 | return false; \ 79 | } 80 | 81 | #define LIST_END() \ 82 | }; 83 | 84 | #define LIST_INITSTART(__cls_name) \ 85 | __cls_name() { 86 | 87 | #define LIST_INITEND() \ 88 | pPrev = NULL; \ 89 | pNext = NULL; \ 90 | pLast = NULL; \ 91 | nCount = 1; \ 92 | } 93 | 94 | // Never use FAST versions if you do "Remove" or "Push" in a loop! Or maintain it by yourself! 95 | 96 | #define LIST_FOR(__list) for(auto item = __list, itemNext = item ? item->pNext : NULL; item != NULL; item = itemNext, itemNext = item ? item->pNext : NULL) 97 | #define LIST_FOR_FAST(__list) for(auto item = __list; item != NULL; item = item->pNext) 98 | #define LIST_FOR2(__list, __itemname) for(auto __itemname = __list, itemNext = __itemname ? __itemname->pNext : NULL; __itemname != NULL; __itemname = itemNext, itemNext = __itemname ? __itemname->pNext : NULL) 99 | #define LIST_FOR2_FAST(__list, __itemname) for(auto __itemname = __list; __itemname != NULL; __itemname = __itemname->pNext) 100 | #define LIST_FOR_REVERSE(__list) for(auto item = __list ? __list->pLast : NULL, itemPrev = item ? item->pPrev : NULL; item != NULL; item = itemPrev, itemPrev = item ? item->pPrev : NULL) 101 | #define LIST_FOR_REVERSE_FAST(__list) for(auto item = __list ? __list->pLast : NULL; item != NULL; item = item->pPrev) 102 | #define LIST_RESET(__list, __resetFunc) LIST_FOR(__list) { __resetFunc(); item->Remove(&__list); } -------------------------------------------------------------------------------- /template_of_mod/mod/logger.cpp: -------------------------------------------------------------------------------- 1 | #ifndef DONT_USE_STB 2 | #ifndef DONT_IMPLEMENT_STB 3 | #define STB_SPRINTF_IMPLEMENTATION 4 | #endif 5 | #include 6 | 7 | #define vsnprintf stbsp_vsnprintf 8 | #endif 9 | #include "logger.h" 10 | #include 11 | #include 12 | 13 | Logger::Logger() 14 | { 15 | strncpy(m_szTag, "AML Mod", sizeof(m_szTag)); 16 | m_bEnabled = true; 17 | m_fnLogCallback = NULL; 18 | m_fnNewTagCallback = NULL; 19 | m_fnToggledCallback = NULL; 20 | } 21 | 22 | void Logger::ToggleOutput(bool enabled) 23 | { 24 | if(m_bEnabled != enabled) 25 | { 26 | m_bEnabled = enabled; 27 | if(m_fnToggledCallback) m_fnToggledCallback(enabled); 28 | } 29 | } 30 | 31 | void Logger::SetTag(const char* szTag) 32 | { 33 | if(m_fnNewTagCallback) m_fnNewTagCallback(m_szTag, szTag); 34 | strncpy(m_szTag, szTag, sizeof(m_szTag)-1); 35 | m_szTag[sizeof(m_szTag)-1] = 0; 36 | } 37 | 38 | void Logger::Print(eLogPrio prio, const char* szMessage, ...) 39 | { 40 | #ifndef NOLOGGING 41 | if(!m_bEnabled) return; 42 | 43 | char buffer[TMPBUF_SIZE]; 44 | va_list args; 45 | va_start(args, szMessage); 46 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 47 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 48 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 49 | va_end(args); 50 | #endif 51 | } 52 | 53 | void Logger::PrintV(eLogPrio prio, const char* szMessage, va_list args) 54 | { 55 | #ifndef NOLOGGING 56 | if(!m_bEnabled) return; 57 | 58 | char buffer[TMPBUF_SIZE]; 59 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 60 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 61 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 62 | #endif 63 | } 64 | 65 | void Logger::PrintTag(eLogPrio prio, const char* szTag, const char* szMessage, ...) 66 | { 67 | #ifndef NOLOGGING 68 | if(!m_bEnabled) return; 69 | 70 | char buffer[TMPBUF_SIZE]; 71 | va_list args; 72 | va_start(args, szMessage); 73 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 74 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 75 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 76 | va_end(args); 77 | #endif 78 | } 79 | 80 | void Logger::PrintTagV(eLogPrio prio, const char* szTag, const char* szMessage, va_list args) 81 | { 82 | #ifndef NOLOGGING 83 | if(!m_bEnabled) return; 84 | 85 | char buffer[TMPBUF_SIZE]; 86 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 87 | if(m_fnLogCallback) m_fnLogCallback(prio, buffer); 88 | __android_log_write((android_LogPriority)prio, m_szTag, buffer); 89 | #endif 90 | } 91 | 92 | void Logger::Info(const char* szMessage, ...) 93 | { 94 | #ifndef NOLOGGING 95 | if(!m_bEnabled) return; 96 | 97 | char buffer[TMPBUF_SIZE]; 98 | va_list args; 99 | va_start(args, szMessage); 100 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 101 | if(m_fnLogCallback) m_fnLogCallback(LogP_Info, buffer); 102 | __android_log_write(ANDROID_LOG_INFO, m_szTag, buffer); 103 | va_end(args); 104 | #endif 105 | } 106 | 107 | void Logger::InfoV(const char* szMessage, va_list args) 108 | { 109 | #ifndef NOLOGGING 110 | if(!m_bEnabled) return; 111 | 112 | char buffer[TMPBUF_SIZE]; 113 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 114 | if(m_fnLogCallback) m_fnLogCallback(LogP_Info, buffer); 115 | __android_log_write(ANDROID_LOG_INFO, m_szTag, buffer); 116 | #endif 117 | } 118 | 119 | void Logger::Error(const char* szMessage, ...) 120 | { 121 | #ifndef NOLOGGING 122 | if(!m_bEnabled) return; 123 | 124 | char buffer[TMPBUF_SIZE]; 125 | va_list args; 126 | va_start(args, szMessage); 127 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 128 | if(m_fnLogCallback) m_fnLogCallback(LogP_Error, buffer); 129 | __android_log_write(ANDROID_LOG_ERROR, m_szTag, buffer); 130 | va_end(args); 131 | #endif 132 | } 133 | 134 | void Logger::ErrorV(const char* szMessage, va_list args) 135 | { 136 | #ifndef NOLOGGING 137 | if(!m_bEnabled) return; 138 | 139 | char buffer[TMPBUF_SIZE]; 140 | vsnprintf(buffer, sizeof(buffer), szMessage, args); 141 | if(m_fnLogCallback) m_fnLogCallback(LogP_Error, buffer); 142 | __android_log_write(ANDROID_LOG_ERROR, m_szTag, buffer); 143 | #endif 144 | } 145 | 146 | static Logger loggerLocal; 147 | Logger* logger = &loggerLocal; -------------------------------------------------------------------------------- /template_of_mod/mod/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOGGER_H 2 | #define _LOGGER_H 3 | 4 | #include 5 | #define TMPBUF_SIZE 2048 // Max logging buf is 4096 btw 6 | 7 | /* Define NOLOGGING if you DONT need logs in any form */ 8 | /* You can do it like that in Android.mk: LOCAL_CXXFLAGS += -DNOLOGGING */ 9 | 10 | enum eLogPrio 11 | { 12 | LogP_Unk = 0, 13 | LogP_Default, 14 | LogP_Verbose, 15 | LogP_Debug, 16 | LogP_Info, 17 | LogP_Warn, 18 | LogP_Error, 19 | LogP_Fatal, 20 | LogP_Silent, 21 | }; 22 | 23 | class Logger; 24 | extern Logger* logger; 25 | 26 | class Logger 27 | { 28 | public: 29 | typedef void (*LoggerMessageCB)(eLogPrio prio, const char* msg); 30 | typedef void (*LoggerSetTagCB)(const char* oldTag, const char* newTag); 31 | typedef void (*LoggerToggledCB)(bool isEnabled); 32 | 33 | inline static Logger* GetLogger() { return logger; } 34 | Logger(); 35 | 36 | void ToggleOutput(bool enabled); 37 | void SetTag(const char* szTag); 38 | void Print(eLogPrio prio, const char* szMessage, ...); 39 | void PrintV(eLogPrio prio, const char* szMessage, va_list args); 40 | void PrintTag(eLogPrio prio, const char* szTag, const char* szMessage, ...); 41 | void PrintTagV(eLogPrio prio, const char* szTag, const char* szMessage, va_list args); 42 | void Info(const char* szMessage, ...); 43 | void InfoV(const char* szMessage, va_list args); 44 | void Error(const char* szMessage, ...); 45 | void ErrorV(const char* szMessage, va_list args); 46 | #ifdef NOLOGGING 47 | inline bool HasOutput() { return false; } 48 | #else 49 | inline bool HasOutput() { return m_bEnabled; } 50 | #endif 51 | 52 | inline void SetMessageCB(LoggerMessageCB fnCB) { m_fnLogCallback = fnCB; } 53 | inline void SetTagCB(LoggerSetTagCB fnCB) { m_fnNewTagCallback = fnCB; } 54 | inline void SetToggleCB(LoggerToggledCB fnCB) { m_fnToggledCallback = fnCB; } 55 | 56 | private: 57 | char m_szTag[31]; 58 | bool m_bEnabled; 59 | LoggerMessageCB m_fnLogCallback; 60 | LoggerSetTagCB m_fnNewTagCallback; 61 | LoggerToggledCB m_fnToggledCallback; 62 | }; 63 | 64 | #endif // _LOGGER_H -------------------------------------------------------------------------------- /template_of_mod/mod/thirdparty/INICPP_LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Fabian Meyer 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 | -------------------------------------------------------------------------------- /template_of_mod/mod/thirdparty/STB_LICENSE: -------------------------------------------------------------------------------- 1 | This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /template_of_mod/ndkpath.txt: -------------------------------------------------------------------------------- 1 | D:\android-ndk -------------------------------------------------------------------------------- /vtable_hooker.cpp: -------------------------------------------------------------------------------- 1 | #include "vtable_hooker.h" 2 | #include // memcpy 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void* vtablez[MAX_VTABLE_FUNCS] = {NULL}; 9 | int vtablez_offset = 0; 10 | 11 | // This function is not gonna work correctly if vtable has "holes" (incomplete/abstract virtual class) 12 | void HookVtableFunc(void* ptr, unsigned int funcNum, void* func, void** original, bool instantiate) 13 | { 14 | if(!ptr || !func || funcNum < 0) return; 15 | if(ptr == aml || ptr == icfg) return; // you aint doin thiz dirty boy 16 | void** vtableArray = *(void***)ptr; 17 | 18 | int count = 0; 19 | while(vtableArray[count] != NULL) ++count; 20 | if(funcNum > count) return; 21 | 22 | if(instantiate) 23 | { 24 | memcpy(&vtablez[vtablez_offset], vtableArray, count * sizeof(void*)); 25 | *(void***)ptr = &vtablez[vtablez_offset]; 26 | vtableArray = *(void***)ptr; 27 | vtablez_offset += count; 28 | } 29 | else 30 | { 31 | g_pAML->Unprot((uintptr_t)&vtableArray[funcNum], sizeof(void*)); 32 | } 33 | 34 | if(original != NULL) *original = vtableArray[funcNum]; 35 | vtableArray[funcNum] = func; 36 | } 37 | 38 | // Better func but you need to know how much funcs it has 39 | void HookVtableFunc(void* ptr, unsigned int funcNum, unsigned int count, void* func, void** original, bool instantiate) 40 | { 41 | if(!ptr || !func || funcNum < 0) return; 42 | if(ptr == aml || ptr == icfg) return; // you aint doin thiz dirty boy 43 | void** vtableArray = *(void***)ptr; 44 | 45 | if(funcNum > count) return; 46 | 47 | if(instantiate) 48 | { 49 | memcpy(&vtablez[vtablez_offset], vtableArray, count * sizeof(void*)); 50 | *(void***)ptr = &vtablez[vtablez_offset]; 51 | vtableArray = *(void***)ptr; 52 | vtablez_offset += count; 53 | } 54 | else 55 | { 56 | g_pAML->Unprot((uintptr_t)&vtableArray[funcNum], sizeof(void*)); 57 | } 58 | 59 | if(original != NULL) *original = vtableArray[funcNum]; 60 | vtableArray[funcNum] = func; 61 | } -------------------------------------------------------------------------------- /vtable_hooker.h: -------------------------------------------------------------------------------- 1 | #define MAX_VTABLE_FUNCS 8192 // This is not a count of max instantiated! 2 | 3 | void HookVtableFunc(void* ptr, unsigned int funcNum, void* fnAddress, void** orgFnAddress = (void**)0, bool instantiate = false); 4 | void HookVtableFunc(void* ptr, unsigned int funcNum, unsigned int count, void* func, void** orgFnAddress = (void**)0, bool instantiate = false); --------------------------------------------------------------------------------